Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2019-12-11 15:07:38 +00:00
parent b86f474bf5
commit 4eea104c69
44 changed files with 647 additions and 132 deletions

View file

@ -170,8 +170,8 @@ group :unicorn do
end end
group :puma do group :puma do
gem 'puma', '~> 4.3.0', require: false gem 'gitlab-puma', '~> 4.3.1.gitlab.2', require: false
gem 'puma_worker_killer', '~> 0.1.1', require: false gem 'gitlab-puma_worker_killer', '~> 0.1.1.gitlab.1', require: false
gem 'rack-timeout', require: false gem 'rack-timeout', require: false
end end
@ -346,7 +346,7 @@ group :development do
end end
group :development, :test do group :development, :test do
gem 'bullet', '~> 5.5.0', require: !!ENV['ENABLE_BULLET'] gem 'bullet', '~> 6.0.2', require: !!ENV['ENABLE_BULLET']
gem 'pry-byebug', '~> 3.5.1', platform: :mri gem 'pry-byebug', '~> 3.5.1', platform: :mri
gem 'pry-rails', '~> 0.3.4' gem 'pry-rails', '~> 0.3.4'

View file

@ -118,9 +118,9 @@ GEM
brakeman (4.2.1) brakeman (4.2.1)
browser (2.5.3) browser (2.5.3)
builder (3.2.3) builder (3.2.3)
bullet (5.5.1) bullet (6.0.2)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
uniform_notifier (~> 1.10.0) uniform_notifier (~> 1.11)
bundler-audit (0.5.0) bundler-audit (0.5.0)
bundler (~> 1.2) bundler (~> 1.2)
thor (~> 0.18) thor (~> 0.18)
@ -372,6 +372,11 @@ GEM
gitlab-license (1.0.0) gitlab-license (1.0.0)
gitlab-markup (1.7.0) gitlab-markup (1.7.0)
gitlab-net-dns (0.9.1) gitlab-net-dns (0.9.1)
gitlab-puma (4.3.1.gitlab.2)
nio4r (~> 2.0)
gitlab-puma_worker_killer (0.1.1.gitlab.1)
get_process_mem (~> 0.2)
gitlab-puma (>= 2.7, < 5)
gitlab-sidekiq-fetcher (0.5.2) gitlab-sidekiq-fetcher (0.5.2)
sidekiq (~> 5) sidekiq (~> 5)
gitlab-styles (2.8.0) gitlab-styles (2.8.0)
@ -619,7 +624,7 @@ GEM
net-ntp (2.1.3) net-ntp (2.1.3)
net-ssh (5.2.0) net-ssh (5.2.0)
netrc (0.11.0) netrc (0.11.0)
nio4r (2.3.1) nio4r (2.5.2)
no_proxy_fix (0.1.2) no_proxy_fix (0.1.2)
nokogiri (1.10.5) nokogiri (1.10.5)
mini_portile2 (~> 2.4.0) mini_portile2 (~> 2.4.0)
@ -748,11 +753,6 @@ GEM
pry-rails (0.3.6) pry-rails (0.3.6)
pry (>= 0.10.4) pry (>= 0.10.4)
public_suffix (3.1.1) public_suffix (3.1.1)
puma (4.3.1)
nio4r (~> 2.0)
puma_worker_killer (0.1.1)
get_process_mem (~> 0.2)
puma (>= 2.7, < 5)
pyu-ruby-sasl (0.0.3.3) pyu-ruby-sasl (0.0.3.3)
raabro (1.1.6) raabro (1.1.6)
rack (2.0.7) rack (2.0.7)
@ -1057,7 +1057,7 @@ GEM
unicorn-worker-killer (0.4.4) unicorn-worker-killer (0.4.4)
get_process_mem (~> 0) get_process_mem (~> 0)
unicorn (>= 4, < 6) unicorn (>= 4, < 6)
uniform_notifier (1.10.0) uniform_notifier (1.13.0)
unleash (0.1.5) unleash (0.1.5)
murmurhash3 (~> 0.1.6) murmurhash3 (~> 0.1.6)
unparser (0.4.5) unparser (0.4.5)
@ -1139,7 +1139,7 @@ DEPENDENCIES
bootstrap_form (~> 4.2.0) bootstrap_form (~> 4.2.0)
brakeman (~> 4.2) brakeman (~> 4.2)
browser (~> 2.5) browser (~> 2.5)
bullet (~> 5.5.0) bullet (~> 6.0.2)
bundler-audit (~> 0.5.0) bundler-audit (~> 0.5.0)
capybara (~> 3.22.0) capybara (~> 3.22.0)
capybara-screenshot (~> 1.0.22) capybara-screenshot (~> 1.0.22)
@ -1200,6 +1200,8 @@ DEPENDENCIES
gitlab-license (~> 1.0) gitlab-license (~> 1.0)
gitlab-markup (~> 1.7.0) gitlab-markup (~> 1.7.0)
gitlab-net-dns (~> 0.9.1) gitlab-net-dns (~> 0.9.1)
gitlab-puma (~> 4.3.1.gitlab.2)
gitlab-puma_worker_killer (~> 0.1.1.gitlab.1)
gitlab-sidekiq-fetcher (= 0.5.2) gitlab-sidekiq-fetcher (= 0.5.2)
gitlab-styles (~> 2.7) gitlab-styles (~> 2.7)
gitlab_chronic_duration (~> 0.10.6.2) gitlab_chronic_duration (~> 0.10.6.2)
@ -1280,8 +1282,6 @@ DEPENDENCIES
prometheus-client-mmap (~> 0.9.10) prometheus-client-mmap (~> 0.9.10)
pry-byebug (~> 3.5.1) pry-byebug (~> 3.5.1)
pry-rails (~> 0.3.4) pry-rails (~> 0.3.4)
puma (~> 4.3.0)
puma_worker_killer (~> 0.1.1)
rack (~> 2.0.7) rack (~> 2.0.7)
rack-attack (~> 6.2.0) rack-attack (~> 6.2.0)
rack-cors (~> 1.0.0) rack-cors (~> 1.0.0)

View file

