Commit c8102343 authored by Kamil Trzciński's avatar Kamil Trzciński

Merge branch 'ci-project-migrate' into 'master'

Ci Project migrate

- This doesn't migrate: allow_git_fetch, coverage_regex, timeout. Since this are project configuration settings I would propose to migrate them to `.gitlab-ci.yml`.
- This requires offline migrations.
- It simplifies database models making all CI objects to be attached to: Project.
- It removes Ci::Project, but makes /ci/projects working by adding method: Project.find_by_ci_id for backward compatibility (badges, triggers).
- We should add default `timeout` to Application Settings.
- It misses specs.
- It is based on ci-services-migrate for now.
- It removes CI events.
- It removes administrator CI projects overview.
- It removes CI application settings.

In 8.4 or 8.5 we can remove redundant tables and columns.


See merge request !1987
parents e81ae1e6 baa38f0d
class Admin::BuildsController < Admin::ApplicationController
def index
@scope = params[:scope]
@all_builds = Ci::Build
@builds = @all_builds.order('created_at DESC')
@builds =
case @scope
when 'all'
@builds
when 'finished'
@builds.finished
else
@builds.running_or_pending.reverse_order
end
@builds = @builds.page(params[:page]).per(30)
end
def cancel_all
Ci::Build.running_or_pending.each(&:cancel)
redirect_to admin_builds_path
end
end
class Admin::RunnerProjectsController < Admin::ApplicationController
before_action :project, only: [:create]
def index
@runner_projects = project.runner_projects.all
@runner_project = project.runner_projects.new
end
def create
@runner = Ci::Runner.find(params[:runner_project][:runner_id])
if @runner.assign_to(@project, current_user)
redirect_to admin_runner_path(@runner)
else
redirect_to admin_runner_path(@runner), alert: 'Failed adding runner to project'
end
end
def destroy
rp = Ci::RunnerProject.find(params[:id])
runner = rp.runner
rp.destroy
redirect_to admin_runner_path(runner)
end
private
def project
@project = Project.find_with_namespace(
[params[:namespace_id], '/', params[:project_id]].join('')
)
@project || render_404
end
end
class Admin::RunnersController < Admin::ApplicationController
before_action :runner, except: :index
def index
@runners = Ci::Runner.order('id DESC')
@runners = @runners.search(params[:search]) if params[:search].present?
@runners = @runners.page(params[:page]).per(30)
@active_runners_cnt = Ci::Runner.online.count
end
def show
@builds = @runner.builds.order('id DESC').first(30)
@projects =
if params[:search].present?
::Project.search(params[:search])
else
Project.all
end
@projects = @projects.where.not(id: @runner.projects.select(:id)) if @runner.projects.any?
@projects = @projects.page(params[:page]).per(30)
end
def update
@runner.update_attributes(runner_params)
respond_to do |format|
format.js
format.html { redirect_to admin_runner_path(@runner) }
end
end
def destroy
@runner.destroy
redirect_to admin_runners_path
end
def resume
if @runner.update_attributes(active: true)
redirect_to admin_runners_path, notice: 'Runner was successfully updated.'
else
redirect_to admin_runners_path, alert: 'Runner was not updated.'
end
end
def pause
if @runner.update_attributes(active: false)
redirect_to admin_runners_path, notice: 'Runner was successfully updated.'
else
redirect_to admin_runners_path, alert: 'Runner was not updated.'
end
end
private
def runner
@runner ||= Ci::Runner.find(params[:id])
end
def runner_params
params.require(:runner).permit(:token, :description, :tag_list, :active)
end
end
module Ci
module Admin
class ApplicationController < Ci::ApplicationController
before_action :authenticate_user!
before_action :authenticate_admin!
layout "ci/admin"
end
end
end
module Ci
class Admin::ApplicationSettingsController < Ci::Admin::ApplicationController
before_action :set_application_setting
def show
end
def update
if @application_setting.update_attributes(application_setting_params)
redirect_to ci_admin_application_settings_path,
notice: 'Application settings saved successfully'
else
render :show
end
end
private
def set_application_setting
@application_setting = Ci::ApplicationSetting.current
@application_setting ||= Ci::ApplicationSetting.create_from_defaults
end
def application_setting_params
params.require(:application_setting).permit(
:all_broken_builds,
:add_pusher,
)
end
end
end
module Ci
class Admin::BuildsController < Ci::Admin::ApplicationController
def index
@scope = params[:scope]
@builds = Ci::Build.order('created_at DESC').page(params[:page]).per(30)
@builds =
case @scope
when "pending"
@builds.pending
when "running"
@builds.running
else
@builds
end
end
end
end
module Ci
class Admin::EventsController < Ci::Admin::ApplicationController
EVENTS_PER_PAGE = 50
def index
@events = Ci::Event.admin.order('created_at DESC').page(params[:page]).per(EVENTS_PER_PAGE)
end
end
end
module Ci
class Admin::ProjectsController < Ci::Admin::ApplicationController
def index
@projects = Ci::Project.ordered_by_last_commit_date.page(params[:page]).per(30)
end
def destroy
project.destroy
redirect_to ci_projects_url
end
protected
def project
@project ||= Ci::Project.find(params[:id])
end
end
end
module Ci
class Admin::RunnerProjectsController < Ci::Admin::ApplicationController
layout 'ci/project'
def index
@runner_projects = project.runner_projects.all
@runner_project = project.runner_projects.new
end
def create
@runner = Ci::Runner.find(params[:runner_project][:runner_id])
if @runner.assign_to(project, current_user)
redirect_to ci_admin_runner_path(@runner)
else
redirect_to ci_admin_runner_path(@runner), alert: 'Failed adding runner to project'
end
end
def destroy
rp = Ci::RunnerProject.find(params[:id])
runner = rp.runner
rp.destroy
redirect_to ci_admin_runner_path(runner)
end
private
def project
@project ||= Ci::Project.find(params[:project_id])
end
end
end
module Ci
class Admin::RunnersController < Ci::Admin::ApplicationController
before_action :runner, except: :index
def index
@runners = Ci::Runner.order('id DESC')
@runners = @runners.search(params[:search]) if params[:search].present?
@runners = @runners.page(params[:page]).per(30)
@active_runners_cnt = Ci::Runner.online.count
end
def show
@builds = @runner.builds.order('id DESC').first(30)
@projects = Ci::Project.all
if params[:search].present?
@gl_projects = ::Project.search(params[:search])
@projects = @projects.where(gitlab_id: @gl_projects.select(:id))
end
@projects = @projects.where("ci_projects.id NOT IN (?)", @runner.projects.pluck(:id)) if @runner.projects.any?
@projects = @projects.joins(:gl_project)
@projects = @projects.page(params[:page]).per(30)
end
def update
@runner.update_attributes(runner_params)
respond_to do |format|
format.js
format.html { redirect_to ci_admin_runner_path(@runner) }
end
end
def destroy
@runner.destroy
redirect_to ci_admin_runners_path
end
def resume
if @runner.update_attributes(active: true)
redirect_to ci_admin_runners_path, notice: 'Runner was successfully updated.'
else
redirect_to ci_admin_runners_path, alert: 'Runner was not updated.'
end
end
def pause
if @runner.update_attributes(active: false)
redirect_to ci_admin_runners_path, notice: 'Runner was successfully updated.'
else
redirect_to ci_admin_runners_path, alert: 'Runner was not updated.'
end
end
def assign_all
Ci::Project.unassigned(@runner).all.each do |project|
@runner.assign_to(project, current_user)
end
redirect_to ci_admin_runner_path(@runner), notice: "Runner was assigned to all projects"
end
private
def runner
@runner ||= Ci::Runner.find(params[:id])
end
def runner_params
params.require(:runner).permit(:token, :description, :tag_list, :active)
end
end
end
......@@ -4,24 +4,16 @@ module Ci
"app/helpers/ci"
end
helper_method :gl_project
private
def authenticate_token!
unless project.valid_token?(params[:token])
return head(403)
end
end
def authorize_access_project!
unless can?(current_user, :read_project, gl_project)
unless can?(current_user, :read_project, project)
return page_404
end
end
def authorize_manage_builds!
unless can?(current_user, :manage_builds, gl_project)
unless can?(current_user, :manage_builds, project)
return page_404
end
end
......@@ -31,7 +23,7 @@ module Ci
end
def authorize_manage_project!
unless can?(current_user, :admin_project, gl_project)
unless can?(current_user, :admin_project, project)
return page_404
end
end
......@@ -58,9 +50,5 @@ module Ci
count: count
}
end
def gl_project
::Project.find(@project.gitlab_id)
end
end
end
module Ci
class LintsController < Ci::ApplicationController
class LintsController < ApplicationController
before_action :authenticate_user!
def show
......
......@@ -3,13 +3,12 @@ module Ci
before_action :project, except: [:index]
before_action :authenticate_user!, except: [:index, :build, :badge]
before_action :authorize_access_project!, except: [:index, :badge]
before_action :authorize_manage_project!, only: [:toggle_shared_runners, :dumped_yaml]
before_action :no_cache, only: [:badge]
protect_from_forgery
def show
# Temporary compatibility with CI badges pointing to CI project page
redirect_to namespace_project_path(project.gl_project.namespace, project.gl_project)
redirect_to namespace_project_path(project.namespace, project)
end
# Project status badge
......@@ -20,16 +19,10 @@ module Ci
send_file image.path, filename: image.name, disposition: 'inline', type:"image/svg+xml"
end
def toggle_shared_runners
project.toggle!(:shared_runners_enabled)
redirect_to namespace_project_runners_path(project.gl_project.namespace, project.gl_project)
end
protected
def project
@project ||= Ci::Project.find(params[:id])
@project ||= Project.find_by(ci_id: params[:id].to_i)
end
def no_cache
......
module Ci
class RunnerProjectsController < Ci::ApplicationController
before_action :authenticate_user!
before_action :project
before_action :authorize_manage_project!
def create
@runner = Ci::Runner.find(params[:runner_project][:runner_id])
return head(403) unless current_user.ci_authorized_runners.include?(@runner)
path = runners_path(@project.gl_project)
if @runner.assign_to(project, current_user)
redirect_to path
else
redirect_to path, alert: 'Failed adding runner to project'
end
end
def destroy
runner_project = project.runner_projects.find(params[:id])
runner_project.destroy
redirect_to runners_path(@project.gl_project)
end
private
def project
@project ||= Ci::Project.find(params[:project_id])
end
end
end
......@@ -31,8 +31,4 @@ class Projects::ApplicationController < ApplicationController
def builds_enabled
return render_404 unless @project.builds_enabled?
end
def ci_project
@ci_project ||= @project.ensure_gitlab_ci_project
end
end
class Projects::BuildsController < Projects::ApplicationController
before_action :ci_project
before_action :build, except: [:index, :cancel_all]
before_action :authorize_manage_builds!, except: [:index, :show, :status]
......@@ -9,7 +8,7 @@ class Projects::BuildsController < Projects::ApplicationController
def index
@scope = params[:scope]
@all_builds = project.ci_builds
@all_builds = project.builds
@builds = @all_builds.order('created_at DESC')
@builds =
case @scope
......@@ -24,13 +23,13 @@ class Projects::BuildsController < Projects::ApplicationController
end
def cancel_all
@project.ci_builds.running_or_pending.each(&:cancel)
@project.builds.running_or_pending.each(&:cancel)
redirect_to namespace_project_builds_path(project.namespace, project)
end
def show
@builds = @ci_project.commits.find_by_sha(@build.sha).builds.order('id DESC')
@builds = @project.ci_commits.find_by_sha(@build.sha).builds.order('id DESC')
@builds = @builds.where("id not in (?)", @build.id)
@commit = @build.commit
......@@ -77,7 +76,7 @@ class Projects::BuildsController < Projects::ApplicationController
private
def build
@build ||= ci_project.builds.unscoped.find_by!(id: params[:id])
@build ||= project.builds.unscoped.find_by!(id: params[:id])
end
def artifacts_file
......@@ -85,7 +84,7 @@ class Projects::BuildsController < Projects::ApplicationController
end
def build_path(build)
namespace_project_build_path(build.gl_project.namespace, build.gl_project, build)
namespace_project_build_path(build.project.namespace, build.project, build)
end
def authorize_manage_builds!
......
class Projects::CiSettingsController < Projects::ApplicationController
before_action :ci_project
before_action :authorize_admin_project!
layout "project_settings"
def edit
end
def update
if ci_project.update_attributes(project_params)
Ci::EventService.new.change_project_settings(current_user, ci_project)
redirect_to edit_namespace_project_ci_settings_path(project.namespace, project), notice: 'Project was successfully updated.'
else
render action: "edit"
end
end
def destroy
ci_project.destroy
Ci::EventService.new.remove_project(current_user, ci_project)
project.gitlab_ci_service.update_attributes(active: false)
redirect_to project_path(project), notice: "CI was disabled for this project"
end
protected
def project_params
params.require(:project).permit(:path, :timeout, :timeout_in_minutes, :default_ref, :always_build,
:polling_interval, :public, :ssh_url_to_repo, :allow_git_fetch, :email_recipients,
:email_add_pusher, :email_only_broken_builds, :coverage_regex, :shared_runners_enabled, :token,
{ variables_attributes: [:id, :key, :value, :_destroy] })
end
end
......@@ -31,7 +31,6 @@ class Projects::CommitController < Projects::ApplicationController
end
def builds
@ci_project = @project.gitlab_ci_project
end
def cancel_builds
......
......@@ -25,13 +25,11 @@ class Projects::GraphsController < Projects::ApplicationController
end
def ci
ci_project = @project.gitlab_ci_project
@charts = {}
@charts[:week] = Ci::Charts::WeekChart.new(ci_project)
@charts[:month] = Ci::Charts::MonthChart.new(ci_project)
@charts[:year] = Ci::Charts::YearChart.new(ci_project)
@charts[:build_times] = Ci::Charts::BuildTime.new(ci_project)
@charts[:week] = Ci::Charts::WeekChart.new(project)
@charts[:month] = Ci::Charts::MonthChart.new(project)
@charts[:year] = Ci::Charts::YearChart.new(project)
@charts[:build_times] = Ci::Charts::BuildTime.new(project)
end
def languages
......
......@@ -81,8 +81,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def builds
@ci_project = @merge_request.source_project.gitlab_ci_project
respond_to do |format|
format.html { render 'show' }
format.json { render json: { html: view_to_html_string('projects/merge_requests/show/_builds') } }
......@@ -106,7 +104,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@first_commit = @merge_request.first_commit
@diffs = @merge_request.compare_diffs
@ci_project = @source_project.gitlab_ci_project
@ci_commit = @merge_request.ci_commit
@statuses = @ci_commit.statuses if @ci_commit
......
class Projects::RunnerProjectsController < Projects::ApplicationController
before_action :authorize_admin_project!
layout 'project_settings'
def create
@runner = Ci::Runner.find(params[:runner_project][:runner_id])
return head(403) unless current_user.ci_authorized_runners.include?(@runner)
path = runners_path(project)
if @runner.assign_to(project, current_user)
redirect_to path
else
redirect_to path, alert: 'Failed adding runner to project'
end
end
def destroy
runner_project = project.runner_projects.find(params[:id])
runner_project.destroy
redirect_to runners_path(project)
end
end
class Projects::RunnersController < Projects::ApplicationController
before_action :ci_project
before_action :set_runner, only: [:edit, :update, :destroy, :pause, :resume, :show]
before_action :authorize_admin_project!
layout 'project_settings'
def index
@runners = @ci_project.runners.ordered
@runners = project.runners.ordered
@specific_runners = current_user.ci_authorized_runners.
where.not(id: @ci_project.runners).
where.not(id: project.runners).
ordered.page(params[:page]).per(20)
@shared_runners = Ci::Runner.shared.active
@shared_runners_count = @shared_runners.count(:all)
......@@ -26,7 +25,7 @@ class Projects::RunnersController < Projects::ApplicationController
end
def destroy
if @runner.only_for?(@ci_project)
if @runner.only_for?(project)
@runner.destroy
end
......@@ -52,10 +51,16 @@ class Projects::RunnersController < Projects::ApplicationController
def show
end
def toggle_shared_runners
project.toggle!(:shared_runners_enabled)
redirect_to namespace_project_runners_path(project.namespace, project)
end
protected
def set_runner
@runner ||= @ci_project.runners.find(params[:id])
@runner ||= project.runners.find(params[:id])
end
def runner_params
......
class Projects::TriggersController < Projects::ApplicationController
before_action :ci_project
before_action :authorize_admin_project!
layout 'project_settings'
def index
@triggers = @ci_project.triggers
@triggers = project.triggers
@trigger = Ci::Trigger.new
end
def create
@trigger = @ci_project.triggers.new
@trigger = project.triggers.new
@trigger.save
if @trigger.valid?
redirect_to namespace_project_triggers_path(@project.namespace, @project)
else
@triggers = @ci_project.triggers.select(&:persisted?)
@triggers = project.triggers.select(&:persisted?)
render :index
end
end
......@@ -30,6 +29,6 @@ class Projects::TriggersController < Projects::ApplicationController
private
def trigger
@trigger ||= @ci_project.triggers.find(params[:id])
@trigger ||= project.triggers.find(params[:id])
end
end
class Projects::VariablesController < Projects::ApplicationController
before_action :ci_project
before_action :authorize_admin_project!
layout 'project_settings'
......@@ -8,9 +7,7 @@ class Projects::VariablesController < Projects::ApplicationController
end
def update
if ci_project.update_attributes(project_params)
Ci::EventService.new.change_project_settings(current_user, ci_project)
if project.update_attributes(project_params)
redirect_to namespace_project_variables_path(project.namespace, project), notice: 'Variables were successfully updated.'
else
render action: 'show'
......
......@@ -210,10 +210,10 @@ class ProjectsController < ApplicationController
def project_params
params.require(:project).permit(
:name, :path, :description, :issues_tracker, :tag_list,
:name, :path, :description, :issues_tracker, :tag_list, :runners_token,
:issues_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id, :default_branch,
:wiki_enabled, :visibility_level, :import_url, :last_activity_at, :namespace_id, :avatar,
:builds_enabled
:builds_enabled, :build_allow_git_fetch, :build_timeout_in_minutes, :build_coverage_regex,
)
end
......
module Ci
module GitlabHelper
def no_turbolink
{ :"data-no-turbolink" => "data-no-turbolink" }
end
def yaml_web_editor_link(project)
commits = project.commits
if commits.any? && commits.last.ci_yaml_file
"#{project.gitlab_url}/edit/master/.gitlab-ci.yml"
else
"#{project.gitlab_url}/new/master"
end
end
end
end
module Ci
module ProjectsHelper
def ref_tab_class ref = nil
'active' if ref == @ref
end
def success_ratio(success_builds, failed_builds)
failed_builds = failed_builds.count(:all)
success_builds = success_builds.count(:all)
return 100 if failed_builds.zero?
ratio = (success_builds.to_f / (success_builds + failed_builds)) * 100
ratio.to_i
end
def markdown_badge_code(project, ref)
url = status_ci_project_url(project, ref: ref, format: 'png')
"[![build status](#{url})](#{ci_project_url(project, ref: ref)})"
end
def html_badge_code(project, ref)
url = status_ci_project_url(project, ref: ref, format: 'png')
"<a href='#{ci_project_url(project, ref: ref)}'><img src='#{url}' /></a>"
end
def project_uses_specific_runner?(project)
project.runners.any?
end
def no_runners_for_project?(project)
project.runners.blank? &&
Ci::Runner.shared.blank?
end
end
end
module CiBadgeHelper
def markdown_badge_code(project, ref)
url = status_ci_project_url(project, ref: ref, format: 'png')
link = namespace_project_commits_path(project.namespace, project, ref)
"[![build status](#{url})](#{link})"
end
def html_badge_code(project, ref)
url = status_ci_project_url(project, ref: ref, format: 'png')
link = namespace_project_commits_path(project.namespace, project, ref)
"<a href='#{link}'><img src='#{url}' /></a>"
end
end
module CiStatusHelper
def ci_status_path(ci_commit)
project = ci_commit.gl_project
project = ci_commit.project
builds_namespace_project_commit_path(project.namespace, project, ci_commit.sha)
end
......@@ -63,4 +63,9 @@ module CiStatusHelper
ci_status_icon(ci_commit)
end
end
def no_runners_for_project?(project)
project.runners.blank? &&
Ci::Runner.shared.blank?
end
end
......@@ -16,4 +16,14 @@ module GraphHelper
ids = parents.map { |p| p.id }
ids.zip(parent_spaces)
end
def success_ratio(success_builds, failed_builds)
failed_builds = failed_builds.count(:all)
success_builds = success_builds.count(:all)
return 100 if failed_builds.zero?
ratio = (success_builds.to_f / (success_builds + failed_builds)) * 100
ratio.to_i
end
end
......@@ -19,7 +19,7 @@ module RunnersHelper
id = "\##{runner.id}"
if current_user && current_user.admin
link_to ci_admin_runner_path(runner) do
link_to admin_runner_path(runner) do
display_name + id
end
else
......
module TriggersHelper
def ci_build_trigger_url(project_id, ref_name)
"#{Settings.gitlab_ci.url}/ci/api/v1/projects/#{project_id}/refs/#{ref_name}/trigger"
def builds_trigger_url(project_id)
"#{Settings.gitlab.url}/api/v3/projects/#{project_id}/trigger/builds"
end
end
# == Schema Information
#
# Table name: ci_application_settings
#
# id :integer not null, primary key
# all_broken_builds :boolean
# add_pusher :boolean
# created_at :datetime
# updated_at :datetime
#
module Ci
class ApplicationSetting < ActiveRecord::Base
extend Ci::Model
CACHE_KEY = 'ci_application_setting.last'
after_commit do
Rails.cache.write(CACHE_KEY, self)
end
def self.expire
Rails.cache.delete(CACHE_KEY)
end
def self.current
Rails.cache.fetch(CACHE_KEY) do
Ci::ApplicationSetting.last
end
end
def self.create_from_defaults
create(
all_broken_builds: Settings.gitlab_ci['all_broken_builds'],
add_pusher: Settings.gitlab_ci['add_pusher'],
)
end
end
end
......@@ -84,6 +84,7 @@ module Ci
new_build.options = build.options
new_build.commands = build.commands
new_build.tag_list = build.tag_list
new_build.gl_project_id = build.gl_project_id
new_build.commit_id = build.commit_id
new_build.name = build.name
new_build.allow_failure = build.allow_failure
......@@ -101,14 +102,9 @@ module Ci
end
after_transition any => [:success, :failed, :canceled] do |build, transition|
return unless build.gl_project
return unless build.project
project = build.project
if project.coverage_enabled?
build.update_coverage
end
build.commit.create_next_builds(build)
build.execute_hooks
end
......@@ -119,7 +115,7 @@ module Ci
end
def retryable?
commands.present?
project.builds_enabled? && commands.present?
end
def retried?
......@@ -132,7 +128,7 @@ module Ci
end
def timeout
project.timeout
project.build_timeout
end
def variables
......@@ -151,26 +147,21 @@ module Ci
project.name
end
def project_recipients
recipients = project.email_recipients.split(' ')
if project.email_add_pusher? && user.present? && user.notification_email.present?
recipients << user.notification_email
end
recipients.uniq
end
def repo_url
project.repo_url_with_auth
auth = "gitlab-ci-token:#{token}@"
project.http_url_to_repo.sub(/^https?:\/\//) do |prefix|
prefix + auth
end
end
def allow_git_fetch
project.allow_git_fetch
project.build_allow_git_fetch
end
def update_coverage
coverage = extract_coverage(trace, project.coverage_regex)
coverage_regex = project.build_coverage_regex
return unless coverage_regex
coverage = extract_coverage(trace, coverage_regex)
if coverage.is_a? Numeric
update_attributes(coverage: coverage)
......@@ -203,7 +194,7 @@ module Ci
def trace
trace = raw_trace
if project && trace.present?
trace.gsub(project.token, 'xxxxxx')
trace.gsub(project.runners_token, 'xxxxxx')
else
trace
end
......@@ -230,29 +221,29 @@ module Ci
end
def token
project.token
project.runners_token
end
def valid_token? token
project.valid_token? token
project.valid_runners_token? token
end
def target_url
Gitlab::Application.routes.url_helpers.
namespace_project_build_url(gl_project.namespace, gl_project, self)
namespace_project_build_url(project.namespace, project, self)
end
def cancel_url
if active?
Gitlab::Application.routes.url_helpers.
cancel_namespace_project_build_path(gl_project.namespace, gl_project, self)
cancel_namespace_project_build_path(project.namespace, project, self)
end
end
def retry_url
if retryable?
Gitlab::Application.routes.url_helpers.
retry_namespace_project_build_path(gl_project.namespace, gl_project, self)
retry_namespace_project_build_path(project.namespace, project, self)
end
end
......@@ -271,16 +262,18 @@ module Ci
def download_url
if artifacts_file.exists?
Gitlab::Application.routes.url_helpers.
download_namespace_project_build_path(gl_project.namespace, gl_project, self)
download_namespace_project_build_path(project.namespace, project, self)
end
end
def execute_hooks
build_data = Gitlab::BuildDataBuilder.build(self)
gl_project.execute_hooks(build_data.dup, :build_hooks)
gl_project.execute_services(build_data.dup, :build_hooks)
project.execute_hooks(build_data.dup, :build_hooks)
project.execute_services(build_data.dup, :build_hooks)
end
private
def yaml_variables
......
......@@ -20,8 +20,8 @@ module Ci
class Commit < ActiveRecord::Base
extend Ci::Model
belongs_to :gl_project, class_name: '::Project', foreign_key: :gl_project_id
has_many :statuses, dependent: :destroy, class_name: 'CommitStatus'
belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id
has_many :statuses, class_name: 'CommitStatus'
has_many :builds, class_name: 'Ci::Build'
has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest'
......@@ -38,10 +38,6 @@ module Ci
sha
end
def project
@project ||= gl_project.ensure_gitlab_ci_project
end
def project_id
project.id
end
......@@ -57,7 +53,7 @@ module Ci
end
def valid_commit_sha
if self.sha == Ci::Git::BLANK_SHA
if self.sha == Gitlab::Git::BLANK_SHA
self.errors.add(:sha, " cant be 00000000 (branch removal)")
end
end
......@@ -79,7 +75,7 @@ module Ci
end
def commit_data
@commit ||= gl_project.commit(sha)
@commit ||= project.commit(sha)
rescue
nil
end
......@@ -187,13 +183,11 @@ module Ci
end
def coverage
if project.coverage_enabled?
coverage_array = latest_builds.map(&:coverage).compact
if coverage_array.size >= 1
'%.2f' % (coverage_array.reduce(:+) / coverage_array.size)
end
end
end
def matrix_for_ref?(ref)
latest_builds_for_ref(ref).size > 1
......@@ -201,7 +195,7 @@ module Ci
def config_processor
return nil unless ci_yaml_file
@config_processor ||= Ci::GitlabCiYamlProcessor.new(ci_yaml_file, gl_project.path_with_namespace)
@config_processor ||= Ci::GitlabCiYamlProcessor.new(ci_yaml_file, project.path_with_namespace)
rescue Ci::GitlabCiYamlProcessor::ValidationError, Psych::SyntaxError => e
save_yaml_error(e.message)
nil
......@@ -211,7 +205,7 @@ module Ci
end
def ci_yaml_file
@ci_yaml_file ||= gl_project.repository.blob_at(sha, '.gitlab-ci.yml').data
@ci_yaml_file ||= project.repository.blob_at(sha, '.gitlab-ci.yml').data
rescue
nil
end
......
# == Schema Information
#
# Table name: ci_events
#
# id :integer not null, primary key
# project_id :integer
# user_id :integer
# is_admin :integer
# description :text
# created_at :datetime
# updated_at :datetime
#
module Ci
class Event < ActiveRecord::Base
extend Ci::Model
belongs_to :project, class_name: 'Ci::Project'
validates :description,
presence: true,
length: { in: 5..200 }
scope :admin, ->(){ where(is_admin: true) }
scope :project_wide, ->(){ where(is_admin: false) }
end
end
# == Schema Information
#
# Table name: ci_projects
#
# id :integer not null, primary key
# name :string(255)
# timeout :integer default(3600), not null
# created_at :datetime
# updated_at :datetime
# token :string(255)
# default_ref :string(255)
# path :string(255)
# always_build :boolean default(FALSE), not null
# polling_interval :integer
# public :boolean default(FALSE), not null
# ssh_url_to_repo :string(255)
# gitlab_id :integer
# allow_git_fetch :boolean default(TRUE), not null
# email_recipients :string(255) default(""), not null
# email_add_pusher :boolean default(TRUE), not null
# email_only_broken_builds :boolean default(TRUE), not null
# skip_refs :string(255)
# coverage_regex :string(255)
# shared_runners_enabled :boolean default(FALSE)
# generated_yaml_config :text
#
module Ci
class Project < ActiveRecord::Base
extend Ci::Model
include Ci::ProjectStatus
belongs_to :gl_project, class_name: '::Project', foreign_key: :gitlab_id
has_many :runner_projects, dependent: :destroy, class_name: 'Ci::RunnerProject'
has_many :runners, through: :runner_projects, class_name: 'Ci::Runner'
has_many :events, dependent: :destroy, class_name: 'Ci::Event'
has_many :variables, dependent: :destroy, class_name: 'Ci::Variable'
has_many :triggers, dependent: :destroy, class_name: 'Ci::Trigger'
accepts_nested_attributes_for :variables, allow_destroy: true
delegate :name_with_namespace, :path_with_namespace, :web_url, :http_url_to_repo, :ssh_url_to_repo, to: :gl_project
#
# Validations
#
validates_presence_of :timeout, :token, :default_ref, :gitlab_id
validates_uniqueness_of :gitlab_id
validates :polling_interval,
presence: true,
if: ->(project) { project.always_build.present? }
before_validation :set_default_values
class << self
include Ci::CurrentSettings
def unassigned(runner)
joins("LEFT JOIN #{Ci::RunnerProject.table_name} ON #{Ci::RunnerProject.table_name}.project_id = #{Ci::Project.table_name}.id " \
"AND #{Ci::RunnerProject.table_name}.runner_id = #{runner.id}").
where("#{Ci::RunnerProject.table_name}.project_id" => nil)
end
def ordered_by_last_commit_date
last_commit_subquery = "(SELECT gl_project_id, MAX(committed_at) committed_at FROM #{Ci::Commit.table_name} GROUP BY gl_project_id)"
joins("LEFT JOIN #{last_commit_subquery} AS last_commit ON #{Ci::Project.table_name}.gitlab_id = last_commit.gl_project_id").
joins(:gl_project).
order("CASE WHEN last_commit.committed_at IS NULL THEN 1 ELSE 0 END, last_commit.committed_at DESC")
end
end
def name
name_with_namespace
end
def path
path_with_namespace
end
def gitlab_url
web_url
end
def any_runners?(&block)
if runners.active.any?(&block)
return true
end
shared_runners_enabled && Ci::Runner.shared.active.any?(&block)
end
def set_default_values
self.token = SecureRandom.hex(15) if self.token.blank?
self.default_ref ||= 'master'
end
def tracked_refs
@tracked_refs ||= default_ref.split(",").map { |ref| ref.strip }
end
def valid_token? token
self.token && self.token == token
end
def no_running_builds?
# Get running builds not later than 3 days ago to ignore hangs
builds.running.where("updated_at > ?", 3.days.ago).empty?
end
def email_notification?
email_add_pusher || email_recipients.present?
end
def timeout_in_minutes
timeout / 60
end
def timeout_in_minutes=(value)
self.timeout = value.to_i * 60
end
def coverage_enabled?
coverage_regex.present?
end
# Build a clone-able repo url
# using http and basic auth
def repo_url_with_auth
auth = "gitlab-ci-token:#{token}@"
http_url_to_repo.sub(/^https?:\/\//) do |prefix|
prefix + auth
end
end
def setup_finished?
commits.any?
end
def commits
gl_project.ci_commits.ordered
end
def builds
gl_project.ci_builds
end
end
end
module Ci
module ProjectStatus
def status
last_commit.status if last_commit
end
def broken?
last_commit.failed? if last_commit
end
def success?
last_commit.success? if last_commit
end
def broken_or_success?
broken? || success?
end
def last_commit
@last_commit ||= commits.last if commits.any?
end
def last_commit_date
last_commit.try(:created_at)
end
def human_status
status
end
end
end
......@@ -25,7 +25,7 @@ module Ci
has_many :builds, class_name: 'Ci::Build'
has_many :runner_projects, dependent: :destroy, class_name: 'Ci::RunnerProject'
has_many :projects, through: :runner_projects, class_name: 'Ci::Project'
has_many :projects, through: :runner_projects, class_name: '::Project', foreign_key: :gl_project_id
has_one :last_build, ->() { order('id DESC') }, class_name: 'Ci::Build'
......@@ -45,10 +45,6 @@ module Ci
query: "%#{query.try(:downcase)}%")
end
def gl_projects_ids
projects.select(:gitlab_id)
end
def set_default_values
self.token = SecureRandom.hex(15) if self.token.blank?
end
......
......@@ -14,8 +14,8 @@ module Ci
extend Ci::Model
belongs_to :runner, class_name: 'Ci::Runner'
belongs_to :project, class_name: 'Ci::Project'
belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id
validates_uniqueness_of :runner_id, scope: :project_id
validates_uniqueness_of :runner_id, scope: :gl_project_id
end
end
......@@ -16,7 +16,7 @@ module Ci
acts_as_paranoid
belongs_to :project, class_name: 'Ci::Project'
belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id
has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest'
validates_presence_of :token
......
......@@ -15,10 +15,10 @@ module Ci
class Variable < ActiveRecord::Base
extend Ci::Model
belongs_to :project, class_name: 'Ci::Project'
belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id
validates_presence_of :key
validates_uniqueness_of :key, scope: :project_id
validates_uniqueness_of :key, scope: :gl_project_id
attr_encrypted :value, mode: :per_attribute_iv_and_salt, key: Gitlab::Application.secrets.db_key_base
end
......
......@@ -30,6 +30,7 @@
class CommitStatus < ActiveRecord::Base
self.table_name = 'ci_builds'
belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id
belongs_to :commit, class_name: 'Ci::Commit'
belongs_to :user
......@@ -76,7 +77,7 @@ class CommitStatus < ActiveRecord::Base
end
after_transition [:pending, :running] => :success do |build, transition|
MergeRequests::MergeWhenBuildSucceedsService.new(build.commit.gl_project, nil).trigger(build)
MergeRequests::MergeWhenBuildSucceedsService.new(build.commit.project, nil).trigger(build)
end
state :pending, value: 'pending'
......@@ -86,8 +87,7 @@ class CommitStatus < ActiveRecord::Base
state :canceled, value: 'canceled'
end
delegate :sha, :short_sha, :gl_project,
to: :commit, prefix: false
delegate :sha, :short_sha, to: :commit, prefix: false
# TODO: this should be removed with all references
def before_sha
......
......@@ -56,6 +56,7 @@ class Project < ActiveRecord::Base
default_value_for :wiki_enabled, gitlab_config_features.wiki
default_value_for :wall_enabled, false
default_value_for :snippets_enabled, gitlab_config_features.snippets
default_value_for(:shared_runners_enabled) { current_application_settings.shared_runners_enabled }
# set last_activity_at to the same as created_at
after_create :set_last_activity_at
......@@ -77,7 +78,6 @@ class Project < ActiveRecord::Base
# Project services
has_many :services
has_one :gitlab_ci_service, dependent: :destroy
has_one :campfire_service, dependent: :destroy
has_one :drone_ci_service, dependent: :destroy
has_one :emails_on_push_service, dependent: :destroy
......@@ -122,14 +122,21 @@ class Project < ActiveRecord::Base
has_many :deploy_keys, through: :deploy_keys_projects
has_many :users_star_projects, dependent: :destroy
has_many :starrers, through: :users_star_projects, source: :user
has_many :ci_commits, dependent: :destroy, class_name: 'Ci::Commit', foreign_key: :gl_project_id
has_many :ci_builds, through: :ci_commits, source: :builds, dependent: :destroy, class_name: 'Ci::Build'
has_many :releases, dependent: :destroy
has_many :lfs_objects_projects, dependent: :destroy
has_many :lfs_objects, through: :lfs_objects_projects
has_one :import_data, dependent: :destroy, class_name: "ProjectImportData"
has_one :gitlab_ci_project, dependent: :destroy, class_name: "Ci::Project", foreign_key: :gitlab_id
has_many :commit_statuses, dependent: :destroy, class_name: 'CommitStatus', foreign_key: :gl_project_id
has_many :ci_commits, dependent: :destroy, class_name: 'Ci::Commit', foreign_key: :gl_project_id
has_many :builds, class_name: 'Ci::Build', foreign_key: :gl_project_id # the builds are created from the commit_statuses
has_many :runner_projects, dependent: :destroy, class_name: 'Ci::RunnerProject', foreign_key: :gl_project_id
has_many :runners, through: :runner_projects, source: :runner, class_name: 'Ci::Runner'
has_many :variables, dependent: :destroy, class_name: 'Ci::Variable', foreign_key: :gl_project_id
has_many :triggers, dependent: :destroy, class_name: 'Ci::Trigger', foreign_key: :gl_project_id
accepts_nested_attributes_for :variables, allow_destroy: true
delegate :name, to: :owner, allow_nil: true, prefix: true
delegate :members, to: :team, prefix: true
......@@ -162,6 +169,11 @@ class Project < ActiveRecord::Base
if: ->(project) { project.avatar.present? && project.avatar_changed? }
validates :avatar, file_size: { maximum: 200.kilobytes.to_i }
before_validation :set_runners_token_token
def set_runners_token_token
self.runners_token = SecureRandom.hex(15) if self.runners_token.blank?
end
mount_uploader :avatar, AvatarUploader
# Scopes
......@@ -257,6 +269,10 @@ class Project < ActiveRecord::Base
projects.iwhere('projects.path' => project_path).take
end
def find_by_ci_id(id)
find_by(ci_id: id.to_i)
end
def visibility_levels
Gitlab::VisibilityLevel.options
end
......@@ -791,39 +807,47 @@ class Project < ActiveRecord::Base
ci_commit(sha) || ci_commits.create(sha: sha)
end
def ensure_gitlab_ci_project
gitlab_ci_project || create_gitlab_ci_project(
shared_runners_enabled: current_application_settings.shared_runners_enabled
)
def enable_ci
self.builds_enabled = true
end
def unlink_fork
if forked?
forked_from_project.lfs_objects.find_each do |lfs_object|
lfs_object.projects << self
end
forked_project_link.destroy
end
end
# TODO: this should be migrated to Project table,
# the same as issues_enabled
def builds_enabled
gitlab_ci_service && gitlab_ci_service.active
def any_runners?(&block)
if runners.active.any?(&block)
return true
end
def builds_enabled?
builds_enabled
shared_runners_enabled? && Ci::Runner.shared.active.any?(&block)
end
def builds_enabled=(value)
service = gitlab_ci_service || create_gitlab_ci_service
service.active = value
service.save
def valid_runners_token? token
self.runners_token && self.runners_token == token
end
def enable_ci
self.builds_enabled = true
# TODO (ayufan): For now we use runners_token (backward compatibility)
# In 8.4 every build will have its own individual token valid for time of build
def valid_build_token? token
self.builds_enabled? && self.runners_token && self.runners_token == token
end
def unlink_fork
if forked?
forked_from_project.lfs_objects.find_each do |lfs_object|
lfs_object.projects << self
def build_coverage_enabled?
build_coverage_regex.present?
end
forked_project_link.destroy
def build_timeout_in_minutes
build_timeout / 60
end
def build_timeout_in_minutes=(value)
self.build_timeout = value.to_i * 60
end
end
......@@ -19,76 +19,5 @@
#
class GitlabCiService < CiService
include Gitlab::Application.routes.url_helpers
after_save :compose_service_hook, if: :activated?
after_save :ensure_gitlab_ci_project, if: :activated?
def compose_service_hook
hook = service_hook || build_service_hook
hook.save
end
def ensure_gitlab_ci_project
return unless project
project.ensure_gitlab_ci_project
end
def supported_events
%w(push tag_push)
end
def execute(data)
return unless supported_events.include?(data[:object_kind])
ci_project = project.gitlab_ci_project
if ci_project
current_user = User.find_by(id: data[:user_id])
Ci::CreateCommitService.new.execute(ci_project, current_user, data)
end
end
def token
if project.gitlab_ci_project.present?
project.gitlab_ci_project.token
end
end
def get_ci_commit(sha, ref)
Ci::Project.find(project.gitlab_ci_project.id).commits.find_by_sha!(sha)
end
def commit_status(sha, ref)
get_ci_commit(sha, ref).status
rescue ActiveRecord::RecordNotFound
:error
end
def commit_coverage(sha, ref)
get_ci_commit(sha, ref).coverage
rescue ActiveRecord::RecordNotFound
:error
end
def build_page(sha, ref)
if project.gitlab_ci_project.present?
builds_namespace_project_commit_url(project.namespace, project, sha)
end
end
def title
'GitLab CI'
end
def description
'Continuous integration server from GitLab'
end
def to_param
'gitlab_ci'
end
def fields
[]
end
# this is no longer used
end
......@@ -41,7 +41,7 @@ class Service < ActiveRecord::Base
validates :project_id, presence: true, unless: Proc.new { |service| service.template? }
scope :visible, -> { where.not(type: 'GitlabIssueTrackerService') }
scope :visible, -> { where.not(type: ['GitlabIssueTrackerService', 'GitlabCiService']) }
scope :push_hooks, -> { where(push_events: true, active: true) }
scope :tag_push_hooks, -> { where(tag_push_events: true, active: true) }
......@@ -188,7 +188,6 @@ class Service < ActiveRecord::Base
external_wiki
flowdock
gemnasium
gitlab_ci
hipchat
irker
jira
......
......@@ -134,7 +134,7 @@ class User < ActiveRecord::Base
has_many :assigned_merge_requests, dependent: :destroy, foreign_key: :assignee_id, class_name: "MergeRequest"
has_many :oauth_applications, class_name: 'Doorkeeper::Application', as: :owner, dependent: :destroy
has_one :abuse_report, dependent: :destroy
has_many :ci_builds, dependent: :nullify, class_name: 'Ci::Build'
has_many :builds, dependent: :nullify, class_name: 'Ci::Build'
#
......@@ -769,10 +769,9 @@ class User < ActiveRecord::Base
def ci_authorized_runners
@ci_authorized_runners ||= begin
runner_ids = Ci::RunnerProject.joins(:project).
where("ci_projects.gitlab_id IN (#{ci_projects_union.to_sql})").
runner_ids = Ci::RunnerProject.
where("ci_runner_projects.gl_project_id IN (#{ci_projects_union.to_sql})").
select(:runner_id)
Ci::Runner.specific.where(id: runner_ids)
end
end
......
......@@ -29,7 +29,8 @@ module Ci
build_attrs.merge!(ref: ref,
tag: tag,
trigger_request: trigger_request,
user: user)
user: user,
project: commit.project)
build = commit.builds.create!(build_attrs)
build.execute_hooks
......
module Ci
class CreateCommitService
def execute(project, user, params)
sha = params[:checkout_sha] || params[:after]
origin_ref = params[:ref]
unless origin_ref && sha.present?
return false
end
ref = origin_ref.gsub(/\Arefs\/(tags|heads)\//, '')
# Skip branch removal
if sha == Ci::Git::BLANK_SHA
return false
end
tag = origin_ref.start_with?('refs/tags/')
commit = project.gl_project.ensure_ci_commit(sha)
unless commit.skip_ci?
commit.update_committed!
commit.create_builds(ref, tag, user)
end
commit
end
end
end
module Ci
class CreateTriggerRequestService
def execute(project, trigger, ref, variables = nil)
commit = project.gl_project.commit(ref)
commit = project.commit(ref)
return unless commit
# check if ref is tag
tag = project.gl_project.repository.find_tag(ref).present?
tag = project.repository.find_tag(ref).present?
ci_commit = project.gl_project.ensure_ci_commit(commit.sha)
ci_commit = project.ensure_ci_commit(commit.sha)
trigger_request = trigger.trigger_requests.create!(
variables: variables,
......
module Ci
class EventService
def remove_project(user, project)
create(
description: "Project \"#{project.name}\" has been removed by #{user.username}",
user_id: user.id,
is_admin: true
)
end
def create_project(user, project)
create(
description: "Project \"#{project.name}\" has been created by #{user.username}",
user_id: user.id,
is_admin: true
)
end
def change_project_settings(user, project)
create(
project_id: project.id,
user_id: user.id,
description: "User \"#{user.username}\" updated projects settings"
)
end
def create(*args)
Ci::Event.create!(*args)
end
end
end
......@@ -4,10 +4,10 @@ module Ci
sha = params[:sha]
sha ||=
if params[:ref]
project.gl_project.commit(params[:ref]).try(:sha)
project.commit(params[:ref]).try(:sha)
end
commit = project.commits.ordered.find_by(sha: sha)
commit = project.ci_commits.ordered.find_by(sha: sha)
image_name = image_for_commit(commit)
image_path = Rails.root.join('public/ci', image_name)
......
......@@ -8,10 +8,10 @@ module Ci
builds =
if current_runner.shared?
# don't run projects which have not enables shared runners
builds.joins(commit: { gl_project: :gitlab_ci_project }).where(ci_projects: { shared_runners_enabled: true })
builds.joins(:project).where(projects: { builds_enabled: true, shared_runners_enabled: true })
else
# do run projects which are only assigned to this runner
builds.joins(:commit).where(ci_commits: { gl_project_id: current_runner.gl_projects_ids })
builds.where(project: current_runner.projects.where(builds_enabled: true))
end
builds = builds.order('created_at ASC')
......@@ -20,10 +20,9 @@ module Ci
build.can_be_served?(current_runner)
end
if build
# In case when 2 runners try to assign the same build, second runner will be declined
# with StateMachine::InvalidTransition in run! method.
# with StateMachines::InvalidTransition in run! method.
build.with_lock do
build.runner_id = current_runner.id
build.save!
......@@ -33,7 +32,7 @@ module Ci
build
rescue StateMachine::InvalidTransition
rescue StateMachines::InvalidTransition
nil
end
end
......
module Ci
class TestHookService
def execute(hook, current_user)
Ci::WebHookService.new.build_end(hook.project.commits.last.last_build)
end
end
end
class CreateCommitBuildsService
def execute(project, user, params)
return false unless project.builds_enabled?
sha = params[:checkout_sha] || params[:after]
origin_ref = params[:ref]
unless origin_ref && sha.present?
return false
end
ref = Gitlab::Git.ref_name(origin_ref)
# Skip branch removal
if sha == Gitlab::Git::BLANK_SHA
return false
end
tag = Gitlab::Git.tag_ref?(origin_ref)
commit = project.ensure_ci_commit(sha)
unless commit.skip_ci?
commit.update_committed!
commit.create_builds(ref, tag, user)
end
commit
end
end
......@@ -61,6 +61,7 @@ class GitPushService
EventCreateService.new.push(project, user, @push_data)
project.execute_hooks(@push_data.dup, :push_hooks)
project.execute_services(@push_data.dup, :push_hooks)
CreateCommitBuildsService.new.execute(project, @user, @push_data)
ProjectCacheWorker.perform_async(project.id)
end
......
......@@ -10,6 +10,7 @@ class GitTagPushService
EventCreateService.new.push(project, user, @push_data)
project.execute_hooks(@push_data.dup, :tag_push_hooks)
project.execute_services(@push_data.dup, :tag_push_hooks)
CreateCommitBuildsService.new.execute(project, @user, @push_data)
ProjectCacheWorker.perform_async(project.id)
true
......
......@@ -7,6 +7,8 @@ module Projects
description: @project.description,
name: @project.name,
path: @project.path,
shared_runners_enabled: @project.shared_runners_enabled,
builds_enabled: @project.builds_enabled,
namespace_id: @params[:namespace].try(:id) || current_user.namespace.id
}
......@@ -15,19 +17,6 @@ module Projects
end
new_project = CreateService.new(current_user, new_params).execute
if new_project.persisted?
if @project.builds_enabled?
new_project.enable_ci
settings = @project.gitlab_ci_project.attributes.select do |attr_name, value|
["public", "shared_runners_enabled", "allow_git_fetch"].include? attr_name
end
new_project.gitlab_ci_project.update(settings)
end
end
new_project
end
end
......
- project = build.project
%tr.build
%td.status
= ci_status_with_icon(build.status)
%td.build-link
- if build.target_url
= link_to build.target_url do
%strong Build ##{build.id}
- else
%strong Build ##{build.id}
- if build.show_warning?
%i.fa.fa-warning.text-warning
%td
- if project
= link_to project.name_with_namespace, admin_namespace_project_path(project.namespace, project), class: "monospace"
%td
= link_to build.short_sha, namespace_project_commit_path(project.namespace, project, build.sha), class: "monospace"
%td
- if build.ref
= link_to build.ref, namespace_project_commits_path(project.namespace, project, build.ref)
- else
.light none
%td
- if build.try(:runner)
= runner_link(build.runner)
- else
.light none
%td
#{build.stage} / #{build.name}
.pull-right
- if build.tags.any?
- build.tags.each do |tag|
%span.label.label-primary
= tag
- if build.try(:trigger_request)
%span.label.label-info triggered
- if build.try(:allow_failure)
%span.label.label-danger allowed to fail
%td.duration
- if build.duration
#{duration_in_words(build.finished_at, build.started_at)}
%td.timestamp
- if build.finished_at
%span #{time_ago_with_tooltip(build.finished_at)}
- if defined?(coverage) && coverage
%td.coverage
- if build.try(:coverage)
#{build.coverage}%
%td
.pull-right
- if current_user && can?(current_user, :download_build_artifacts, project) && build.download_url
= link_to build.download_url, title: 'Download artifacts' do
%i.fa.fa-download
- if current_user && can?(current_user, :manage_builds, build.project)
- if build.active?
- if build.cancel_url
= link_to build.cancel_url, method: :post, title: 'Cancel' do
%i.fa.fa-remove.cred
- elsif defined?(allow_retry) && allow_retry && build.retry_url
= link_to build.retry_url, method: :post, title: 'Retry' do
%i.fa.fa-repeat
.project-issuable-filter
.controls
.pull-left.hidden-xs
- if @all_builds.running_or_pending.any?
= link_to 'Cancel all', cancel_all_admin_builds_path, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post
%ul.center-top-menu
%li{class: ('active' if @scope.nil?)}
= link_to admin_builds_path do
Running
%span.badge.js-running-count= @all_builds.running_or_pending.count(:id)
%li{class: ('active' if @scope == 'finished')}
= link_to admin_builds_path(scope: :finished) do
Finished
%span.badge.js-running-count= @all_builds.finished.count(:id)
%li{class: ('active' if @scope == 'all')}
= link_to admin_builds_path(scope: :all) do
All
%span.badge.js-totalbuilds-count= @all_builds.count(:id)
.gray-content-block
#{(@scope || 'running').capitalize} builds
%ul.content-list
- if @builds.blank?
%li
.nothing-here-block No builds to show
- else
.table-holder
%table.table.builds
%thead
%tr
%th Status
%th Build ID
%th Project
%th Commit
%th Ref
%th Runner
%th Name
%th Duration
%th Finished at
%th
- @builds.each do |build|
= render "admin/builds/build", build: build
= paginate @builds, theme: 'gitlab'
......@@ -8,14 +8,14 @@
%span.label.label-danger paused
%td
= link_to ci_admin_runner_path(runner) do
= link_to admin_runner_path(runner) do
= runner.short_sha
%td
.runner-description
= runner.description
%span (#{link_to 'edit', '#', class: 'edit-runner-link'})
.runner-description-form.hide
= form_for [:ci, :admin, runner], remote: true, html: { class: 'form-inline' } do |f|
= form_for [:admin, runner], remote: true, html: { class: 'form-inline' } do |f|
.form-group
= f.text_field :description, class: 'form-control'
= f.submit 'Save', class: 'btn'
......@@ -38,11 +38,11 @@
Never
%td
.pull-right
= link_to 'Edit', ci_admin_runner_path(runner), class: 'btn btn-sm'
= link_to 'Edit', admin_runner_path(runner), class: 'btn btn-sm'
&nbsp;
- if runner.active?
= link_to 'Pause', [:pause, :ci, :admin, runner], data: { confirm: "Are you sure?" }, method: :get, class: 'btn btn-danger btn-sm'
= link_to 'Pause', [:pause, :admin, runner], data: { confirm: "Are you sure?" }, method: :get, class: 'btn btn-danger btn-sm'
- else
= link_to 'Resume', [:resume, :ci, :admin, runner], method: :get, class: 'btn btn-success btn-sm'
= link_to 'Remove', [:ci, :admin, runner], data: { confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger btn-sm'
= link_to 'Resume', [:resume, :admin, runner], method: :get, class: 'btn btn-success btn-sm'
= link_to 'Remove', [:admin, runner], data: { confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger btn-sm'
......@@ -25,7 +25,7 @@
.append-bottom-20.clearfix
.pull-left
= form_tag ci_admin_runners_path, id: 'runners-search', class: 'form-inline', method: :get do
= form_tag admin_runners_path, id: 'runners-search', class: 'form-inline', method: :get do
.form-group
= search_field_tag :search, params[:search], class: 'form-control', placeholder: 'Runner description or token', spellcheck: false
= submit_tag 'Search', class: 'btn'
......@@ -49,5 +49,5 @@
%th
- @runners.each do |runner|
= render "ci/admin/runners/runner", runner: runner
= render "admin/runners/runner", runner: runner
= paginate @runners
......@@ -22,7 +22,7 @@
%h4 This runner will process builds only from ASSIGNED projects
%p You can't make this a shared runner.
%hr
= form_for @runner, url: ci_admin_runner_path(@runner), html: { class: 'form-horizontal' } do |f|
= form_for @runner, url: admin_runner_path(@runner), html: { class: 'form-horizontal' } do |f|
.form-group
= label_tag :token, class: 'control-label' do
Token
......@@ -53,29 +53,24 @@
%th
- @runner.runner_projects.each do |runner_project|
- project = runner_project.project
- if project.gl_project
- if project
%tr.alert-info
%td
%strong
= project.name
= project.name_with_namespace
%td
.pull-right
= link_to 'Disable', [:ci, :admin, project, runner_project], method: :delete, class: 'btn btn-danger btn-xs'
= link_to 'Disable', [:admin, project.namespace, project, runner_project], method: :delete, class: 'btn btn-danger btn-xs'
%table.table
%thead
%tr
%th Project
%th
.pull-right
= link_to 'Assign to all', assign_all_ci_admin_runner_path(@runner),
class: 'btn btn-sm assign-all-runner',
title: 'Assign runner to all projects',
method: :put
%tr
%td
= form_tag ci_admin_runner_path(@runner), id: 'runner-projects-search', class: 'form-inline', method: :get do
= form_tag admin_runner_path(@runner), id: 'runner-projects-search', class: 'form-inline', method: :get do
.form-group
= search_field_tag :search, params[:search], class: 'form-control', spellcheck: false
= submit_tag 'Search', class: 'btn'
......@@ -84,44 +79,44 @@
- @projects.each do |project|
%tr
%td
= project.name
= project.name_with_namespace
%td
.pull-right
= form_for [:ci, :admin, project, project.runner_projects.new] do |f|
= form_for [:admin, project.namespace.becomes(Namespace), project, project.runner_projects.new] do |f|
= f.hidden_field :runner_id, value: @runner.id
= f.submit 'Enable', class: 'btn btn-xs'
= paginate @projects
.col-md-6
%h4 Recent builds served by this runner
%table.builds.runner-builds
%table.table.builds.runner-builds
%thead
%tr
%th Build ID
%th Build
%th Status
%th Project
%th Commit
%th Finished at
- @builds.each do |build|
- gl_project = build.gl_project
- project = build.project
%tr.build
%td.id
- if gl_project
= link_to namespace_project_build_path(gl_project.namespace, gl_project, build) do
= build.id
- if project
= link_to namespace_project_build_path(project.namespace, project, build) do
%strong ##{build.id}
- else
= build.id
%strong ##{build.id}
%td.status
= ci_status_with_icon(build.status)
%td.status
- if gl_project
= gl_project.name_with_namespace
- if project
= project.name_with_namespace
%td.build-link
- if gl_project
- if project
= link_to ci_status_path(build.commit) do
%strong #{build.commit.short_sha}
......
= form_for @application_setting, url: ci_admin_application_settings_path, html: { class: 'form-horizontal fieldset-form' } do |f|
- if @application_setting.errors.any?
#error_explanation
.alert.alert-danger
- @application_setting.errors.full_messages.each do |msg|
%p= msg
%fieldset
%legend Default Project Settings
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :all_broken_builds do
= f.check_box :all_broken_builds
Send emails only on broken builds
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :add_pusher do
= f.check_box :add_pusher
Add pusher to recipients list
.form-actions
= f.submit 'Save', class: 'btn btn-primary'
%h3.page-title Settings
%hr
= render 'form'
- gl_project = build.project.gl_project
- if build.commit && build.project
%tr.build
%td.build-link
= link_to namespace_project_build_path(gl_project.namespace, gl_project, build) do
%strong #{build.id}
%td.status
= ci_status_with_icon(build.status)
%td.commit-link
= link_to ci_status_path(build.commit) do
%strong #{build.commit.short_sha}
%td.runner
- if build.runner
= link_to build.runner.id, ci_admin_runner_path(build.runner)
%td.build-project
= truncate build.project.name, length: 30
%td.build-message
%span= truncate(build.commit.git_commit_message, length: 30)
%td.build-branch
%span= truncate(build.ref, length: 25)
%td.duration
- if build.duration
#{duration_in_words(build.finished_at, build.started_at)}
%td.timestamp
- if build.finished_at
%span #{time_ago_in_words build.finished_at} ago
%ul.nav.nav-tabs.append-bottom-20
%li{class: ("active" if @scope.nil?)}
= link_to 'All builds', ci_admin_builds_path
%li{class: ("active" if @scope == "pending")}
= link_to "Pending", ci_admin_builds_path(scope: :pending)
%li{class: ("active" if @scope == "running")}
= link_to "Running", ci_admin_builds_path(scope: :running)
%table.builds
%thead
%tr
%th Build
%th Status
%th Commit
%th Runner
%th Project
%th Message
%th Branch
%th Duration
%th Finished at
- @builds.each do |build|
= render "ci/admin/builds/build", build: build
= paginate @builds
.table-holder
%table.table
%thead
%tr
%th User ID
%th Description
%th When
- @events.each do |event|
%tr
%td
= event.user_id
%td
= event.description
%td.light
= time_ago_in_words event.updated_at
ago
= paginate @events
- last_commit = project.commits.last
%tr
%td
= project.id
%td
= link_to [:ci, project] do
%strong= project.name
%td
- if last_commit
= ci_status_with_icon(last_commit.status)
- if project.last_commit_date
&middot;
= time_ago_in_words project.last_commit_date
ago
- else
No builds yet
%td
- if project.public
%i.fa.fa-globe
Public
- else
%i.fa.fa-lock
Private
%td
= project.commits.count
%td
= link_to [:ci, :admin, project], method: :delete, class: 'btn btn-danger btn-sm' do
%i.fa.fa-remove
Remove
.table-holder
%table.table
%thead
%tr
%th ID
%th Name
%th Last build
%th Access
%th Builds
%th
- @projects.each do |project|
= render "ci/admin/projects/project", project: project
= paginate @projects
%p.lead
To register a new runner visit #{link_to 'this page ', ci_runners_path}
.row
.col-md-8
%h5 Activated:
%table.table
%tr
%th Runner ID
%th Runner Description
%th Last build
%th Builds Stats
%th Registered
%th
- @runner_projects.each do |runner_project|
- runner = runner_project.runner
- builds = runner.builds.where(project_id: @project.id)
%tr
%td
%span.badge.badge-info= runner.id
%td
= runner.display_name
%td
- last_build = builds.last
- if last_build
= link_to last_build.short_sha, [last_build.project, last_build]
- else
unknown
%td
%span.badge.badge-success
#{builds.success.count}
%span /
%span.badge.badge-important
#{builds.failed.count}
%td
#{time_ago_in_words(runner_project.created_at)} ago
%td
= link_to 'Disable', [:ci, @project, runner_project], data: { confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger btn-sm right'
.col-md-4
%h5 Available
%table.table
%tr
%th ID
%th Token
%th
- (Ci::Runner.all - @project.runners).each do |runner|
%tr
%td
= runner.id
%td
= runner.token
%td
= form_for [:ci, @project, @runner_project] do |f|
= f.hidden_field :runner_id, value: runner.id
= f.submit 'Add', class: 'btn btn-sm'
......@@ -27,7 +27,6 @@
- if commit.finished_at
%span #{time_ago_in_words commit.finished_at} ago
- if commit.project.coverage_enabled?
%td.coverage
- if commit.coverage
%td.coverage
#{commit.coverage}%
......@@ -4,12 +4,10 @@
%ol
%li
Add at least one runner to the project.
Go to #{link_to 'Runners page', runners_path(@project.gl_project), target: :blank} for instructions.
Go to #{link_to 'Runners page', runners_path(@project), target: :blank} for instructions.
%li
Put the .gitlab-ci.yml in the root of your repository. Examples can be found in #{link_to "Configuring project (.gitlab-ci.yml)", "http://doc.gitlab.com/ci/yaml/README.html", target: :blank}.
Put the .gitlab-ci.yml in the root of your repository. Examples can be found in
#{link_to "Configuring project (.gitlab-ci.yml)", "http://doc.gitlab.com/ci/yaml/README.html", target: :blank}.
You can also test your .gitlab-ci.yml in the #{link_to "Lint", ci_lint_path}
%li
Visit #{link_to 'GitLab project settings', @project.gitlab_url + "/services/gitlab_ci/edit", target: :blank}
and press the "Test settings" button.
%li
Return to this page and refresh it, it should show a new build.
.login-block
%h2 Login using GitLab account
%p.light
Make sure you have an account on the GitLab server
= link_to GitlabCi.config.gitlab_server.url, GitlabCi.config.gitlab_server.url, no_turbolink
%hr
= link_to "Login with GitLab", auth_ci_user_sessions_path(state: params[:state]), no_turbolink.merge( class: 'btn btn-login btn-success' )
%ul.nav.nav-sidebar
= nav_link do
= link_to admin_root_path, title: 'Back to admin', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw')
%span
Back to admin
%li.separate-item
= nav_link path: 'projects#index' do
= link_to ci_admin_projects_path do
= icon('list-alt fw')
%span
Projects
= nav_link path: 'events#index' do
= link_to ci_admin_events_path do
= icon('book fw')
%span
Events
= nav_link path: ['runners#index', 'runners#show'] do
= link_to ci_admin_runners_path do
= icon('cog fw')
%span
Runners
%span.count= Ci::Runner.count(:all)
= nav_link path: 'builds#index' do
= link_to ci_admin_builds_path do
= icon('link fw')
%span
Builds
%span.count= Ci::Build.count(:all)
= nav_link(controller: :application_settings, html_options: { class: 'separate-item'}) do
= link_to ci_admin_application_settings_path do
= icon('cogs fw')
%span
Settings
%ul.nav.nav-sidebar
= nav_link do
= link_to project_path(@project.gl_project), title: 'Back to project', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw')
%span
Back to project
%li.separate-item
= nav_link path: 'events#index' do
= link_to ci_project_events_path(@project) do
= icon('book fw')
%span
Events
!!! 5
%html{ lang: "en"}
= render 'layouts/head'
%body{class: "ci-body #{user_application_theme}", 'data-page' => body_data_page}
- header_title = "Admin area"
- if current_user
= render "layouts/header/default", title: header_title
- else
= render "layouts/header/public", title: header_title
= render 'layouts/ci/page', sidebar: 'nav_admin'
!!! 5
%html{ lang: "en"}
= render 'layouts/head'
%body{class: "ci-body #{user_application_theme}", 'data-page' => body_data_page}
- header_title = "Continuous Integration"
- if current_user
= render "layouts/header/default", title: header_title
- else
= render "layouts/header/public", title: header_title
= render 'layouts/ci/page'
......@@ -24,11 +24,18 @@
= icon('key fw')
%span
Deploy Keys
= nav_link do
= link_to ci_admin_projects_path, title: 'Continuous Integration' do
= icon('building fw')
= nav_link path: ['runners#index', 'runners#show'] do
= link_to admin_runners_path do
= icon('cog fw')
%span
Runners
%span.count= Ci::Runner.count(:all)
= nav_link path: 'builds#index' do
= link_to admin_builds_path do
= icon('link fw')
%span
Continuous Integration
Builds
%span.count= Ci::Build.count(:all)
= nav_link(controller: :logs) do
= link_to admin_logs_path, title: 'Logs' do
= icon('file-text fw')
......
......@@ -44,7 +44,7 @@
= icon('cubes fw')
%span
Builds
%span.count.builds_counter= @project.ci_builds.running_or_pending.count(:all)
%span.count.builds_counter= @project.builds.running_or_pending.count(:all)
- if project_nav_tab? :graphs
= nav_link(controller: %w(graphs)) do
......
......@@ -50,8 +50,3 @@
= icon('retweet fw')
%span
Triggers
= nav_link path: 'ci_settings#edit' do
= link_to edit_namespace_project_ci_settings_path(@project.namespace, @project), title: 'CI Settings' do
= icon('building fw')
%span
CI Settings
......@@ -7,7 +7,7 @@
= @project.name
%p
Commit: #{link_to @build.short_sha, namespace_project_commit_url(@build.gl_project.namespace, @build.gl_project, @build.sha)}
Commit: #{link_to @build.short_sha, namespace_project_commit_url(@build.project.namespace, @build.project, @build.sha)}
%p
Author: #{@build.commit.git_author_name}
%p
......@@ -20,4 +20,4 @@
Message: #{@build.commit.git_commit_message}
%p
Build details: #{link_to "Build #{@build.id}", namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build)}
Build details: #{link_to "Build #{@build.id}", namespace_project_build_url(@build.project.namespace, @build.project, @build)}
......@@ -8,4 +8,4 @@ Stage: <%= @build.stage %>
Job: <%= @build.name %>
Message: <%= @build.commit.git_commit_message %>
Url: <%= namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build) %>
Url: <%= namespace_project_build_url(@build.project.namespace, @build.project, @build) %>
......@@ -8,7 +8,7 @@
= @project.name
%p
Commit: #{link_to @build.short_sha, namespace_project_commit_url(@build.gl_project.namespace, @build.gl_project, @build.sha)}
Commit: #{link_to @build.short_sha, namespace_project_commit_url(@build.project.namespace, @build.project, @build.sha)}
%p
Author: #{@build.commit.git_author_name}
%p
......@@ -21,4 +21,4 @@
Message: #{@build.commit.git_commit_message}
%p
Build details: #{link_to "Build #{@build.id}", namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build)}
Build details: #{link_to "Build #{@build.id}", namespace_project_build_url(@build.project.namespace, @build.project, @build)}
......@@ -8,4 +8,4 @@ Stage: <%= @build.stage %>
Job: <%= @build.name %>
Message: <%= @build.commit.git_commit_message %>
Url: <%= namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build) %>
Url: <%= namespace_project_build_url(@build.project.namespace, @build.project, @build) %>
......@@ -3,7 +3,7 @@
.project-issuable-filter
.controls
- if @ci_project && can?(current_user, :manage_builds, @project)
- if can?(current_user, :manage_builds, @project)
.pull-left.hidden-xs
- if @all_builds.running_or_pending.any?
= link_to 'Cancel running', cancel_all_namespace_project_builds_path(@project.namespace, @project), data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post
......@@ -40,7 +40,7 @@
%thead
%tr
%th Status
%th Build ID
%th Runner
%th Commit
%th Ref
%th Stage
......
......@@ -56,7 +56,7 @@
%br
Go to
= link_to namespace_project_runners_path(@build.gl_project.namespace, @build.gl_project) do
= link_to namespace_project_runners_path(@build.project.namespace, @build.project) do
Runners page
.row.prepend-top-default
......@@ -113,7 +113,7 @@
%p
%span.attr-name Runner:
- if @build.runner && current_user && current_user.admin
= link_to "##{@build.runner.id}", ci_admin_runner_path(@build.runner.id)
= link_to "##{@build.runner.id}", admin_runner_path(@build.runner.id)
- elsif @build.runner
\##{@build.runner.id}
......
%h3.page-title
CI settings
%hr
.bs-callout.help-callout
%p
If you want to test your .gitlab-ci.yml, you can use special tool - #{link_to "Lint", ci_lint_path}
%p
Edit your
#{link_to ".gitlab-ci.yml using web-editor", yaml_web_editor_link(@ci_project)}
- unless @project.empty_repo?
%p
Paste build status image for #{@repository.root_ref} with next link
= link_to '#', class: 'badge-codes-toggle btn btn-default btn-xs' do
Status Badge
.badge-codes-block.bs-callout.bs-callout-info.hide
%p
Status badge for
%span.label.label-info #{@ref}
branch
%div
%label Markdown:
= text_field_tag 'badge_md', markdown_badge_code(@ci_project, @repository.root_ref), readonly: true, class: 'form-control'
%label Html:
= text_field_tag 'badge_html', html_badge_code(@ci_project, @repository.root_ref), readonly: true, class: 'form-control'
= nested_form_for @ci_project, url: namespace_project_ci_settings_path(@project.namespace, @project), html: { class: 'form-horizontal' } do |f|
- if @ci_project.errors.any?
#error_explanation
%p.lead= "#{pluralize(@ci_project.errors.count, "error")} prohibited this project from being saved:"
.alert.alert-error
%ul
- @ci_project.errors.full_messages.each do |msg|
%li= msg
%fieldset
%legend Build settings
.form-group
= label_tag nil, class: 'control-label' do
Get code
.col-sm-10
%p Get recent application code using the following command:
.radio
= label_tag do
= f.radio_button :allow_git_fetch, 'false'
%strong git clone
.light Slower but makes sure you have a clean dir before every build
.radio
= label_tag do
= f.radio_button :allow_git_fetch, 'true'
%strong git fetch
.light Faster
.form-group
= f.label :timeout_in_minutes, 'Timeout', class: 'control-label'
.col-sm-10
= f.number_field :timeout_in_minutes, class: 'form-control', min: '0'
.light per build in minutes
%fieldset
%legend Build Schedule
.form-group
= f.label :always_build, 'Schedule build', class: 'control-label'
.col-sm-10
.checkbox
= f.label :always_build do
= f.check_box :always_build
%span.light Repeat last build after X hours if no builds
.form-group
= f.label :polling_interval, "Build interval", class: 'control-label'
.col-sm-10
= f.number_field :polling_interval, placeholder: '5', min: '0', class: 'form-control'
.light In hours
%fieldset
%legend Project settings
.form-group
= f.label :default_ref, "Make tabs for the following branches", class: 'control-label'
.col-sm-10
= f.text_field :default_ref, class: 'form-control', placeholder: 'master, stable'
.light You will be able to filter builds by the following branches
.form-group
= f.label :public, 'Public mode', class: 'control-label'
.col-sm-10
.checkbox
= f.label :public do
= f.check_box :public
%span.light Anyone can see project and builds
.form-group
= f.label :coverage_regex, "Test coverage parsing", class: 'control-label'
.col-sm-10
.input-group
%span.input-group-addon /
= f.text_field :coverage_regex, class: 'form-control', placeholder: '\(\d+.\d+\%\) covered'
%span.input-group-addon /
.light We will use this regular expression to find test coverage output in build trace. Leave blank if you want to disable this feature
.bs-callout.bs-callout-info
%p Below are examples of regex for existing tools:
%ul
%li
Simplecov (Ruby) -
%code \(\d+.\d+\%\) covered
%li
pytest-cov (Python) -
%code \d+\%\s*$
%li
phpunit --coverage-text --colors=never (PHP) -
%code ^\s*Lines:\s*\d+.\d+\%
%fieldset
%legend Advanced settings
.form-group
= f.label :token, "CI token", class: 'control-label'
.col-sm-10
= f.text_field :token, class: 'form-control', placeholder: 'xEeFCaDAB89'
.form-actions
= f.submit 'Save changes', class: 'btn btn-save'
- unless @ci_project.new_record?
= link_to 'Remove Project', ci_project_path(@ci_project), method: :delete, data: { confirm: 'Project will be removed. Are you sure?' }, class: 'btn btn-danger pull-right'
.alert.alert-danger
%p
There are NO runners to build this project.
%br
You can add Specific runner for this project on Runners page
- if current_user.admin
or add Shared runner for whole application in admin area.
- page_title "CI Settings"
- if no_runners_for_project?(@ci_project)
= render 'no_runners'
= render 'form'
.gray-content-block.middle-block
.pull-right
- if @ci_project && can?(current_user, :manage_builds, @ci_commit.gl_project)
- if can?(current_user, :manage_builds, @ci_commit.project)
- if @ci_commit.builds.latest.failed.any?(&:retryable?)
= link_to "Retry failed", retry_builds_namespace_project_commit_path(@ci_commit.gl_project.namespace, @ci_commit.gl_project, @ci_commit.sha), class: 'btn btn-grouped btn-primary', method: :post
= link_to "Retry failed", retry_builds_namespace_project_commit_path(@ci_commit.project.namespace, @ci_commit.project, @ci_commit.sha), class: 'btn btn-grouped btn-primary', method: :post
- if @ci_commit.builds.running_or_pending.any?
= link_to "Cancel running", cancel_builds_namespace_project_commit_path(@ci_commit.gl_project.namespace, @ci_commit.gl_project, @ci_commit.sha), data: { confirm: 'Are you sure?' }, class: 'btn btn-grouped btn-danger', method: :post
= link_to "Cancel running", cancel_builds_namespace_project_commit_path(@ci_commit.project.namespace, @ci_commit.project, @ci_commit.sha), data: { confirm: 'Are you sure?' }, class: 'btn btn-grouped btn-danger', method: :post
.oneline
= pluralize @statuses.count(:id), "build"
- if defined?(link_to_commit) && link_to_commit
for commit
= link_to @ci_commit.short_sha, namespace_project_commit_path(@ci_commit.gl_project.namespace, @ci_commit.gl_project, @ci_commit.sha), class: "monospace"
= link_to @ci_commit.short_sha, namespace_project_commit_path(@ci_commit.project.namespace, @ci_commit.project, @ci_commit.sha), class: "monospace"
- if @ci_commit.duration > 0
in
= time_interval_in_words @ci_commit.duration
......@@ -22,8 +22,9 @@
%ul
- @ci_commit.yaml_errors.split(",").each do |error|
%li= error
You can also test your .gitlab-ci.yml in the #{link_to "Lint", ci_lint_path}
- if @ci_commit.gl_project.builds_enabled? && !@ci_commit.ci_yaml_file
- if @ci_commit.project.builds_enabled? && !@ci_commit.ci_yaml_file
.bs-callout.bs-callout-warning
\.gitlab-ci.yml not found in this commit
......@@ -38,12 +39,12 @@
%th Name
%th Duration
%th Finished at
- if @ci_project && @ci_project.coverage_enabled?
- if @ci_commit.project.build_coverage_enabled?
%th Coverage
%th
- @ci_commit.refs.each do |ref|
= render partial: "projects/commit_statuses/commit_status", collection: @ci_commit.statuses.for_ref(ref).latest.ordered,
locals: { coverage: @ci_project.try(:coverage_enabled?), stage: true, allow_retry: true }
locals: { coverage: @ci_commit.project.build_coverage_enabled?, stage: true, allow_retry: true }
- if @ci_commit.retried.any?
.gray-content-block.second-block
......@@ -60,8 +61,8 @@
%th Name
%th Duration
%th Finished at
- if @ci_project && @ci_project.coverage_enabled?
- if @ci_commit.project.build_coverage_enabled?
%th Coverage
%th
= render partial: "projects/commit_statuses/commit_status", collection: @ci_commit.retried,
locals: { coverage: @ci_project.try(:coverage_enabled?), stage: true }
locals: { coverage: @ci_commit.project.build_coverage_enabled?, stage: true }
......@@ -69,7 +69,7 @@
- if current_user && can?(current_user, :download_build_artifacts, @project) && commit_status.download_url
= link_to commit_status.download_url, title: 'Download artifacts' do
%i.fa.fa-download
- if current_user && can?(current_user, :manage_builds, commit_status.gl_project)
- if current_user && can?(current_user, :manage_builds, commit_status.project)
- if commit_status.active?
- if commit_status.cancel_url
= link_to commit_status.cancel_url, method: :post, title: 'Cancel' do
......
......@@ -112,6 +112,62 @@
%hr
= link_to 'Remove avatar', namespace_project_avatar_path(@project.namespace, @project), data: { confirm: "Project avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar"
%fieldset.features
%legend
Continuous Integration
.form-group
.col-sm-offset-2.col-sm-10
%p Get recent application code using the following command:
.radio
= f.label :build_allow_git_fetch do
= f.radio_button :build_allow_git_fetch, 'false'
%strong git clone
%br
%span.descr Slower but makes sure you have a clean dir before every build
.radio
= f.label :build_allow_git_fetch do
= f.radio_button :build_allow_git_fetch, 'true'
%strong git fetch
%br
%span.descr Faster
.form-group
= f.label :build_timeout_in_minutes, 'Timeout', class: 'control-label'
.col-sm-10
= f.number_field :build_timeout_in_minutes, class: 'form-control', min: '0'
%p.help-block per build in minutes
.form-group
= f.label :build_coverage_regex, "Test coverage parsing", class: 'control-label'
.col-sm-10
.input-group
%span.input-group-addon /
= f.text_field :build_coverage_regex, class: 'form-control', placeholder: '\(\d+.\d+\%\) covered'
%span.input-group-addon /
%p.help-block
We will use this regular expression to find test coverage output in build trace.
Leave blank if you want to disable this feature
.bs-callout.bs-callout-info
%p Below are examples of regex for existing tools:
%ul
%li
Simplecov (Ruby) -
%code \(\d+.\d+\%\) covered
%li
pytest-cov (Python) -
%code \d+\%\s*$
%li
phpunit --coverage-text --colors=never (PHP) -
%code ^\s*Lines:\s*\d+.\d+\%
%fieldset.features
%legend
Advanced settings
.form-group
= f.label :runners_token, "CI token", class: 'control-label'
.col-sm-10
= f.text_field :runners_token, class: "form-control", placeholder: 'xEeFCaDAB89'
%p.help-block The secure token used to checkout project.
.form-actions
= f.submit 'Save changes', class: "btn btn-save"
......
- ci_project = @project.gitlab_ci_project
%h4 Overall stats
%ul
%li
Total:
%strong= pluralize ci_project.builds.count(:all), 'build'
%strong= pluralize @project.builds.count(:all), 'build'
%li
Successful:
%strong= pluralize ci_project.builds.success.count(:all), 'build'
%strong= pluralize @project.builds.success.count(:all), 'build'
%li
Failed:
%strong= pluralize ci_project.builds.failed.count(:all), 'build'
%strong= pluralize @project.builds.failed.count(:all), 'build'
%li
Success ratio:
%strong
#{success_ratio(ci_project.builds.success, ci_project.builds.failed)}%
#{success_ratio(@project.builds.success, @project.builds.failed)}%
%li
Commits covered:
%strong
= ci_project.commits.count(:all)
= @project.ci_commits.count(:all)
......@@ -15,10 +15,10 @@
- if runner.belongs_to_one_project?
= link_to 'Remove runner', runner_path(runner), data: { confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger btn-sm'
- else
- runner_project = @ci_project.runner_projects.find_by(runner_id: runner)
= link_to 'Disable for this project', [:ci, @ci_project, runner_project], data: { confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger btn-sm'
- runner_project = @project.runner_projects.find_by(runner_id: runner)
= link_to 'Disable for this project', namespace_project_runner_project_path(@project.namespace, @project, runner_project), data: { confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger btn-sm'
- elsif runner.specific?
= form_for [:ci, @ci_project, @ci_project.runner_projects.new] do |f|
= form_for [@project.namespace, @project, @project.runner_projects.new] do |f|
= f.hidden_field :runner_id, value: runner.id
= f.submit 'Enable for this project', class: 'btn btn-sm'
.pull-right
......
......@@ -3,11 +3,11 @@
.bs-callout.bs-callout-warning
GitLab Runners do not offer secure isolation between projects that they do builds for. You are TRUSTING all GitLab users who can push code to project A, B or C to run shell scripts on the machine hosting runner X.
%hr
- if @ci_project.shared_runners_enabled
= link_to toggle_shared_runners_ci_project_path(@ci_project), class: 'btn btn-warning', method: :post do
- if @project.shared_runners_enabled?
= link_to toggle_shared_runners_namespace_project_runners_path(@project.namespace, @project), class: 'btn btn-warning', method: :post do
Disable shared runners
- else
= link_to toggle_shared_runners_ci_project_path(@ci_project), class: 'btn btn-success', method: :post do
= link_to toggle_shared_runners_namespace_project_runners_path(@project.namespace, @project), class: 'btn btn-success', method: :post do
Enable shared runners
&nbsp; for this project
......
......@@ -12,7 +12,7 @@
%code #{ci_root_url(only_path: false)}
%li
Use the following registration token during setup:
%code #{@ci_project.token}
%code #{@project.runners_token}
%li
Start runner!
......
......@@ -36,7 +36,8 @@
:plain
curl -X POST \
-F token=TOKEN \
#{ci_build_trigger_url(@ci_project.id, 'REF_NAME')}
-F ref=REF_NAME \
#{builds_trigger_url(@project.id)}
%h3
Use .gitlab-ci.yml
......@@ -51,7 +52,7 @@
trigger:
type: deploy
script:
- "curl -X POST -F token=TOKEN #{ci_build_trigger_url(@ci_project.id, 'REF_NAME')}"
- "curl -X POST -F token=TOKEN -F ref=REF_NAME #{builds_trigger_url(@project.id)}"
%h3
Pass build variables
......@@ -65,5 +66,6 @@
:plain
curl -X POST \
-F token=TOKEN \
-F "ref=REF_NAME" \
-F "variables[RUN_NIGHTLY_BUILD]=true" \
#{ci_build_trigger_url(@ci_project.id, 'REF_NAME')}
#{builds_trigger_url(@project.id)}
......@@ -10,13 +10,13 @@
%hr
= nested_form_for @ci_project, url: url_for(controller: 'projects/variables', action: 'update'), html: { class: 'form-horizontal' } do |f|
= nested_form_for @project, url: url_for(controller: 'projects/variables', action: 'update'), html: { class: 'form-horizontal' } do |f|
- if @project.errors.any?
#error_explanation
%p.lead= "#{pluralize(@ci_project.errors.count, "error")} prohibited this project from being saved:"
%p.lead= "#{pluralize(@project.errors.count, "error")} prohibited this project from being saved:"
.alert.alert-error
%ul
- @ci_project.errors.full_messages.each do |msg|
- @project.errors.full_messages.each do |msg|
%li= msg
= f.fields_for :variables do |variable_form|
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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