Commit 51d92fb5 authored by Kamil Trzciński's avatar Kamil Trzciński

Merge branch '43603-ci-lint-support' into 'master'

Resolve "/ci/lint should support include keyword in config file"

Closes #43603

See merge request gitlab-org/gitlab-ce!17729
parents 949d1b37 bab17600
.ci-body {
.incorrect-syntax {
font-size: 18px;
color: $lint-incorrect-color;
}
.correct-syntax {
font-size: 18px;
color: $lint-correct-color;
}
}
.ci-linter {
.ci-editor {
height: 400px;
}
.ci-template pre {
white-space: pre-wrap;
}
}
......@@ -1121,3 +1121,25 @@ pre.light-well {
padding-top: $gl-padding;
padding-bottom: 37px;
}
.project-ci-body {
.incorrect-syntax {
font-size: 18px;
color: $lint-incorrect-color;
}
.correct-syntax {
font-size: 18px;
color: $lint-correct-color;
}
}
.project-ci-linter {
.ci-editor {
height: 400px;
}
.ci-template pre {
white-space: pre-wrap;
}
}
......@@ -4,20 +4,5 @@ module Ci
def show
end
def create
@content = params[:content]
@error = Gitlab::Ci::YamlProcessor.validation_message(@content)
@status = @error.blank?
if @error.blank?
@config_processor = Gitlab::Ci::YamlProcessor.new(@content)
@stages = @config_processor.stages
@builds = @config_processor.builds
@jobs = @config_processor.jobs
end
render :show
end
end
end
class Projects::Ci::LintsController < Projects::ApplicationController
before_action :authorize_create_pipeline!
def show
end
def create
@content = params[:content]
@error = Gitlab::Ci::YamlProcessor.validation_message(@content, yaml_processor_options)
@status = @error.blank?
if @error.blank?
@config_processor = Gitlab::Ci::YamlProcessor.new(@content, yaml_processor_options)
@stages = @config_processor.stages
@builds = @config_processor.builds
@jobs = @config_processor.jobs
end
render :show
end
private
def yaml_processor_options
{ project: @project, sha: project.repository.commit.sha }
end
end
......@@ -29,12 +29,12 @@ module Projects
@project_runners = @project.runners.ordered
@assignable_runners = current_user.ci_authorized_runners
.assignable_for(project).ordered.page(params[:page]).per(20)
@shared_runners = Ci::Runner.shared.active
@shared_runners = ::Ci::Runner.shared.active
@shared_runners_count = @shared_runners.count(:all)
end
def define_secret_variables
@variable = Ci::Variable.new(project: project)
@variable = ::Ci::Variable.new(project: project)
.present(current_user: current_user)
@variables = project.variables.order_key_asc
.map { |variable| variable.present(current_user: current_user) }
......@@ -42,7 +42,7 @@ module Projects
def define_triggers_variables
@triggers = @project.triggers
@trigger = Ci::Trigger.new
@trigger = ::Ci::Trigger.new
end
def define_badges_variables
......
- page_title "CI Lint"
- page_description "Validate your GitLab CI configuration file"
- content_for :library_javascripts do
= page_specific_javascript_tag('lib/ace.js')
%h2 Check your .gitlab-ci.yml
.ci-linter
.row
= form_tag ci_lint_path, method: :post do
.form-group
.col-sm-12
.file-holder
.js-file-title.file-title.clearfix
Content of .gitlab-ci.yml
#ci-editor.ci-editor= @content
= text_area_tag(:content, @content, class: 'hidden form-control span1', rows: 7, require: true)
.col-sm-12
.pull-left.prepend-top-10
= submit_tag('Validate', class: 'btn btn-success submit-yml')
.pull-right.prepend-top-10
= button_tag('Clear', type: 'button', class: 'btn btn-default clear-yml')
.row.prepend-top-20
.col-sm-12
.results.ci-template
= render partial: 'create' if defined?(@status)
.row.empty-state
.col-xs-12
.svg-content
= image_tag 'illustrations/feature_moved.svg'
.col-xs-12
.text-content.text-center
%h4= _("GitLab CI Linter has been moved")
%p
= _("To validate your GitLab CI configurations, go to 'CI/CD → Pipelines' inside your project, and click on the 'CI Lint' button.")
- page_title "CI Lint"
- page_description "Validate your GitLab CI configuration file"
- content_for :library_javascripts do
= page_specific_javascript_tag('lib/ace.js')
%h2 Check your .gitlab-ci.yml
.project-ci-linter
.row
= form_tag project_ci_lint_path(@project), method: :post do
.form-group
.col-sm-12
.file-holder
.js-file-title.file-title.clearfix
Content of .gitlab-ci.yml
#ci-editor.ci-editor= @content
= text_area_tag(:content, @content, class: 'hidden form-control span1', rows: 7, require: true)
.col-sm-12
.pull-left.prepend-top-10
= submit_tag('Validate', class: 'btn btn-success submit-yml')
.pull-right.prepend-top-10
= button_tag('Clear', type: 'button', class: 'btn btn-default clear-yml')
.row.prepend-top-20
.col-sm-12
.results.project-ci-template
= render partial: 'create' if defined?(@status)
......@@ -10,6 +10,6 @@
"no-pipelines-svg-path" => image_path('illustrations/pipelines_pending.svg'),
"can-create-pipeline" => can?(current_user, :create_pipeline, @project).to_s,
"new-pipeline-path" => can?(current_user, :create_pipeline, @project) && new_project_pipeline_path(@project),
"ci-lint-path" => can?(current_user, :create_pipeline, @project) && ci_lint_path,
"ci-lint-path" => can?(current_user, :create_pipeline, @project) && project_ci_lint_path(@project),
"reset-cache-path" => can?(current_user, :admin_pipeline, @project) && reset_cache_project_settings_ci_cd_path(@project) ,
"has-gitlab-ci" => (@project.has_ci? && @project.builds_enabled?).to_s } }
---
title: Move ci/lint under project's namespace
merge_request: 17729
author:
type: added
namespace :ci do
resource :lint, only: [:show, :create]
resource :lint, only: :show
root to: redirect('')
end
......@@ -280,6 +280,10 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
post :keep
end
end
namespace :ci do
resource :lint, only: [:show, :create]
end
end
draw :legacy_builds
......
......@@ -104,8 +104,8 @@ Jobs are used to create jobs, which are then picked by
What is important is that each job is run independently from each other.
If you want to check whether your `.gitlab-ci.yml` file is valid, there is a
Lint tool under the page `/ci/lint` of your GitLab instance. You can also find
If you want to check whether the `.gitlab-ci.yml` of your project is valid, there is a
Lint tool under the page `/ci/lint` of your project namespace. You can also find
a "CI Lint" button to go to this page under **CI/CD ➔ Pipelines** and
**Pipelines ➔ Jobs** in your project.
......
......@@ -1526,8 +1526,9 @@ capitalization, the commit will be created but the pipeline will be skipped.
## Validate the .gitlab-ci.yml
Each instance of GitLab CI has an embedded debug tool called Lint.
You can find the link under `/ci/lint` of your gitlab instance.
Each instance of GitLab CI has an embedded debug tool called Lint, which validates the
content of your `.gitlab-ci.yml` files. You can find the Lint under the page `ci/lint` of your
project namespace (e.g, `http://gitlab-example.com/gitlab-org/project-123/ci/lint`)
## Using reserved keywords
......
......@@ -4,7 +4,8 @@ module Gitlab
# Base GitLab CI Configuration facade
#
class Config
def initialize(config)
# EE would override this and utilize opts argument
def initialize(config, opts = {})
@config = Loader.new(config).load!
@global = Entry::Global.new(@config)
......
......@@ -7,8 +7,8 @@ module Gitlab
attr_reader :cache, :stages, :jobs
def initialize(config)
@ci_config = Gitlab::Ci::Config.new(config)
def initialize(config, opts = {})
@ci_config = Gitlab::Ci::Config.new(config, opts)
@config = @ci_config.to_hash
unless @ci_config.valid?
......@@ -73,11 +73,11 @@ module Gitlab
end
end
def self.validation_message(content)
def self.validation_message(content, opts = {})
return 'Please provide content of .gitlab-ci.yml' if content.blank?
begin
Gitlab::Ci::YamlProcessor.new(content)
Gitlab::Ci::YamlProcessor.new(content, opts)
nil
rescue ValidationError => e
e.message
......
require 'spec_helper'
describe Projects::Ci::LintsController do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
before do
sign_in(user)
end
describe 'GET #show' do
context 'with enough privileges' do
before do
project.add_developer(user)
get :show, namespace_id: project.namespace, project_id: project
end
it 'should be success' do
expect(response).to be_success
end
it 'should render show page' do
expect(response).to render_template :show
end
it 'should retrieve project' do
expect(assigns(:project)).to eq(project)
end
end
context 'without enough privileges' do
before do
project.add_guest(user)
get :show, namespace_id: project.namespace, project_id: project
end
it 'should respond with 404' do
expect(response).to have_gitlab_http_status(404)
end
end
end
describe 'POST #create' do
let(:remote_file_path) { 'https://gitlab.com/gitlab-org/gitlab-ce/blob/1234/.gitlab-ci-1.yml' }
let(:remote_file_content) do
<<~HEREDOC
before_script:
- apt-get update -qq && apt-get install -y -qq sqlite3 libsqlite3-dev nodejs
- ruby -v
- which ruby
- gem install bundler --no-ri --no-rdoc
- bundle install --jobs $(nproc) "${FLAGS[@]}"
HEREDOC
end
let(:content) do
<<~HEREDOC
include:
- #{remote_file_path}
rubocop:
script:
- bundle exec rubocop
HEREDOC
end
context 'with a valid gitlab-ci.yml' do
before do
WebMock.stub_request(:get, remote_file_path).to_return(body: remote_file_content)
project.add_developer(user)
post :create, namespace_id: project.namespace, project_id: project, content: content
end
it 'should be success' do
expect(response).to be_success
end
it 'render show page' do
expect(response).to render_template :show
end
it 'should retrieve project' do
expect(assigns(:project)).to eq(project)
end
end
context 'with an invalid gitlab-ci.yml' do
let(:content) do
<<~HEREDOC
rubocop:
scriptt:
- bundle exec rubocop
HEREDOC
end
before do
project.add_developer(user)
post :create, namespace_id: project.namespace, project_id: project, content: content
end
it 'should assign errors' do
expect(assigns[:error]).to eq('jobs:rubocop config contains unknown keys: scriptt')
end
end
context 'without enough privileges' do
before do
project.add_guest(user)
post :create, namespace_id: project.namespace, project_id: project, content: content
end
it 'should respond with 404' do
expect(response).to have_gitlab_http_status(404)
end
end
end
end
require 'spec_helper'
describe 'CI Lint', :js do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
before do
sign_in(create(:user))
project.add_developer(user)
sign_in(user)
visit ci_lint_path
visit project_ci_lint_path(project)
find('#ci-editor')
execute_script("ace.edit('ci-editor').setValue(#{yaml_content.to_json});")
......
require 'spec_helper'
describe 'ci/lints/show' do
describe 'projects/ci/lints/show' do
include Devise::Test::ControllerHelpers
let(:project) { create(:project, :repository) }
let(:config_processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(content)) }
describe 'XSS protection' do
let(:config_processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(content)) }
before do
assign(:project, project)
assign(:status, true)
assign(:builds, config_processor.builds)
assign(:stages, config_processor.stages)
......@@ -48,22 +49,21 @@ describe 'ci/lints/show' do
end
end
let(:content) do
{
build_template: {
script: './build.sh',
tags: ['dotnet'],
only: ['test@dude/repo'],
except: ['deploy'],
environment: 'testing'
context 'when the content is valid' do
let(:content) do
{
build_template: {
script: './build.sh',
tags: ['dotnet'],
only: ['test@dude/repo'],
except: ['deploy'],
environment: 'testing'
}
}
}
end
let(:config_processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(content)) }
end
context 'when the content is valid' do
before do
assign(:project, project)
assign(:status, true)
assign(:builds, config_processor.builds)
assign(:stages, config_processor.stages)
......@@ -83,6 +83,7 @@ describe 'ci/lints/show' do
context 'when the content is invalid' do
before do
assign(:project, project)
assign(:status, false)
assign(:error, 'Undefined error')
end
......
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