Commit f444f745 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@12-6-stable-ee

parent 58fa510a
......@@ -12,6 +12,14 @@ module Clusters
cluster.kubeclient&.get_namespace(Clusters::Kubernetes::KNATIVE_SERVING_NAMESPACE)
rescue Kubeclient::ResourceNotFoundError
nil
rescue Kubeclient::HttpError => e
# If the kubernetes auth engine is enabled, it will return 403
if e.error_code == 403
Gitlab::ErrorTracking.track_exception(e)
nil
else
raise
end
end
end
end
......@@ -32,6 +32,7 @@ module Ci
has_many :stages, -> { order(position: :asc) }, inverse_of: :pipeline
has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline
has_many :latest_statuses_ordered_by_stage, -> { latest.order(:stage_idx, :stage) }, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline
has_many :processables, -> { processables },
class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline
has_many :builds, foreign_key: :commit_id, inverse_of: :pipeline
......@@ -45,6 +46,7 @@ module Ci
has_many :merge_requests_as_head_pipeline, foreign_key: "head_pipeline_id", class_name: 'MergeRequest'
has_many :pending_builds, -> { pending }, foreign_key: :commit_id, class_name: 'Ci::Build'
has_many :failed_builds, -> { latest.failed }, foreign_key: :commit_id, class_name: 'Ci::Build', inverse_of: :pipeline
has_many :retryable_builds, -> { latest.failed_or_canceled.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build'
has_many :cancelable_statuses, -> { cancelable }, foreign_key: :commit_id, class_name: 'CommitStatus'
has_many :manual_actions, -> { latest.manual_actions.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build'
......@@ -377,9 +379,7 @@ module Ci
end
def legacy_stages_using_composite_status
stages = statuses.latest
.order(:stage_idx, :stage)
.group_by(&:stage)
stages = latest_statuses_ordered_by_stage.group_by(&:stage)
stages.map do |stage_name, jobs|
composite_status = Gitlab::Ci::Status::Composite
......
......@@ -78,7 +78,7 @@ class PipelineEntity < Grape::Entity
end
expose :failed_builds, if: -> (*) { can_retry? }, using: JobEntity do |pipeline|
pipeline.builds.failed
pipeline.failed_builds
end
private
......
......@@ -40,7 +40,11 @@ class PipelineSerializer < BaseSerializer
def preloaded_relations
[
:latest_statuses_ordered_by_stage,
:stages,
{
failed_builds: %i(project metadata)
},
:retryable_builds,
:cancelable_statuses,
:trigger_requests,
......@@ -48,6 +52,7 @@ class PipelineSerializer < BaseSerializer
:scheduled_actions,
:artifacts,
:merge_request,
:user,
{
pending_builds: :project,
project: [:route, { namespace: :route }],
......
---
title: Fix stack trace highlight for PHP
merge_request: 22258
author:
type: fixed
---
title: Handle forbidden error when checking for knative
merge_request: 22170
author:
type: fixed
---
title: Eliminate N+1 queries in PipelinesController#index
merge_request: 22189
author:
type: performance
......@@ -57,7 +57,7 @@ Parameters:
Creates a two-way relation between two issues. User must be allowed to update both issues in order to succeed.
```
POST /projects/:id/issues/:issue_iid/links/:target_project_id/:target_issue_iid
POST /projects/:id/issues/:issue_iid/links
```
| Attribute | Type | Required | Description |
......@@ -67,6 +67,12 @@ POST /projects/:id/issues/:issue_iid/links/:target_project_id/:target_issue_iid
| `target_project_id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) of a target project |
| `target_issue_iid` | integer/string | yes | The internal ID of a target project's issue |
```bash
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/4/issues/1/links?target_project_id=5&target_issue_iid=1"
```
Example response:
```json
{
"source_issue" : {
......
......@@ -116,6 +116,35 @@ rendered to HTML when viewed.
Interactive features, including JavaScript plots, will not work when viewed in
GitLab.
### OpenAPI viewer
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/19515) in GitLab 12.6.
GitLab can render OpenAPI specification files with its file viewer, provided
their filenames include `openapi` or `swagger` and their extension is `yaml`,
`yml`, or `json`. The following examples are all correct:
- `openapi.yml`
- `openapi.yaml`
- `openapi.json`
- `swagger.yml`
- `swagger.yaml`
- `swagger.json`
- `gitlab_swagger.yml`
- `openapi_gitlab.yml`
- `OpenAPI.YML`
- `openapi.Yaml`
- `openapi.JSON`
- `openapi.gitlab.yml`
- `gitlab.openapi.yml`
Then, to render them:
1. Navigate to the OpenAPI file in your repository in GitLab's UI.
1. Click the "Display OpenAPI" button which is located between the "Display source"
and "Edit" buttons (when an OpenAPI file is found, it replaces the
"Display rendered file" button).
## Branches
For details, see [Branches](branches/index.md).
......
......@@ -28,7 +28,7 @@ module Gitlab
end
def highlight_entry_context(filename, context)
language = Rouge::Lexer.guess_by_filename(filename).tag
language = guess_language_by_filename(filename)
context.map do |line_number, line_of_code|
[
......@@ -38,6 +38,12 @@ module Gitlab
]
end
end
def guess_language_by_filename(filename)
Rouge::Lexer.guess_by_filename(filename).tag
rescue Rouge::Guesser::Ambiguous => e
e.alternatives.min_by(&:tag)&.tag
end
end
end
end
......@@ -6,7 +6,7 @@ describe Projects::PipelinesController do
include ApiHelpers
let_it_be(:user) { create(:user) }
let(:project) { create(:project, :public, :repository) }
let_it_be(:project) { create(:project, :public, :repository) }
let(:feature) { ProjectFeature::ENABLED }
before do
......@@ -19,12 +19,12 @@ describe Projects::PipelinesController do
describe 'GET index.json' do
before do
%w(pending running success failed canceled).each_with_index do |status, index|
create_pipeline(status, project.commit("HEAD~#{index}"))
end
create_all_pipeline_types
end
context 'when using persisted stages', :request_store do
render_views
before do
stub_feature_flags(ci_pipeline_persisted_stages: true)
end
......@@ -32,9 +32,7 @@ describe Projects::PipelinesController do
it 'returns serialized pipelines', :request_store do
expect(::Gitlab::GitalyClient).to receive(:allow_ref_name_caching).and_call_original
queries = ActiveRecord::QueryRecorder.new do
get_pipelines_index_json
end
get_pipelines_index_json
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('pipeline')
......@@ -49,8 +47,22 @@ describe Projects::PipelinesController do
json_response.dig('pipelines', 0, 'details', 'stages').tap do |stages|
expect(stages.count).to eq 3
end
end
it 'does not execute N+1 queries' do
get_pipelines_index_json
control_count = ActiveRecord::QueryRecorder.new do
get_pipelines_index_json
end.count
expect(queries.count).to be
create_all_pipeline_types
# There appears to be one extra query for Pipelines#has_warnings? for some reason
expect { get_pipelines_index_json }.not_to exceed_query_limit(control_count + 1)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['pipelines'].count).to eq 10
end
end
......@@ -133,19 +145,27 @@ describe Projects::PipelinesController do
format: :json
end
def create_all_pipeline_types
%w(pending running success failed canceled).each_with_index do |status, index|
create_pipeline(status, project.commit("HEAD~#{index}"))
end
end
def create_pipeline(status, sha)
user = create(:user)
pipeline = create(:ci_empty_pipeline, status: status,
project: project,
sha: sha)
sha: sha,
user: user)
create_build(pipeline, 'build', 1, 'build')
create_build(pipeline, 'test', 2, 'test')
create_build(pipeline, 'deploy', 3, 'deploy')
create_build(pipeline, 'build', 1, 'build', user)
create_build(pipeline, 'test', 2, 'test', user)
create_build(pipeline, 'deploy', 3, 'deploy', user)
end
def create_build(pipeline, stage, stage_idx, name)
def create_build(pipeline, stage, stage_idx, name, user = nil)
status = %w[created running pending success failed canceled].sample
create(:ci_build, pipeline: pipeline, stage: stage, stage_idx: stage_idx, name: name, status: status)
create(:ci_build, pipeline: pipeline, stage: stage, stage_idx: stage_idx, name: name, status: status, user: user)
end
end
......
......@@ -35,6 +35,16 @@ FactoryBot.define do
[8, "}\n"]
]
},
{
'function' => 'print',
'lineNo' => 3,
'filename' => 'hello_world.php',
'context' => [
[1, "// PHP/Hack example\n"],
[2, "<?php\n"],
[3, "echo 'Hello, World!';\n"]
]
},
{
'filename' => 'blank.txt'
}
......
# frozen_string_literal: true
require 'spec_helper'
describe Clusters::KnativeServingNamespaceFinder do
include KubernetesHelpers
let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:service) { environment.deployment_platform }
let(:project) { cluster.cluster_project.project }
let(:environment) { create(:environment, project: project) }
subject { described_class.new(cluster) }
before do
stub_kubeclient_discover(service.api_url)
end
it 'finds the namespace in a cluster where it exists' do
stub_kubeclient_get_namespace(service.api_url, namespace: Clusters::Kubernetes::KNATIVE_SERVING_NAMESPACE)
expect(subject.execute).to be_a Kubeclient::Resource
end
it 'returns nil in a cluster where it does not' do
stub_kubeclient_get_namespace(
service.api_url,
namespace: Clusters::Kubernetes::KNATIVE_SERVING_NAMESPACE,
response: {
status: [404, "Resource Not Found"]
}
)
expect(subject.execute).to be nil
end
it 'returns nil in a cluster where the lookup results in a 403 as it will in some versions of kubernetes' do
stub_kubeclient_get_namespace(
service.api_url,
namespace: Clusters::Kubernetes::KNATIVE_SERVING_NAMESPACE,
response: {
status: [403, "Resource Not Found"]
}
)
expect(subject.execute).to be nil
end
it 'raises an error if error code is not 404 or 403' do
stub_kubeclient_get_namespace(
service.api_url,
namespace: Clusters::Kubernetes::KNATIVE_SERVING_NAMESPACE,
response: {
status: [500, "Internal Server Error"]
}
)
expect { subject.execute }.to raise_error(Kubeclient::HttpError)
end
end
......@@ -48,6 +48,16 @@ describe Gitlab::ErrorTracking::StackTraceHighlightDecorator do
[8, '<span id="LC1" class="line" lang="swift"><span class="p">}</span></span>']
]
},
{
'function' => 'print',
'lineNo' => 3,
'filename' => 'hello_world.php',
'context' => [
[1, '<span id="LC1" class="line" lang="hack"><span class="c1">// PHP/Hack example</span></span>'],
[2, '<span id="LC1" class="line" lang="hack"><span class="cp">&lt;?php</span></span>'],
[3, '<span id="LC1" class="line" lang="hack"><span class="k">echo</span> <span class="s1">\'Hello, World!\'</span><span class="p">;</span></span>']
]
},
{
'filename' => 'blank.txt'
}
......
......@@ -160,6 +160,7 @@ ci_pipelines:
- user
- stages
- statuses
- latest_statuses_ordered_by_stage
- builds
- processables
- trigger_requests
......@@ -168,6 +169,7 @@ ci_pipelines:
- auto_canceled_pipelines
- auto_canceled_jobs
- pending_builds
- failed_builds
- retryable_builds
- cancelable_statuses
- manual_actions
......
......@@ -159,7 +159,7 @@ describe PipelineSerializer do
it 'verifies number of queries', :request_store do
recorded = ActiveRecord::QueryRecorder.new { subject }
expected_queries = Gitlab.ee? ? 38 : 35
expected_queries = Gitlab.ee? ? 42 : 39
expect(recorded.count).to be_within(2).of(expected_queries)
expect(recorded.cached_count).to eq(0)
......@@ -180,7 +180,7 @@ describe PipelineSerializer do
# pipeline. With the same ref this check is cached but if refs are
# different then there is an extra query per ref
# https://gitlab.com/gitlab-org/gitlab-foss/issues/46368
expected_queries = Gitlab.ee? ? 41 : 38
expected_queries = Gitlab.ee? ? 45 : 42
expect(recorded.count).to be_within(2).of(expected_queries)
expect(recorded.cached_count).to eq(0)
......
......@@ -229,9 +229,9 @@ module KubernetesHelpers
.to_return(kube_response(kube_v1_namespace_list_body))
end
def stub_kubeclient_get_namespace(api_url, namespace: 'default')
def stub_kubeclient_get_namespace(api_url, namespace: 'default', response: kube_response({}))
WebMock.stub_request(:get, api_url + "/api/v1/namespaces/#{namespace}")
.to_return(kube_response({}))
.to_return(response)
end
def stub_kubeclient_put_cluster_role(api_url, name)
......
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