@ -145,7 +145,8 @@ export default {
:is-loading="model.isLoadingDeployBoard" :is-loading="model.isLoadingDeployBoard"
:is-empty="model.isEmptyDeployBoard" :is-empty="model.isEmptyDeployBoard"
:has-legacy-app-label="model.hasLegacyAppLabel" :has-legacy-app-label="model.hasLegacyAppLabel"
:logs-path="model.logs_path" :project-path="model.project_path"
:environment-name="model.name"
/> />
</div> </div>
</div> </div>

View file

@ -1,28 +1,35 @@
import { __ } from '~/locale'; import { __ } from '~/locale';
import { parseUrlPathname, parseUrl } from '../lib/utils/common_utils';
function swapActiveState(activateBtn, deactivateBtn) {
activateBtn.classList.add('is-active');
deactivateBtn.classList.remove('is-active');
}
export default () => { export default () => {
const shareBtn = document.querySelector('.js-share-btn'); const shareBtn = document.querySelector('.js-share-btn');
if (shareBtn) { if (shareBtn) {
const { protocol, host, pathname } = window.location;
const embedBtn = document.querySelector('.js-embed-btn'); const embedBtn = document.querySelector('.js-embed-btn');
const snippetUrlArea = document.querySelector('.js-snippet-url-area'); const snippetUrlArea = document.querySelector('.js-snippet-url-area');
const embedAction = document.querySelector('.js-embed-action'); const embedAction = document.querySelector('.js-embed-action');
const url = `${protocol}//${host + pathname}`; const dataUrl = snippetUrlArea.getAttribute('data-url');
snippetUrlArea.addEventListener('click', () => snippetUrlArea.select());
shareBtn.addEventListener('click', () => { shareBtn.addEventListener('click', () => {
shareBtn.classList.add('is-active'); swapActiveState(shareBtn, embedBtn);
embedBtn.classList.remove('is-active'); snippetUrlArea.value = dataUrl;
snippetUrlArea.value = url;
embedAction.innerText = __('Share'); embedAction.innerText = __('Share');
}); });
embedBtn.addEventListener('click', () => { embedBtn.addEventListener('click', () => {
embedBtn.classList.add('is-active'); const parser = parseUrl(dataUrl);
shareBtn.classList.remove('is-active'); const url = `${parser.origin + parseUrlPathname(dataUrl)}`;
const scriptTag = `<script src="${url}.js"></script>`; const params = parser.search;
const scriptTag = `<script src="${url}.js${params}"></script>`;
swapActiveState(embedBtn, shareBtn);
snippetUrlArea.value = scriptTag; snippetUrlArea.value = scriptTag;
embedAction.innerText = __('Embed'); embedAction.innerText = __('Embed');
}); });

View file

@ -5,8 +5,8 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
include RendersNotes include RendersNotes
before_action :apply_diff_view_cookie! before_action :apply_diff_view_cookie!
before_action :commit, except: :diffs_batch before_action :commit
before_action :define_diff_vars, except: :diffs_batch before_action :define_diff_vars
before_action :define_diff_comment_vars, except: [:diffs_batch, :diffs_metadata] before_action :define_diff_comment_vars, except: [:diffs_batch, :diffs_metadata]
def show def show
@ -20,11 +20,7 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
def diffs_batch def diffs_batch
return render_404 unless Feature.enabled?(:diffs_batch_load, @merge_request.project) return render_404 unless Feature.enabled?(:diffs_batch_load, @merge_request.project)
diffable = @merge_request.merge_request_diff diffs = @compare.diffs_in_batch(params[:page], params[:per_page], diff_options: diff_options)
return render_404 unless diffable
diffs = diffable.diffs_in_batch(params[:page], params[:per_page], diff_options: diff_options)
positions = @merge_request.note_positions_for_paths(diffs.diff_file_paths, current_user) positions = @merge_request.note_positions_for_paths(diffs.diff_file_paths, current_user)
diffs.unfold_diff_files(positions.unfoldable) diffs.unfold_diff_files(positions.unfoldable)
@ -40,8 +36,10 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
end end
def diffs_metadata def diffs_metadata
diffs = @compare.diffs(diff_options)
render json: DiffsMetadataSerializer.new(project: @merge_request.project) render json: DiffsMetadataSerializer.new(project: @merge_request.project)
.represent(@diffs, additional_attributes) .represent(diffs, additional_attributes)
end end
private private
@ -50,11 +48,13 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
[{ source_project: :namespace }, { target_project: :namespace }] [{ source_project: :namespace }, { target_project: :namespace }]
end end
# Deprecated: https://gitlab.com/gitlab-org/gitlab/issues/37735
def render_diffs def render_diffs
diffs = @compare.diffs(diff_options)
@environment = @merge_request.environments_for(current_user).last @environment = @merge_request.environments_for(current_user).last
@diffs.unfold_diff_files(note_positions.unfoldable) diffs.unfold_diff_files(note_positions.unfoldable)
@diffs.write_cache diffs.write_cache
request = { request = {
current_user: current_user, current_user: current_user,
@ -64,15 +64,14 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
options = additional_attributes.merge(diff_view: diff_view) options = additional_attributes.merge(diff_view: diff_view)
render json: DiffsSerializer.new(request).represent(@diffs, options) render json: DiffsSerializer.new(request).represent(diffs, options)
end end
# Deprecated: https://gitlab.com/gitlab-org/gitlab/issues/37735
def define_diff_vars def define_diff_vars
@merge_request_diffs = @merge_request.merge_request_diffs.viewable.order_id_desc @merge_request_diffs = @merge_request.merge_request_diffs.viewable.order_id_desc
@compare = commit || find_merge_request_diff_compare @compare = commit || find_merge_request_diff_compare
return render_404 unless @compare return render_404 unless @compare
@diffs = @compare.diffs(diff_options)
end end
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
@ -85,6 +84,8 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
#
# Deprecated: https://gitlab.com/gitlab-org/gitlab/issues/37735
def find_merge_request_diff_compare def find_merge_request_diff_compare
@merge_request_diff = @merge_request_diff =
if diff_id = params[:diff_id].presence if diff_id = params[:diff_id].presence
@ -127,6 +128,7 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
} }
end end
# Deprecated: https://gitlab.com/gitlab-org/gitlab/issues/37735
def define_diff_comment_vars def define_diff_comment_vars
@new_diff_note_attrs = { @new_diff_note_attrs = {
noteable_type: 'MergeRequest', noteable_type: 'MergeRequest',

View file

@ -112,6 +112,17 @@ module SnippetsHelper
content_tag(:script, nil, src: gitlab_snippet_url(snippet, format: :js)) content_tag(:script, nil, src: gitlab_snippet_url(snippet, format: :js))
end end
def snippet_embed_input(snippet)
content_tag(:input,
nil,
type: :text,
readonly: true,
class: 'js-snippet-url-area snippet-embed-input form-control',
data: { url: gitlab_snippet_url(snippet) },
value: snippet_embed_tag(snippet),
autocomplete: 'off')
end
def snippet_badge(snippet) def snippet_badge(snippet)
return unless attrs = snippet_badge_attributes(snippet) return unless attrs = snippet_badge_attributes(snippet)

View file

@ -12,6 +12,7 @@ class Commit
include StaticModel include StaticModel
include Presentable include Presentable
include ::Gitlab::Utils::StrongMemoize include ::Gitlab::Utils::StrongMemoize
include ActsAsPaginatedDiff
include CacheMarkdownField include CacheMarkdownField
attr_mentionable :safe_message, pipeline: :single_line attr_mentionable :safe_message, pipeline: :single_line

View file

@ -4,6 +4,7 @@ require 'set'
class Compare class Compare
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
include ActsAsPaginatedDiff
delegate :same, :head, :base, to: :@compare delegate :same, :head, :base, to: :@compare

View file

@ -0,0 +1,11 @@
# frozen_string_literal: true
module ActsAsPaginatedDiff
# Comparisons going back to the repository will need proper batch
# loading (https://gitlab.com/gitlab-org/gitlab/issues/32859).
# For now, we're returning all the diffs available with
# no pagination data.
def diffs_in_batch(_batch_page, _batch_size, diff_options:)
diffs(diff_options)
end
end

View file

@ -309,20 +309,25 @@ class MergeRequestDiff < ApplicationRecord
end end
def diffs_in_batch(batch_page, batch_size, diff_options:) def diffs_in_batch(batch_page, batch_size, diff_options:)
Gitlab::Diff::FileCollection::MergeRequestDiffBatch.new(self, fetching_repository_diffs(diff_options) do |comparison|
batch_page, if comparison
batch_size, comparison.diffs_in_batch(batch_page, batch_size, diff_options: diff_options)
diff_options: diff_options) else
diffs_in_batch_collection(batch_page, batch_size, diff_options: diff_options)
end
end
end end
def diffs(diff_options = nil) def diffs(diff_options = nil)
if without_files? && comparison = diff_refs&.compare_in(project) fetching_repository_diffs(diff_options) do |comparison|
# It should fetch the repository when diffs are cleaned by the system. # It should fetch the repository when diffs are cleaned by the system.
# We don't keep these for storage overload purposes. # We don't keep these for storage overload purposes.
# See https://gitlab.com/gitlab-org/gitlab-foss/issues/37639 # See https://gitlab.com/gitlab-org/gitlab-foss/issues/37639
comparison.diffs(diff_options) if comparison
else comparison.diffs(diff_options)
diffs_collection(diff_options) else
diffs_collection(diff_options)
end
end end
end end
@ -430,6 +435,13 @@ class MergeRequestDiff < ApplicationRecord
private private
def diffs_in_batch_collection(batch_page, batch_size, diff_options:)
Gitlab::Diff::FileCollection::MergeRequestDiffBatch.new(self,
batch_page,
batch_size,
diff_options: diff_options)
end
def encode_in_base64?(diff_text) def encode_in_base64?(diff_text)
(diff_text.encoding == Encoding::BINARY && !diff_text.ascii_only?) || (diff_text.encoding == Encoding::BINARY && !diff_text.ascii_only?) ||
diff_text.include?("\0") diff_text.include?("\0")
@ -487,6 +499,25 @@ class MergeRequestDiff < ApplicationRecord
end end
end end
# Yields the block with the repository Compare object if it should
# fetch diffs from the repository instead DB.
def fetching_repository_diffs(diff_options)
return unless block_given?
diff_options ||= {}
# Can be read as: fetch the persisted diffs if yielded without the
# Compare object.
return yield unless without_files? || diff_options[:ignore_whitespace_change]
return yield unless diff_refs&.complete?
comparison = diff_refs.compare_in(repository.project)
return yield unless comparison
yield(comparison)
end
def use_external_diff? def use_external_diff?
return false unless has_attribute?(:external_diff) return false unless has_attribute?(:external_diff)
return false unless Gitlab.config.external_diffs.enabled return false unless Gitlab.config.external_diffs.enabled

View file

@ -1,14 +0,0 @@
- page_title _('Pod logs')
.row.empty-state
.col-sm-12
.svg-content
= image_tag 'illustrations/operations_log_pods_empty.svg'
.col-12
.text-content
%h4.text-center
= s_('Environments|No deployed environments')
%p.state-description.text-center
= s_('Logs|To see the pod logs, deploy your code to an environment.')
.text-center
= link_to s_('Environments|Learn about environments'), help_page_path('ci/environments'), class: 'btn btn-success'

View file

@ -44,7 +44,7 @@
%li %li
%button.js-share-btn.btn.btn-transparent{ type: 'button' } %button.js-share-btn.btn.btn-transparent{ type: 'button' }
%strong.embed-toggle-list-item= _("Share") %strong.embed-toggle-list-item= _("Share")
%input.js-snippet-url-area.snippet-embed-input.form-control{ type: "text", autocomplete: 'off', value: snippet_embed_tag(@snippet) } = snippet_embed_input(@snippet)
.input-group-append .input-group-append
= clipboard_button(title: _('Copy'), class: 'js-clipboard-btn snippet-clipboard-btn btn btn-default', target: '.js-snippet-url-area') = clipboard_button(title: _('Copy'), class: 'js-clipboard-btn snippet-clipboard-btn btn btn-default', target: '.js-snippet-url-area')
.clearfix .clearfix

View file

@ -0,0 +1,5 @@
---
title: Allow Job-Token authentication on Releases creation API
merge_request: 20632
author:
type: added

View file

@ -0,0 +1,6 @@
---
title: Do not allow specifying a Kubernetes namespace via CI template for managed
clusters
merge_request: 21223
author:
type: added

View file

@ -0,0 +1,5 @@
---
title: Rework pod logs navigation scheme
merge_request: 20578
author:
type: changed

View file

@ -0,0 +1,5 @@
---
title: CI template for Sentry managed app
merge_request: 21208
author:
type: added

View file

@ -0,0 +1,5 @@
---
title: Respect snippet query params when displaying embed urls
merge_request: 21131
author:
type: fixed

View file

@ -0,0 +1,5 @@
---
title: Fork Puma to validate scheduler fixes
merge_request: 21547
author:
type: performance

View file

@ -6,6 +6,7 @@ last_update: 2019-07-03
# Merge Trains **(PREMIUM)** # Merge Trains **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/9186) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.0. > [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/9186) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.0.
> [Squash and merge](../../../../user/project/merge_requests/squash_and_merge.md) support [introduced](https://gitlab.com/gitlab-org/gitlab/issues/13001) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.6.
[Pipelines for merged results](../index.md#pipelines-for-merged-results-premium) introduces [Pipelines for merged results](../index.md#pipelines-for-merged-results-premium) introduces
running a build on the result of the merged code prior to merging, as a way to keep master green. running a build on the result of the merged code prior to merging, as a way to keep master green.
@ -36,7 +37,6 @@ Merge trains have the following requirements and limitations:
If more than twenty merge requests are added to the merge train, the merge requests If more than twenty merge requests are added to the merge train, the merge requests
will be queued until a slot in the merge train is free. There is no limit to the will be queued until a slot in the merge train is free. There is no limit to the
number of merge requests that can be queued. number of merge requests that can be queued.
- This feature does not support [squash and merge](../../../../user/project/merge_requests/squash_and_merge.md).
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i> <i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
Watch this video for a demonstration on [how parallel execution Watch this video for a demonstration on [how parallel execution

View file

@ -524,7 +524,7 @@ Here are some common pitfalls and how to overcome them:
```ruby ```ruby
u = User.find_by_username('your-username') u = User.find_by_username('your-username')
s = SearchService.new(u, {:search => 'search_term', :scope => blobs}) s = SearchService.new(u, {:search => 'search_term', :scope => 'blobs'})
pp s.search_objects.to_a pp s.search_objects.to_a
``` ```

View file

@ -450,6 +450,7 @@ install using Helm `values.yaml` files.
Supported applications: Supported applications:
- [Ingress](#install-ingress-using-gitlab-ci) - [Ingress](#install-ingress-using-gitlab-ci)
- [Sentry](#install-sentry-using-gitlab-ci)
### Usage ### Usage
@ -498,6 +499,67 @@ management project. Refer to the
[chart](https://github.com/helm/charts/tree/master/stable/nginx-ingress) [chart](https://github.com/helm/charts/tree/master/stable/nginx-ingress)
for the available configuration options. for the available configuration options.
### Install Sentry using GitLab CI
NOTE: **Note:**
The Sentry Helm chart [recommends](https://github.com/helm/charts/blob/f6e5784f265dd459c5a77430185d0302ed372665/stable/sentry/values.yaml#L284-L285) at least 3GB of available RAM for database migrations.
To install Sentry, define the `.gitlab/managed-apps/config.yaml` file
with:
```yaml
sentry:
installed: true
```
Sentry will then be installed into the `gitlab-managed-apps` namespace
of your cluster.
You can customize the installation of Sentry by defining
`.gitlab/managed-apps/sentry/values.yaml` file in your cluster
management project. Refer to the
[chart](https://github.com/helm/charts/tree/master/stable/sentry)
for the available configuration options.
We recommend you pay close attention to the following configuration options:
- `email`. Needed to invite users to your Sentry instance and to send error emails.
- `user`. Where you can set the login credentials for the default admin user.
- `postgresql`. For a PostgreSQL password that can be used when running future updates.
NOTE: **Note:**
When upgrading it is important to provide the existing PostgreSQL password (given using the `postgresql.postgresqlPassword` key) or you will receive authentication errors. See the [PostgreSQL chart documentation](https://github.com/helm/charts/tree/master/stable/postgresql#upgrade) for more information.
Here is an example configuration for Sentry:
```yaml
# Admin user to create
user:
# Indicated to create the admin user or not,
# Default is true as the initial installation.
create: true
email: "<your email>"
password: "<your password>"
email:
from_address: "<your from email>"
host: smtp
port: 25
use_tls: false
user: "<your email username>"
password: "<your email password>"
enable_replies: false
ingress:
enabled: true
hostname: "<sentry.example.com>"
# Needs to be here between runs.
# See https://github.com/helm/charts/tree/master/stable/postgresql#upgrade for more info
postgresql:
postgresqlPassword: example-postgresql-password
```
## Upgrading applications ## Upgrading applications
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/24789) in GitLab 11.8. > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/24789) in GitLab 11.8.
@ -539,6 +601,7 @@ The applications below can be uninstalled.
| Knative | 12.1+ | The associated IP will be deleted and cannot be restored. | | Knative | 12.1+ | The associated IP will be deleted and cannot be restored. |
| Prometheus | 11.11+ | All data will be deleted and cannot be restored. | | Prometheus | 11.11+ | All data will be deleted and cannot be restored. |
| Crossplane | 12.5+ | All data will be deleted and cannot be restored. | | Crossplane | 12.5+ | All data will be deleted and cannot be restored. |
| Sentry | 12.6+ | The PostgreSQL persistent volume will remain and should be manually removed for complete uninstall. |
To uninstall an application: To uninstall an application:

View file

@ -57,6 +57,7 @@ module API
optional :milestones, type: Array, desc: 'The titles of the related milestones', default: [] optional :milestones, type: Array, desc: 'The titles of the related milestones', default: []
optional :released_at, type: DateTime, desc: 'The date when the release will be/was ready. Defaults to the current time.' optional :released_at, type: DateTime, desc: 'The date when the release will be/was ready. Defaults to the current time.'
end end
route_setting :authentication, job_token_allowed: true
post ':id/releases' do post ':id/releases' do
authorize_create_release! authorize_create_release!

View file

@ -63,12 +63,33 @@ module Gitlab
end end
def create_namespace def create_namespace
namespace = kubernetes_namespace || build_namespace_record
return if conflicting_ci_namespace_requested?(namespace)
Clusters::Kubernetes::CreateOrUpdateNamespaceService.new( Clusters::Kubernetes::CreateOrUpdateNamespaceService.new(
cluster: deployment_cluster, cluster: deployment_cluster,
kubernetes_namespace: kubernetes_namespace || build_namespace_record kubernetes_namespace: namespace
).execute ).execute
end end
##
# A namespace can only be specified via gitlab-ci.yml
# for unmanaged clusters, as we currently have no way
# of preventing a job requesting a namespace it
# shouldn't have access to.
#
# To make this clear, we fail the build instead of
# silently using a namespace other than the one
# explicitly specified.
#
# Support for managed clusters will be added in
# https://gitlab.com/gitlab-org/gitlab/issues/38054
def conflicting_ci_namespace_requested?(namespace_record)
build.expanded_kubernetes_namespace.present? &&
namespace_record.namespace != build.expanded_kubernetes_namespace
end
def build_namespace_record def build_namespace_record
Clusters::BuildKubernetesNamespaceService.new( Clusters::BuildKubernetesNamespaceService.new(
deployment_cluster, deployment_cluster,

View file

@ -1,12 +1,13 @@
apply: apply:
stage: deploy stage: deploy
image: "registry.gitlab.com/gitlab-org/cluster-integration/cluster-applications:v0.2.0" image: "registry.gitlab.com/gitlab-org/cluster-integration/cluster-applications:v0.3.0"
environment: environment:
name: production name: production
variables: variables:
TILLER_NAMESPACE: gitlab-managed-apps TILLER_NAMESPACE: gitlab-managed-apps
GITLAB_MANAGED_APPS_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/config.yaml GITLAB_MANAGED_APPS_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/config.yaml
INGRESS_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/ingress/values.yaml INGRESS_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/ingress/values.yaml
SENTRY_VALUES_FILE: $CI_PROJECT_DIR/.gitlab/managed-apps/sentry/values.yaml
script: script:
- gitlab-managed-apps /usr/local/share/gitlab-managed-apps/helmfile.yaml - gitlab-managed-apps /usr/local/share/gitlab-managed-apps/helmfile.yaml
only: only:

View file

@ -34,6 +34,18 @@ module Gitlab
@diff_files ||= diffs.decorate! { |diff| decorate_diff!(diff) } @diff_files ||= diffs.decorate! { |diff| decorate_diff!(diff) }
end end
def diff_file_paths
diff_files.map(&:file_path)
end
def pagination_data
{
current_page: nil,
next_page: nil,
total_pages: nil
}
end
# This mutates `diff_files` lines. # This mutates `diff_files` lines.
def unfold_diff_files(positions) def unfold_diff_files(positions)
positions_grouped_by_path = positions.group_by { |position| position.file_path } positions_grouped_by_path = positions.group_by { |position| position.file_path }

View file

@ -29,10 +29,6 @@ module Gitlab
} }
end end
def diff_file_paths
diff_files.map(&:file_path)
end
override :diffs override :diffs
def diffs def diffs
strong_memoize(:diffs) do strong_memoize(:diffs) do

View file

@ -21,7 +21,7 @@ module Gitlab
def decorate(diff_file) def decorate(diff_file)
if content = read_file(diff_file) if content = read_file(diff_file)
diff_file.highlighted_diff_lines = content.map do |line| diff_file.highlighted_diff_lines = content.map do |line|
Gitlab::Diff::Line.init_from_hash(line) Gitlab::Diff::Line.safe_init_from_hash(line)
end end
end end
end end

View file

@ -34,6 +34,14 @@ module Gitlab
rich_text: hash[:rich_text]) rich_text: hash[:rich_text])
end end
def self.safe_init_from_hash(hash)
line = hash.with_indifferent_access
rich_text = line[:rich_text]
line[:rich_text] = rich_text&.html_safe
init_from_hash(line)
end
def to_hash def to_hash
hash = {} hash = {}
SERIALIZE_KEYS.each { |key| hash[key] = send(key) } # rubocop:disable GitlabSecurity/PublicSend SERIALIZE_KEYS.each { |key| hash[key] = send(key) } # rubocop:disable GitlabSecurity/PublicSend

View file

@ -43,11 +43,7 @@ module Gitlab
next unless lines next unless lines
JSON.parse(lines).map! do |line| JSON.parse(lines).map! do |line|
line = line.with_indifferent_access Gitlab::Diff::Line.safe_init_from_hash(line)
rich_text = line[:rich_text]
line[:rich_text] = rich_text&.html_safe
Gitlab::Diff::Line.init_from_hash(line)
end end
end end
end end

View file

@ -5,6 +5,19 @@ require 'spec_helper'
describe Projects::MergeRequests::DiffsController do describe Projects::MergeRequests::DiffsController do
include ProjectForksHelper include ProjectForksHelper
shared_examples '404 for unexistent diffable' do
context 'when diffable does not exists' do
it 'returns 404' do
unexistent_diff_id = 9999
go(diff_id: unexistent_diff_id)
expect(MergeRequestDiff.find_by(id: unexistent_diff_id)).to be_nil
expect(response).to have_gitlab_http_status(404)
end
end
end
shared_examples 'forked project with submodules' do shared_examples 'forked project with submodules' do
render_views render_views
@ -137,6 +150,8 @@ describe Projects::MergeRequests::DiffsController do
get :diffs_metadata, params: params.merge(extra_params) get :diffs_metadata, params: params.merge(extra_params)
end end
it_behaves_like '404 for unexistent diffable'
context 'when not authorized' do context 'when not authorized' do
let(:another_user) { create(:user) } let(:another_user) { create(:user) }
@ -159,14 +174,6 @@ describe Projects::MergeRequests::DiffsController do
end end
end end
context 'when diffable does not exists' do
it 'returns 404' do
go(diff_id: 9999)
expect(response).to have_gitlab_http_status(404)
end
end
context 'with valid diff_id' do context 'with valid diff_id' do
it 'returns success' do it 'returns success' do
go(diff_id: merge_request.merge_request_diff.id) go(diff_id: merge_request.merge_request_diff.id)
@ -328,17 +335,53 @@ describe Projects::MergeRequests::DiffsController do
end end
describe 'GET diffs_batch' do describe 'GET diffs_batch' do
shared_examples_for 'serializes diffs with expected arguments' do
it 'serializes paginated merge request diff collection' do
expect_next_instance_of(PaginatedDiffSerializer) do |instance|
expect(instance).to receive(:represent)
.with(an_instance_of(collection), expected_options)
.and_call_original
end
subject
end
end
shared_examples_for 'successful request' do
it 'returns success' do
subject
expect(response).to have_gitlab_http_status(200)
end
end
def collection_arguments(pagination_data = {})
{
merge_request: merge_request,
diff_view: :inline,
pagination_data: {
current_page: nil,
next_page: nil,
total_pages: nil
}.merge(pagination_data)
}
end
def go(extra_params = {}) def go(extra_params = {})
params = { params = {
namespace_id: project.namespace.to_param, namespace_id: project.namespace.to_param,
project_id: project, project_id: project,
id: merge_request.iid, id: merge_request.iid,
page: 1,
per_page: 20,
format: 'json' format: 'json'
} }
get :diffs_batch, params: params.merge(extra_params) get :diffs_batch, params: params.merge(extra_params)
end end
it_behaves_like '404 for unexistent diffable'
context 'when feature is disabled' do context 'when feature is disabled' do
before do before do
stub_feature_flags(diffs_batch_load: false) stub_feature_flags(diffs_batch_load: false)
@ -365,52 +408,60 @@ describe Projects::MergeRequests::DiffsController do
end end
end end
context 'with default params' do context 'with valid diff_id' do
let(:expected_options) do subject { go(diff_id: merge_request.merge_request_diff.id) }
{
merge_request: merge_request, it_behaves_like 'serializes diffs with expected arguments' do
diff_view: :inline, let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch }
pagination_data: { let(:expected_options) { collection_arguments(current_page: 1, total_pages: 1) }
current_page: 1,
next_page: nil,
total_pages: 1
}
}
end end
it 'serializes paginated merge request diff collection' do it_behaves_like 'successful request'
expect_next_instance_of(PaginatedDiffSerializer) do |instance| end
expect(instance).to receive(:represent)
.with(an_instance_of(Gitlab::Diff::FileCollection::MergeRequestDiffBatch), expected_options)
.and_call_original
end
go context 'with commit_id param' do
subject { go(commit_id: merge_request.diff_head_sha) }
it_behaves_like 'serializes diffs with expected arguments' do
let(:collection) { Gitlab::Diff::FileCollection::Commit }
let(:expected_options) { collection_arguments }
end end
end end
context 'with diff_id and start_sha params' do
subject do
go(diff_id: merge_request.merge_request_diff.id,
start_sha: merge_request.merge_request_diff.start_commit_sha)
end
it_behaves_like 'serializes diffs with expected arguments' do
let(:collection) { Gitlab::Diff::FileCollection::Compare }
let(:expected_options) { collection_arguments }
end
it_behaves_like 'successful request'
end
context 'with default params' do
subject { go }
it_behaves_like 'serializes diffs with expected arguments' do
let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch }
let(:expected_options) { collection_arguments(current_page: 1, total_pages: 1) }
end
it_behaves_like 'successful request'
end
context 'with smaller diff batch params' do context 'with smaller diff batch params' do
let(:expected_options) do subject { go(page: 2, per_page: 5) }
{
merge_request: merge_request, it_behaves_like 'serializes diffs with expected arguments' do
diff_view: :inline, let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch }
pagination_data: { let(:expected_options) { collection_arguments(current_page: 2, next_page: 3, total_pages: 4) }
current_page: 2,
next_page: 3,
total_pages: 4
}
}
end end
it 'serializes paginated merge request diff collection' do it_behaves_like 'successful request'
expect_next_instance_of(PaginatedDiffSerializer) do |instance|
expect(instance).to receive(:represent)
.with(an_instance_of(Gitlab::Diff::FileCollection::MergeRequestDiffBatch), expected_options)
.and_call_original
end
go(page: 2, per_page: 5)
end
end end
it_behaves_like 'forked project with submodules' it_behaves_like 'forked project with submodules'

View file

@ -16,6 +16,7 @@ describe 'Public Snippets', :js do
expect(page).to have_content(public_snippet.content) expect(page).to have_content(public_snippet.content)
expect(page).to have_css('.js-embed-btn', visible: false) expect(page).to have_css('.js-embed-btn', visible: false)
expect(page).to have_css('.js-share-btn', visible: false) expect(page).to have_css('.js-share-btn', visible: false)
expect(page.find('.js-snippet-url-area')).to be_readonly
end end
it 'Unauthenticated user should see raw public snippets' do it 'Unauthenticated user should see raw public snippets' do

View file

@ -26,6 +26,7 @@
"stop_path": { "type": "string" }, "stop_path": { "type": "string" },
"cancel_auto_stop_path": { "type": "string" }, "cancel_auto_stop_path": { "type": "string" },
"folder_path": { "type": "string" }, "folder_path": { "type": "string" },
"project_path": { "type": "string" },
"created_at": { "type": "string", "format": "date-time" }, "created_at": { "type": "string", "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" }, "updated_at": { "type": "string", "format": "date-time" },
"auto_stop_at": { "type": "string", "format": "date-time" }, "auto_stop_at": { "type": "string", "format": "date-time" },

View file

@ -1,6 +1,6 @@
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
import mutations from '~/error_tracking/store/list/mutations'; import mutations from '~/error_tracking/store/list/mutations';
import * as types from '~/error_tracking/store/list/mutation_types'; import * as types from '~/error_tracking/store/list/mutation_types';
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
const ADD_RECENT_SEARCH = mutations[types.ADD_RECENT_SEARCH]; const ADD_RECENT_SEARCH = mutations[types.ADD_RECENT_SEARCH];
const CLEAR_RECENT_SEARCHES = mutations[types.CLEAR_RECENT_SEARCHES]; const CLEAR_RECENT_SEARCHES = mutations[types.CLEAR_RECENT_SEARCHES];

View file

@ -8,7 +8,7 @@ describe SnippetsController, '(JavaScript fixtures)', type: :controller do
let(:admin) { create(:admin) } let(:admin) { create(:admin) }
let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} let(:namespace) { create(:namespace, name: 'frontend-fixtures' )}
let(:project) { create(:project, :repository, namespace: namespace, path: 'branches-project') } let(:project) { create(:project, :repository, namespace: namespace, path: 'branches-project') }
let(:snippet) { create(:personal_snippet, title: 'snippet.md', content: '# snippet', file_name: 'snippet.md', author: admin) } let(:snippet) { create(:personal_snippet, :public, title: 'snippet.md', content: '# snippet', file_name: 'snippet.md', author: admin) }
render_views render_views

View file

@ -1,9 +1,9 @@
import Vue from 'vue'; import Vue from 'vue';
import '~/behaviors/markdown/render_gfm'; import '~/behaviors/markdown/render_gfm';
import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
import { createStore } from '~/ide/stores'; import { createStore } from '~/ide/stores';
import RightPane from '~/ide/components/panes/right.vue'; import RightPane from '~/ide/components/panes/right.vue';
import { rightSidebarViews } from '~/ide/constants'; import { rightSidebarViews } from '~/ide/constants';
import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
describe('IDE right pane', () => { describe('IDE right pane', () => {
let Component; let Component;

View file

@ -0,0 +1,70 @@
import snippetEmbed from '~/snippet/snippet_embed';
import { loadHTMLFixture } from './helpers/fixtures';
describe('Snippets', () => {
let embedBtn;
let snippetUrlArea;
let shareBtn;
let scriptTag;
const snippetUrl = 'http://test.host/snippets/1';
beforeEach(() => {
loadHTMLFixture('snippets/show.html');
embedBtn = document.querySelector('.js-embed-btn');
snippetUrlArea = document.querySelector('.js-snippet-url-area');
shareBtn = document.querySelector('.js-share-btn');
});
it('selects the fields content when it is clicked', () => {
jest.spyOn(snippetUrlArea, 'select');
snippetEmbed();
expect(snippetUrlArea.select).not.toHaveBeenCalled();
snippetUrlArea.dispatchEvent(new Event('click'));
expect(snippetUrlArea.select).toHaveBeenCalled();
});
describe('when the snippet url does not include params', () => {
beforeEach(() => {
snippetEmbed();
scriptTag = `<script src="${snippetUrl}.js"></script>`;
});
it('shows the script tag as default', () => {
expect(snippetUrlArea.value).toEqual(scriptTag);
});
it('sets the proper url depending on the button clicked', () => {
shareBtn.dispatchEvent(new Event('click'));
expect(snippetUrlArea.value).toEqual(snippetUrl);
embedBtn.dispatchEvent(new Event('click'));
expect(snippetUrlArea.value).toEqual(scriptTag);
});
});
describe('when the snippet url includes params', () => {
beforeEach(() => {
scriptTag = `<script src="${snippetUrl}.js?foo=bar"></script>`;
snippetUrlArea.value = scriptTag;
snippetUrlArea.dataset.url = `${snippetUrl}?foo=bar`;
snippetEmbed();
});
it('shows the script tag as default', () => {
expect(snippetUrlArea.value).toEqual(scriptTag);
});
it('sets the proper url depending on the button clicked', () => {
shareBtn.dispatchEvent(new Event('click'));
expect(snippetUrlArea.value).toEqual(`${snippetUrl}?foo=bar`);
embedBtn.dispatchEvent(new Event('click'));
expect(snippetUrlArea.value).toEqual(scriptTag);
});
});
});

View file

@ -40,6 +40,9 @@ Object.defineProperty(global.Element.prototype, 'innerText', {
get() { get() {
return this.textContent; return this.textContent;
}, },
set(value) {
this.textContext = value;
},
configurable: true, // make it so that it doesn't blow chunks on re-running tests with things like --watch configurable: true, // make it so that it doesn't blow chunks on re-running tests with things like --watch
}); });

View file

@ -127,4 +127,28 @@ describe SnippetsHelper do
end end
end end
end end
describe '#snippet_embed_input' do
subject { snippet_embed_input(snippet) }
context 'with PersonalSnippet' do
let(:snippet) { public_personal_snippet }
it 'returns the input component' do
expect(subject).to eq embed_input(snippet_url(snippet))
end
end
context 'with ProjectSnippet' do
let(:snippet) { public_project_snippet }
it 'returns the input component' do
expect(subject).to eq embed_input(project_snippet_url(snippet.project, snippet))
end
end
def embed_input(url)
"<input type=\"text\" readonly=\"readonly\" class=\"js-snippet-url-area snippet-embed-input form-control\" data-url=\"#{url}\" value=\"<script src=&quot;#{url}.js&quot;></script>\" autocomplete=\"off\"></input>"
end
end
end end

View file

@ -128,6 +128,47 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do
subject subject
end end
context 'the build has a namespace configured via CI template' do
let(:kubernetes_namespace) { double(namespace: existing_namespace) }
before do
allow(build).to receive(:expanded_kubernetes_namespace)
.and_return(requested_namespace)
end
context 'the requested namespace matches the default' do
let(:requested_namespace) { 'production' }
let(:existing_namespace) { requested_namespace }
it 'creates a namespace' do
expect(Clusters::BuildKubernetesNamespaceService)
.to receive(:new)
.with(cluster, environment: deployment.environment)
.and_return(namespace_builder)
expect(Clusters::Kubernetes::CreateOrUpdateNamespaceService)
.to receive(:new)
.with(cluster: cluster, kubernetes_namespace: kubernetes_namespace)
.and_return(service)
expect(service).to receive(:execute).once
subject
end
end
context 'the requested namespace differs from the default' do
let(:requested_namespace) { 'production' }
let(:existing_namespace) { 'other-namespace' }
it 'does not create a namespace' do
expect(Clusters::Kubernetes::CreateOrUpdateNamespaceService).not_to receive(:new)
subject
end
end
end
end end
context 'kubernetes namespace exists (but has no service_account_token)' do context 'kubernetes namespace exists (but has no service_account_token)' do

View file

@ -68,6 +68,15 @@ describe Gitlab::Diff::HighlightCache, :clean_gitlab_redis_cache do
expect(diff_file.highlighted_diff_lines.size).to be > 5 expect(diff_file.highlighted_diff_lines.size).to be > 5
end end
it 'assigns highlighted diff lines which rich_text are HTML-safe' do
cache.write_if_empty
cache.decorate(diff_file)
rich_texts = diff_file.highlighted_diff_lines.map(&:rich_text)
expect(rich_texts).to all(be_html_safe)
end
end end
describe '#write_if_empty' do describe '#write_if_empty' do

View file

@ -1,18 +1,48 @@
# frozen_string_literal: true # frozen_string_literal: true
describe Gitlab::Diff::Line do require 'spec_helper'
describe '.init_from_hash' do
it 'round-trips correctly with to_hash' do
line = described_class.new('<input>', 'match', 0, 0, 1,
parent_file: double(:file),
line_code: double(:line_code),
rich_text: '&lt;input&gt;')
expect(described_class.init_from_hash(line.to_hash).to_hash) describe Gitlab::Diff::Line do
shared_examples 'line object initialized by hash' do
it 'round-trips correctly with to_hash' do
expect(described_class.safe_init_from_hash(line.to_hash).to_hash)
.to eq(line.to_hash) .to eq(line.to_hash)
end end
end end
let(:line) do
described_class.new('<input>', 'match', 0, 0, 1,
parent_file: double(:file),
line_code: double(:line_code),
rich_text: rich_text)
end
describe '.init_from_hash' do
let(:rich_text) { '&lt;input&gt;' }
it_behaves_like 'line object initialized by hash'
end
describe '.safe_init_from_hash' do
let(:rich_text) { '<input>' }
it_behaves_like 'line object initialized by hash'
it 'ensures rich_text is HTML-safe' do
expect(line.rich_text).not_to be_html_safe
new_line = described_class.safe_init_from_hash(line.to_hash)
expect(new_line.rich_text).to be_html_safe
end
context 'when given hash has no rich_text' do
it_behaves_like 'line object initialized by hash' do
let(:rich_text) { nil }
end
end
end
context "when setting rich text" do context "when setting rich text" do
it 'escapes any HTML special characters in the diff chunk header' do it 'escapes any HTML special characters in the diff chunk header' do
subject = described_class.new("<input>", "", 0, 0, 0) subject = described_class.new("<input>", "", 0, 0, 0)

View file

@ -62,6 +62,15 @@ describe Gitlab::DiscussionsDiff::HighlightCache, :clean_gitlab_redis_cache do
expect(found.second.size).to eq(2) expect(found.second.size).to eq(2)
expect(found.second).to all(be_a(Gitlab::Diff::Line)) expect(found.second).to all(be_a(Gitlab::Diff::Line))
end end
it 'returns lines which rich_text are HTML-safe' do
described_class.write_multiple(mapping)
found = described_class.read_multiple(mapping.keys)
rich_texts = found.flatten.map(&:rich_text)
expect(rich_texts).to all(be_html_safe)
end
end end
describe '#clear_multiple' do describe '#clear_multiple' do

View file

@ -211,6 +211,65 @@ describe MergeRequestDiff do
end end
end end
describe '#diffs_in_batch' do
let(:diff_options) { {} }
shared_examples_for 'fetching full diffs' do
it 'returns diffs from repository comparison' do
expect_next_instance_of(Compare) do |comparison|
expect(comparison).to receive(:diffs_in_batch)
.with(1, 10, diff_options: diff_options)
.and_call_original
end
diff_with_commits.diffs_in_batch(1, 10, diff_options: diff_options)
end
it 'returns a Gitlab::Diff::FileCollection::Compare with full diffs' do
diffs = diff_with_commits.diffs_in_batch(1, 10, diff_options: diff_options)
expect(diffs).to be_a(Gitlab::Diff::FileCollection::Compare)
expect(diffs.diff_files.size).to be > 10
end
it 'returns empty pagination data' do
diffs = diff_with_commits.diffs_in_batch(1, 10, diff_options: diff_options)
expect(diffs.pagination_data).to eq(current_page: nil,
next_page: nil,
total_pages: nil)
end
end
context 'when no persisted files available' do
before do
diff_with_commits.clean!
end
it_behaves_like 'fetching full diffs'
end
context 'when diff_options include ignore_whitespace_change' do
it_behaves_like 'fetching full diffs' do
let(:diff_options) do
{ ignore_whitespace_change: true }
end
end
end
context 'when persisted files available' do
it 'returns paginated diffs' do
diffs = diff_with_commits.diffs_in_batch(1, 10, diff_options: {})
expect(diffs).to be_a(Gitlab::Diff::FileCollection::MergeRequestDiffBatch)
expect(diffs.diff_files.size).to eq(10)
expect(diffs.pagination_data).to eq(current_page: 1,
next_page: 2,
total_pages: 2)
end
end
end
describe '#raw_diffs' do describe '#raw_diffs' do
context 'when the :ignore_whitespace_change option is set' do context 'when the :ignore_whitespace_change option is set' do
it 'creates a new compare object instead of using preprocessed data' do it 'creates a new compare object instead of using preprocessed data' do

View file

@ -558,6 +558,43 @@ describe API::Releases do
end end
end end
context 'when using JOB-TOKEN auth' do
let(:job) { create(:ci_build, user: maintainer) }
let(:params) do
{
name: 'Another release',
tag_name: 'v0.2',
description: 'Another nice release',
released_at: '2019-04-25T10:00:00+09:00'
}
end
context 'when no token is provided' do
it 'returns a :not_found error' do
post api("/projects/#{project.id}/releases"), params: params
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'when an invalid token is provided' do
it 'returns an :unauthorized error' do
post api("/projects/#{project.id}/releases"), params: params.merge(job_token: 'yadayadayada')
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
context 'when a valid token is provided' do
it 'creates the release' do
post api("/projects/#{project.id}/releases"), params: params.merge(job_token: job.token)
expect(response).to have_gitlab_http_status(:created)
expect(project.releases.last.description).to eq('Another nice release')
end
end
end
context 'when tag does not exist in git repository' do context 'when tag does not exist in git repository' do
let(:params) do let(:params) do
{ {