提交 0e13b2c7 编写于 作者: G GitLab Bot

Add latest changes from gitlab-org/gitlab@master

上级 40024efc
此差异已折叠。
02ae27efafdf367d991eac43df02b892be378a1b
31eb7ddcaef320e2ae17e5bc0fa45fa1ebacf5ac
<script>
/* eslint-disable vue/no-v-html */
import { GlIcon } from '@gitlab/ui';
import { GlIcon, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
import ViewerMixin from './mixins';
import { HIGHLIGHT_CLASS_NAME } from './constants';
......@@ -8,6 +7,9 @@ export default {
components: {
GlIcon,
},
directives: {
SafeHtml,
},
mixins: [ViewerMixin],
data() {
return {
......@@ -64,7 +66,7 @@ export default {
</a>
</div>
<div class="blob-content">
<pre class="code highlight"><code id="blob-code-content" v-html="content"></code></pre>
<pre class="code highlight"><code id="blob-code-content" v-safe-html="content"></code></pre>
</div>
</div>
</template>
......@@ -14,6 +14,11 @@ class Projects::Ci::LintsController < Projects::ApplicationController
.new(project: @project, current_user: current_user)
.validate(@content, dry_run: @dry_run)
render :show
respond_to do |format|
format.html { render :show }
format.json do
render json: ::Ci::Lint::ResultSerializer.new.represent(@result)
end
end
end
end
# frozen_string_literal: true
class Ci::Lint::JobEntity < Grape::Entity
expose :name
expose :stage
expose :before_script
expose :script
expose :after_script
expose :tag_list
expose :environment
expose :when
expose :allow_failure
expose :only
expose :except
end
# frozen_string_literal: true
class Ci::Lint::ResultEntity < Grape::Entity
expose :valid?, as: :valid
expose :errors
expose :warnings
expose :jobs, using: Ci::Lint::JobEntity do |result, options|
next [] unless result.valid?
result.jobs
end
end
# frozen_string_literal: true
class Ci::Lint::ResultSerializer < BaseSerializer
entity ::Ci::Lint::ResultEntity
end
......@@ -8,3 +8,17 @@ To generate and validate your changelog entries:
See [development/changelog] documentation for detailed usage.
[development/changelog]: https://docs.gitlab.com/ee/development/changelog.html
# Changelog archival
The current major release is always in [CHANGELOG.md](../CHANGELOG.md) at the
root of the repository.
From GitLab 10.0.0 onwards, we store all changelog entries for a major release
in their own file in this directory. For instance, the changelog entries for the
10.X series of GitLab are in [archive-10.md](archive-10.md). Releases prior to
10.0.0 have their changelogs archived in [archive.md](archive.md).
Changelogs for GitLab Enterprise Edition features (all tiers) are in the
corresponding `-ee` files, such as [CHANGELOG-EE.md](../CHANGELOG-EE.md) and
[archive-12-ee.md](archive-12-ee.md).
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
---
title: Add json api endpoint that provides CI linting
merge_request: 37344
author:
type: added
......@@ -983,7 +983,7 @@ Relative linking enables crosslinks to work:
- in Review Apps, local previews, and `/help`.
- when working on the documentation locally, so you can verify that they work as
early as possible in the process.
- within the GitLab user interace when browsing doc files in their respective
- within the GitLab user interface when browsing doc files in their respective
repositories. For example, the links displayed at
`https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/README.md`.
......@@ -1426,7 +1426,7 @@ interface:
| **{monitor}** Monitoring | View GitLab system information, and information on background jobs, logs, health checks, requests profiles, and audit logs. |
| **{messages}** Messages | Send and manage broadcast messages for your users. |
Use an icon when you find youself having to describe an interface element. For
Use an icon when you find yourself having to describe an interface element. For
example:
- Do: Click the Admin Area icon ( **{admin}** ).
......
......@@ -76,6 +76,9 @@ Version specific changes in Omnibus GitLab Linux packages can be found in [the O
NOTE: **Note:**
Instructions are available for downloading an Omnibus GitLab Linux package locally and [manually installing](https://docs.gitlab.com/omnibus/manual_install.html) it.
NOTE: **Note:**
A step-by-step guide to [upgrading the Omnibus-bundled PostgreSQL is documented separately](https://docs.gitlab.com/omnibus/settings/database.html#upgrade-packaged-postgresql-server).
### Upgrading major versions
Upgrading the *major* version requires more attention.
......
......@@ -65,10 +65,10 @@ module Gitlab
{
name: job.name,
stage: stage.name,
before_script: job.options[:before_script],
script: job.options[:script],
after_script: job.options[:after_script],
tag_list: (job.tag_list if job.is_a?(::Ci::Build)),
before_script: job.options[:before_script].to_a,
script: job.options[:script].to_a,
after_script: job.options[:after_script].to_a,
tag_list: (job.tag_list if job.is_a?(::Ci::Build)).to_a,
environment: job.options.dig(:environment, :name),
when: job.when,
allow_failure: job.allow_failure
......@@ -88,9 +88,9 @@ module Gitlab
jobs << {
name: job[:name],
stage: stage_name,
before_script: job.dig(:options, :before_script),
script: job.dig(:options, :script),
after_script: job.dig(:options, :after_script),
before_script: job.dig(:options, :before_script).to_a,
script: job.dig(:options, :script).to_a,
after_script: job.dig(:options, :after_script).to_a,
tag_list: job[:tag_list].to_a,
only: job[:only],
except: job[:except],
......
......@@ -5,8 +5,8 @@ require 'spec_helper'
RSpec.describe Projects::Ci::LintsController do
include StubRequests
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
before do
sign_in(user)
......@@ -20,7 +20,7 @@ RSpec.describe Projects::Ci::LintsController do
get :show, params: { namespace_id: project.namespace, project_id: project }
end
it { expect(response).to be_successful }
it { expect(response).to have_gitlab_http_status(:ok) }
it 'renders show page' do
expect(response).to render_template :show
......@@ -47,7 +47,8 @@ RSpec.describe Projects::Ci::LintsController do
describe 'POST #create' do
subject { post :create, params: params }
let(:params) { { namespace_id: project.namespace, project_id: project, content: content } }
let(:format) { :html }
let(:params) { { namespace_id: project.namespace, project_id: project, content: content, format: format } }
let(:remote_file_path) { 'https://gitlab.com/gitlab-org/gitlab-foss/blob/1234/.gitlab-ci-1.yml' }
let(:remote_file_content) do
......@@ -71,6 +72,20 @@ RSpec.describe Projects::Ci::LintsController do
HEREDOC
end
shared_examples 'successful request with format json' do
context 'with format json' do
let(:format) { :json }
let(:parsed_body) { Gitlab::Json.parse(response.body) }
it 'renders json' do
expect(response).to have_gitlab_http_status :ok
expect(response.content_type).to eq 'application/json'
expect(parsed_body).to include('errors', 'warnings', 'jobs', 'valid')
expect(parsed_body).to match_schema('entities/lint_result_entity')
end
end
end
context 'with a valid gitlab-ci.yml' do
before do
stub_full_request(remote_file_path).to_return(body: remote_file_content)
......@@ -78,20 +93,23 @@ RSpec.describe Projects::Ci::LintsController do
end
shared_examples 'returns a successful validation' do
it 'returns successfully' do
before do
subject
expect(response).to be_successful
end
it 'render show page' do
subject
it 'returns successfully' do
expect(response).to have_gitlab_http_status :ok
end
it 'renders show page' do
expect(response).to render_template :show
end
it 'retrieves project' do
subject
expect(assigns(:project)).to eq(project)
end
it_behaves_like 'successful request with format json'
end
context 'using legacy validation (YamlProcessor)' do
......@@ -145,25 +163,30 @@ RSpec.describe Projects::Ci::LintsController do
before do
project.add_developer(user)
subject
end
it 'assigns result with errors' do
subject
expect(assigns[:result].errors).to match_array([
'jobs rubocop config should implement a script: or a trigger: keyword',
'jobs config should contain at least one visible job'
])
end
it 'render show page' do
expect(response).to render_template :show
end
it_behaves_like 'successful request with format json'
context 'with dry_run mode' do
subject { post :create, params: params.merge(dry_run: 'true') }
it 'assigns result with errors' do
subject
expect(assigns[:result].errors).to eq(['jobs rubocop config should implement a script: or a trigger: keyword'])
end
it_behaves_like 'successful request with format json'
end
end
......@@ -177,6 +200,14 @@ RSpec.describe Projects::Ci::LintsController do
it 'responds with 404' do
expect(response).to have_gitlab_http_status(:not_found)
end
context 'with format json' do
let(:format) { :json }
it 'responds with 404' do
expect(response).to have_gitlab_http_status :not_found
end
end
end
end
end
{
"type": "object",
"required": [
"name",
"stage",
"before_script",
"script",
"after_script",
"tag_list",
"environment",
"when",
"allow_failure",
"only",
"except"
],
"properties": {
"name": {
"type": ["string"]
},
"stage": {
"type": ["string"]
},
"before_script": {
"type": ["array"],
"items": { "type": "string" }
},
"script": {
"type": ["array"],
"items": { "type": "string" }
},
"after_script": {
"type": ["array"],
"items": { "type": "string" }
},
"when": {
"items": { "type": ["string"] }
},
"allow_failure": {
"type": ["boolean"]
},
"environment": {
"type": ["string", null]
},
"tag_list": {
"type": ["array"],
"items": { "type": "string" }
},
"only": {
"type": ["array", "object", null],
"items": { "type": ["string", "array"]}
},
"except": {
"type": ["array", "object", null],
"items": { "type": ["string", "array"]}
}
},
"additionalProperties": false
}
{
"type": "object",
"required": ["valid", "errors", "jobs", "warnings"],
"properties": {
"errors": {
"type": "array",
"items": { "type": "string" }
},
"warnings": {
"type": "array",
"items": { "type": "string" }
},
"valid": {
"type": "boolean"
},
"jobs": {
"type": ["array", null],
"items": {
"type": "object",
"$ref": "lint_job_entity.json"
}
}
},
"additionalProperties": false
}
......@@ -42,7 +42,7 @@ RSpec.describe Gitlab::Ci::Lint do
expect(build_job[:stage]).to eq('build')
expect(build_job[:before_script]).to eq(['before_build'])
expect(build_job[:script]).to eq(['echo'])
expect(build_job.fetch(:after_script)).to be_nil
expect(build_job.fetch(:after_script)).to eq([])
expect(build_job[:tag_list]).to eq([])
expect(build_job[:environment]).to eq('staging')
expect(build_job[:when]).to eq('manual')
......@@ -51,7 +51,7 @@ RSpec.describe Gitlab::Ci::Lint do
rspec_job = subject.jobs.last
expect(rspec_job[:name]).to eq('rspec')
expect(rspec_job[:stage]).to eq('test')
expect(rspec_job.fetch(:before_script)).to be_nil
expect(rspec_job.fetch(:before_script)).to eq([])
expect(rspec_job[:script]).to eq(['rspec'])
expect(rspec_job[:after_script]).to eq(['after_rspec'])
expect(rspec_job[:tag_list]).to eq(['docker'])
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Ci::Lint::JobEntity, :aggregate_failures do
describe '#represent' do
let(:job) do
{
name: 'rspec',
stage: 'test',
before_script: ['bundle install', 'bundle exec rake db:create'],
script: ["rake spec"],
after_script: ["rake spec"],
tag_list: %w[ruby postgres],
environment: { name: 'hello', url: 'world' },
when: 'on_success',
allow_failure: false,
except: { refs: ["branches"] },
only: { refs: ["branches"] },
variables: { hello: 'world' }
}
end
subject(:serialized_job_result) { described_class.new(job).as_json }
it 'exposes job data' do
expect(serialized_job_result.keys).to contain_exactly(
:name,
:stage,
:before_script,
:script,
:after_script,
:tag_list,
:environment,
:when,
:allow_failure,
:only,
:except
)
expect(serialized_job_result.keys).not_to include(:variables)
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Ci::Lint::ResultEntity do
describe '#represent' do
let(:yaml_content) { YAML.dump({ rspec: { script: 'test', tags: 'mysql' } }) }
let(:result) { Gitlab::Ci::YamlProcessor.new(yaml_content).execute }
subject(:serialized_linting_result) { described_class.new(result).as_json }
it 'serializes with lint result entity' do
expect(serialized_linting_result.keys).to include(:valid, :errors, :jobs, :warnings)
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Ci::Lint::ResultSerializer, :aggregate_failures do
let_it_be(:project) { create(:project, :repository) }
let(:result) do
Gitlab::Ci::Lint
.new(project: project, current_user: project.owner)
.validate(yaml_content, dry_run: false)
end
let(:first_job) { linting_result[:jobs].first }
let(:serialized_linting_result) { linting_result.to_json }
subject(:linting_result) { described_class.new.represent(result) }
shared_examples 'matches schema' do
it { expect(serialized_linting_result).to match_schema('entities/lint_result_entity') }
end
context 'when config is invalid' do
let(:yaml_content) { YAML.dump({ rspec: { script: 'test', tags: 'mysql' } }) }
it_behaves_like 'matches schema'
it 'returns expected validity' do
expect(linting_result[:valid]).to eq(false)
expect(linting_result[:errors]).to eq(['jobs:rspec:tags config should be an array of strings'])
expect(linting_result[:warnings]).to eq([])
end
it 'returns job data' do
expect(linting_result[:jobs]).to eq([])
end
end
context 'when config is valid' do
let(:yaml_content) { File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml')) }
it_behaves_like 'matches schema'
it 'returns expected validity' do
expect(linting_result[:valid]).to eq(true)
expect(linting_result[:errors]).to eq([])
expect(linting_result[:warnings]).to eq([])
end
it 'returns job data' do
expect(first_job[:name]).to eq('rspec')
expect(first_job[:stage]).to eq('test')
expect(first_job[:before_script]).to eq(['bundle install', 'bundle exec rake db:create'])
expect(first_job[:script]).to eq(['rake spec'])
expect(first_job[:after_script]).to eq([])
expect(first_job[:tag_list]).to eq(%w[ruby postgres])
expect(first_job[:environment]).to eq(nil)
expect(first_job[:when]).to eq('on_success')
expect(first_job[:allow_failure]).to eq(false)
expect(first_job[:only]).to eq(refs: ['branches'])
expect(first_job[:except]).to eq(nil)
end
context 'when dry run is enabled' do
let(:result) do
Gitlab::Ci::Lint
.new(project: project, current_user: project.owner)
.validate(yaml_content, dry_run: true)
end
it_behaves_like 'matches schema'
it 'returns expected validity' do
expect(linting_result[:valid]).to eq(true)
expect(linting_result[:errors]).to eq([])
expect(linting_result[:warnings]).to eq([])
end
it 'returns job data' do
expect(first_job[:name]).to eq('rspec')
expect(first_job[:stage]).to eq('test')
expect(first_job[:before_script]).to eq(['bundle install', 'bundle exec rake db:create'])
expect(first_job[:script]).to eq(['rake spec'])
expect(first_job[:after_script]).to eq([])
expect(first_job[:tag_list]).to eq(%w[ruby postgres])
expect(first_job[:environment]).to eq(nil)
expect(first_job[:when]).to eq('on_success')
expect(first_job[:allow_failure]).to eq(false)
expect(first_job[:only]).to eq(nil)
expect(first_job[:except]).to eq(nil)
end
end
context 'when only is not nil in the yaml' do
context 'when only: is hash' do
let(:yaml_content) do
<<~YAML
build:
stage: build
script: echo
only:
refs:
- branches
YAML
end
it_behaves_like 'matches schema'
it 'renders only:refs as hash' do
expect(first_job[:only]).to eq(refs: ['branches'])
end
end
context 'when only is an array of strings in the yaml' do
let(:yaml_content) do
<<~YAML
build:
stage: build
script: echo
only:
- pushes
YAML
end
it_behaves_like 'matches schema'
it 'renders only: list as hash' do
expect(first_job[:only]).to eq(refs: ['pushes'])
end
end
end
context 'when except is not nil in the yaml' do
context 'when except: is hash' do
let(:yaml_content) do
<<~YAML
build:
stage: build
script: echo
except:
refs:
- branches
YAML
end
it_behaves_like 'matches schema'
it 'renders except as hash' do
expect(first_job[:except]).to eq(refs: ['branches'])
end
end
context 'when except is an array of strings in the yaml' do
let(:yaml_content) do
<<~YAML
build:
stage: build
script: echo
except:
- pushes
YAML
end
it_behaves_like 'matches schema'
it 'renders only: list as hash' do
expect(first_job[:except]).to eq(refs: ['pushes'])
end
end
context 'with minimal job configuration' do
let(:yaml_content) do
<<~YAML
build:
stage: build
script: echo
YAML
end
it_behaves_like 'matches schema'
it 'renders the job with defaults' do
expect(first_job[:name]).to eq('build')
expect(first_job[:stage]).to eq('build')
expect(first_job[:before_script]).to eq([])
expect(first_job[:script]).to eq(['echo'])
expect(first_job[:after_script]).to eq([])
expect(first_job[:tag_list]).to eq([])
expect(first_job[:environment]).to eq(nil)
expect(first_job[:when]).to eq('on_success')
expect(first_job[:allow_failure]).to eq(false)
expect(first_job[:only]).to eq(refs: %w[branches tags])
expect(first_job[:except]).to eq(nil)
end
end
context 'with environment defined' do
context 'when formatted as a hash in yaml' do
let(:yaml_content) do
<<~YAML
build:
stage: build
script: echo
environment:
name: production
url: https://example.com
YAML
end
it_behaves_like 'matches schema'
it 'renders the environment as a string' do
expect(first_job[:environment]).to eq('production')
end
end
context 'when formatted as a string in yaml' do
let(:yaml_content) do
<<~YAML
build:
stage: build
script: echo
environment: production
YAML
end
it_behaves_like 'matches schema'
it 'renders the environment as a string' do
expect(first_job[:environment]).to eq('production')
end
end
end
context 'when script values are formatted as arrays in the yaml' do
let(:yaml_content) do
<<~YAML
build:
stage: build
before_script:
- echo
- cat '~/.zshrc'
script:
- echo
- cat '~/.zshrc'
after_script:
- echo
- cat '~/.zshrc'
YAML
end
it_behaves_like 'matches schema'
it 'renders the scripts as arrays' do
expect(first_job[:before_script]).to eq(['echo', "cat '~/.zshrc'"])
expect(first_job[:script]).to eq(['echo', "cat '~/.zshrc'"])
expect(first_job[:after_script]).to eq(['echo', "cat '~/.zshrc'"])
end
end
end
end
end
......@@ -848,10 +848,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.161.0.tgz#661e8d19862dfba0e4c558e2eb6d64b402c1453e"
integrity sha512-qsbboEICn08ZoEoAX/TuYygsFaXlzsCY+CfmdOzqvJbOdfHhVXmrJBxd2hP2qqjTZm2PkbRRmn+03+ce1jvatQ==
"@gitlab/ui@20.17.0":
version "20.17.0"
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-20.17.0.tgz#5a148c778247efc08df5c093acf5e82069823970"
integrity sha512-yDZ+B9/rq7t6OqIHMxPk120KzAO7xM1JKlE9ahkDyijC7lohQy9ygQGFlvVHo1Bic4Y/IW7nzeeZErjzJ3PPtA==
"@gitlab/ui@20.18.0":
version "20.18.0"
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-20.18.0.tgz#f308c444bcd2d0f09fb9ca358c97dd8817ea5598"
integrity sha512-JSIK7qHyQf0jAALUn9igOPSi6fIPNZyen7C0L2HFBzi5WIwYNIrV/4/uFfwdG/5fHvtPvTCbjFRRwOrP2IwCNA==
dependencies:
"@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.3.0"
......@@ -3813,13 +3813,6 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9:
dependencies:
ms "2.0.0"
debug@=3.1.0, debug@~3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
dependencies:
ms "2.0.0"
debug@^3.1.1, debug@^3.2.5, debug@^3.2.6:
version "3.2.6"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
......@@ -3834,6 +3827,13 @@ debug@^4.0.1, debug@^4.1.0, debug@^4.1.1:
dependencies:
ms "^2.1.1"
debug@~3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
dependencies:
ms "2.0.0"
decamelize-keys@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9"
......@@ -5138,14 +5138,7 @@ flush-write-stream@^1.0.0:
inherits "^2.0.3"
readable-stream "^2.3.6"
follow-redirects@^1.0.0:
version "1.5.10"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==
dependencies:
debug "=3.1.0"
follow-redirects@^1.10.0:
follow-redirects@^1.0.0, follow-redirects@^1.10.0:
version "1.13.0"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db"
integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册