mirror of
https://github.com/wahyd4/gitlabhq.git
synced 2026-08-09 12:46:07 +10:00
Merge branch 'master' into ux/suppress-ci-yml-warning
* master: (24 commits) Fix runners admin view Fix migrations Run builds from projects with enabled CI Use Gitlab::Git instead of Ci::Git Fix last specs Fix specs Fix after column rename Fix errors Update badge Finishing touches Fix triggers tests Rename columns and rename migrations Reimplement Trigger API Remove ci_ prefix from all ci related things Add runners token Migrate CI::Project to Project Fix indentation and BuildsEmailService Change default values Enhance migrate CI emails Fix issue tracker service ... Conflicts: spec/features/commits_spec.rb
This commit is contained in:
@@ -21,6 +21,7 @@ v 8.3.0 (unreleased)
|
||||
- Fire update hook from GitLab
|
||||
- Style warning about mentioning many people in a comment
|
||||
- Fix: sort milestones by due date once again (Greg Smethells)
|
||||
- Migrate all CI::Services and CI::WebHooks to Services and WebHooks
|
||||
- Don't show project fork event as "imported"
|
||||
- Add API endpoint to fetch merge request commits list
|
||||
- Expose events API with comment information and author info
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
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
|
||||
@@ -0,0 +1,35 @@
|
||||
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
|
||||
@@ -0,0 +1,63 @@
|
||||
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
|
||||
@@ -1,10 +0,0 @@
|
||||
module Ci
|
||||
module Admin
|
||||
class ApplicationController < Ci::ApplicationController
|
||||
before_action :authenticate_user!
|
||||
before_action :authenticate_admin!
|
||||
|
||||
layout "ci/admin"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,31 +0,0 @@
|
||||
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
|
||||
@@ -1,18 +0,0 @@
|
||||
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
|
||||
@@ -1,9 +0,0 @@
|
||||
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
|
||||
@@ -1,19 +0,0 @@
|
||||
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
|
||||
@@ -1,34 +0,0 @@
|
||||
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
|
||||
@@ -1,73 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
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!
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
class Projects::CiServicesController < Projects::ApplicationController
|
||||
before_action :ci_project
|
||||
before_action :authorize_admin_project!
|
||||
|
||||
layout "project_settings"
|
||||
|
||||
def index
|
||||
@ci_project.build_missing_services
|
||||
@services = @ci_project.services.reload
|
||||
end
|
||||
|
||||
def edit
|
||||
service
|
||||
end
|
||||
|
||||
def update
|
||||
if service.update_attributes(service_params)
|
||||
redirect_to edit_namespace_project_ci_service_path(@project.namespace, @project, service.to_param)
|
||||
else
|
||||
render 'edit'
|
||||
end
|
||||
end
|
||||
|
||||
def test
|
||||
last_build = @project.ci_builds.last
|
||||
|
||||
if service.execute(last_build)
|
||||
message = { notice: 'We successfully tested the service' }
|
||||
else
|
||||
message = { alert: 'We tried to test the service but error occurred' }
|
||||
end
|
||||
|
||||
redirect_back_or_default(options: message)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def service
|
||||
@service ||= @ci_project.services.find { |service| service.to_param == params[:id] }
|
||||
end
|
||||
|
||||
def service_params
|
||||
params.require(:service).permit(
|
||||
:type, :active, :webhook, :notify_only_broken_builds,
|
||||
:email_recipients, :email_only_broken_builds, :email_add_pusher,
|
||||
:hipchat_token, :hipchat_room, :hipchat_server
|
||||
)
|
||||
end
|
||||
end
|
||||
@@ -1,36 +0,0 @@
|
||||
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
|
||||
@@ -1,45 +0,0 @@
|
||||
class Projects::CiWebHooksController < Projects::ApplicationController
|
||||
before_action :ci_project
|
||||
before_action :authorize_admin_project!
|
||||
|
||||
layout "project_settings"
|
||||
|
||||
def index
|
||||
@web_hooks = @ci_project.web_hooks
|
||||
@web_hook = Ci::WebHook.new
|
||||
end
|
||||
|
||||
def create
|
||||
@web_hook = @ci_project.web_hooks.new(web_hook_params)
|
||||
@web_hook.save
|
||||
|
||||
if @web_hook.valid?
|
||||
redirect_to namespace_project_ci_web_hooks_path(@project.namespace, @project)
|
||||
else
|
||||
@web_hooks = @ci_project.web_hooks.select(&:persisted?)
|
||||
render :index
|
||||
end
|
||||
end
|
||||
|
||||
def test
|
||||
Ci::TestHookService.new.execute(hook, current_user)
|
||||
|
||||
redirect_back_or_default(default: { action: 'index' })
|
||||
end
|
||||
|
||||
def destroy
|
||||
hook.destroy
|
||||
|
||||
redirect_to namespace_project_ci_web_hooks_path(@project.namespace, @project)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def hook
|
||||
@web_hook ||= @ci_project.web_hooks.find(params[:id])
|
||||
end
|
||||
|
||||
def web_hook_params
|
||||
params.require(:web_hook).permit(:url)
|
||||
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
|
||||
|
||||
@@ -53,6 +53,7 @@ class Projects::HooksController < Projects::ApplicationController
|
||||
|
||||
def hook_params
|
||||
params.require(:hook).permit(:url, :push_events, :issues_events,
|
||||
:merge_requests_events, :tag_push_events, :note_events, :enable_ssl_verification)
|
||||
:merge_requests_events, :tag_push_events, :note_events,
|
||||
:build_events, :enable_ssl_verification)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
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
|
||||
@@ -1,14 +1,13 @@
|
||||
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
|
||||
|
||||
@@ -6,7 +6,9 @@ class Projects::ServicesController < Projects::ApplicationController
|
||||
:description, :issues_url, :new_issue_url, :restrict_to_branch, :channel,
|
||||
:colorize_messages, :channels,
|
||||
:push_events, :issues_events, :merge_requests_events, :tag_push_events,
|
||||
:note_events, :send_from_committer_email, :disable_diffs, :external_wiki_url,
|
||||
:note_events, :build_events,
|
||||
:notify_only_broken_builds, :add_pusher,
|
||||
:send_from_committer_email, :disable_diffs, :external_wiki_url,
|
||||
:notify, :color,
|
||||
:server_host, :server_port, :default_irc_uri, :enable_ssl_verification]
|
||||
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
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
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
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
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
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
|
||||
@@ -1,36 +0,0 @@
|
||||
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')
|
||||
"[](#{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
|
||||
@@ -0,0 +1,13 @@
|
||||
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)
|
||||
"[](#{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
|
||||
@@ -1,6 +1,6 @@
|
||||
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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
module Ci
|
||||
module Emails
|
||||
module Builds
|
||||
def build_fail_email(build_id, to)
|
||||
@build = Ci::Build.find(build_id)
|
||||
@project = @build.project
|
||||
mail(to: to, subject: subject("Build failed for #{@project.name}", @build.short_sha))
|
||||
end
|
||||
|
||||
def build_success_email(build_id, to)
|
||||
@build = Ci::Build.find(build_id)
|
||||
@project = @build.project
|
||||
mail(to: to, subject: subject("Build success for #{@project.name}", @build.short_sha))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,46 +0,0 @@
|
||||
module Ci
|
||||
class Notify < ActionMailer::Base
|
||||
include Ci::Emails::Builds
|
||||
|
||||
add_template_helper Ci::GitlabHelper
|
||||
|
||||
default_url_options[:host] = Gitlab.config.gitlab.host
|
||||
default_url_options[:protocol] = Gitlab.config.gitlab.protocol
|
||||
default_url_options[:port] = Gitlab.config.gitlab.port unless Gitlab.config.gitlab_on_standard_port?
|
||||
default_url_options[:script_name] = Gitlab.config.gitlab.relative_url_root
|
||||
|
||||
default from: Gitlab.config.gitlab.email_from
|
||||
|
||||
# Just send email with 3 seconds delay
|
||||
def self.delay
|
||||
delay_for(2.seconds)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Formats arguments into a String suitable for use as an email subject
|
||||
#
|
||||
# extra - Extra Strings to be inserted into the subject
|
||||
#
|
||||
# Examples
|
||||
#
|
||||
# >> subject('Lorem ipsum')
|
||||
# => "GitLab-CI | Lorem ipsum"
|
||||
#
|
||||
# # Automatically inserts Project name when @project is set
|
||||
# >> @project = Project.last
|
||||
# => #<Project id: 1, name: "Ruby on Rails", path: "ruby_on_rails", ...>
|
||||
# >> subject('Lorem ipsum')
|
||||
# => "GitLab-CI | Ruby on Rails | Lorem ipsum "
|
||||
#
|
||||
# # Accepts multiple arguments
|
||||
# >> subject('Lorem ipsum', 'Dolor sit amet')
|
||||
# => "GitLab-CI | Lorem ipsum | Dolor sit amet"
|
||||
def subject(*extra)
|
||||
subject = "GitLab-CI"
|
||||
subject << (@project ? " | #{@project.name}" : "")
|
||||
subject << " | " + extra.join(' | ') if extra.present?
|
||||
subject
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,15 @@
|
||||
module Emails
|
||||
module Builds
|
||||
def build_fail_email(build_id, to)
|
||||
@build = Ci::Build.find(build_id)
|
||||
@project = @build.project
|
||||
mail(to: to, subject: subject("Build failed for #{@project.name}", @build.short_sha))
|
||||
end
|
||||
|
||||
def build_success_email(build_id, to)
|
||||
@build = Ci::Build.find(build_id)
|
||||
@project = @build.project
|
||||
mail(to: to, subject: subject("Build success for #{@project.name}", @build.short_sha))
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -7,6 +7,7 @@ class Notify < BaseMailer
|
||||
include Emails::Projects
|
||||
include Emails::Profile
|
||||
include Emails::Groups
|
||||
include Emails::Builds
|
||||
|
||||
add_template_helper MergeRequestsHelper
|
||||
add_template_helper EmailsHelper
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
# == 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
|
||||
+33
-34
@@ -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
|
||||
@@ -96,21 +97,16 @@ module Ci
|
||||
end
|
||||
|
||||
state_machine :status, initial: :pending do
|
||||
after_transition pending: :running do |build, transition|
|
||||
build.execute_hooks
|
||||
end
|
||||
|
||||
after_transition any => [:success, :failed, :canceled] do |build, transition|
|
||||
return unless build.gl_project
|
||||
|
||||
project = build.project
|
||||
|
||||
if project.web_hooks?
|
||||
Ci::WebHookService.new.build_end(build)
|
||||
end
|
||||
return unless build.project
|
||||
|
||||
build.update_coverage
|
||||
build.commit.create_next_builds(build)
|
||||
project.execute_services(build)
|
||||
|
||||
if project.coverage_enabled?
|
||||
build.update_coverage
|
||||
end
|
||||
build.execute_hooks
|
||||
end
|
||||
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,10 +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)
|
||||
project.execute_hooks(build_data.dup, :build_hooks)
|
||||
project.execute_services(build_data.dup, :build_hooks)
|
||||
end
|
||||
|
||||
|
||||
|
||||
private
|
||||
|
||||
def yaml_variables
|
||||
|
||||
+14
-16
@@ -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
|
||||
@@ -178,16 +174,18 @@ module Ci
|
||||
duration_array.reduce(:+).to_i
|
||||
end
|
||||
|
||||
def started_at
|
||||
@started_at ||= statuses.order('started_at ASC').first.try(:started_at)
|
||||
end
|
||||
|
||||
def finished_at
|
||||
@finished_at ||= statuses.order('finished_at DESC').first.try(:finished_at)
|
||||
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
|
||||
coverage_array = latest_builds.map(&:coverage).compact
|
||||
if coverage_array.size >= 1
|
||||
'%.2f' % (coverage_array.reduce(:+) / coverage_array.size)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -197,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
|
||||
@@ -207,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
|
||||
@@ -227,7 +225,7 @@ module Ci
|
||||
# on project level and `.gitlab-ci.yml` file is present.
|
||||
#
|
||||
def show_build_status?
|
||||
gl_project.builds_enabled? && ci_yaml_file
|
||||
project.builds_enabled? && ci_yaml_file
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
# == 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
|
||||
@@ -1,192 +0,0 @@
|
||||
# == 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 :web_hooks, dependent: :destroy, class_name: 'Ci::WebHook'
|
||||
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'
|
||||
|
||||
# Project services
|
||||
has_many :services, dependent: :destroy, class_name: 'Ci::Service'
|
||||
has_one :hip_chat_service, dependent: :destroy, class_name: 'Ci::HipChatService'
|
||||
has_one :slack_service, dependent: :destroy, class_name: 'Ci::SlackService'
|
||||
has_one :mail_service, dependent: :destroy, class_name: 'Ci::MailService'
|
||||
|
||||
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 web_hooks?
|
||||
web_hooks.any?
|
||||
end
|
||||
|
||||
def services?
|
||||
services.any?
|
||||
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 available_services_names
|
||||
%w(slack mail hip_chat)
|
||||
end
|
||||
|
||||
def build_missing_services
|
||||
available_services_names.each do |service_name|
|
||||
service = services.find { |service| service.to_param == service_name }
|
||||
|
||||
# If service is available but missing in db
|
||||
# we should create an instance. Ex `create_gitlab_ci_service`
|
||||
self.send :"create_#{service_name}_service" if service.nil?
|
||||
end
|
||||
end
|
||||
|
||||
def execute_services(data)
|
||||
services.each do |service|
|
||||
|
||||
# Call service hook only if it is active
|
||||
begin
|
||||
service.execute(data) if service.active && service.can_execute?(data)
|
||||
rescue => e
|
||||
logger.error(e)
|
||||
end
|
||||
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
|
||||
@@ -1,31 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: ci_services
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# type :string(255)
|
||||
# title :string(255)
|
||||
# project_id :integer not null
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# active :boolean default(FALSE), not null
|
||||
# properties :text
|
||||
#
|
||||
|
||||
# To add new service you should build a class inherited from Service
|
||||
# and implement a set of methods
|
||||
module Ci
|
||||
class Service < ActiveRecord::Base
|
||||
extend Ci::Model
|
||||
|
||||
serialize :properties, JSON
|
||||
|
||||
default_value_for :active, false
|
||||
|
||||
after_initialize :initialize_properties
|
||||
|
||||
belongs_to :project, class_name: 'Ci::Project'
|
||||
|
||||
validates :project_id, presence: true
|
||||
|
||||
def activated?
|
||||
active
|
||||
end
|
||||
|
||||
def category
|
||||
:common
|
||||
end
|
||||
|
||||
def initialize_properties
|
||||
self.properties = {} if properties.nil?
|
||||
end
|
||||
|
||||
def title
|
||||
# implement inside child
|
||||
end
|
||||
|
||||
def description
|
||||
# implement inside child
|
||||
end
|
||||
|
||||
def help
|
||||
# implement inside child
|
||||
end
|
||||
|
||||
def to_param
|
||||
# implement inside child
|
||||
end
|
||||
|
||||
def fields
|
||||
# implement inside child
|
||||
[]
|
||||
end
|
||||
|
||||
def can_test?
|
||||
project.builds.any?
|
||||
end
|
||||
|
||||
def can_execute?(build)
|
||||
true
|
||||
end
|
||||
|
||||
def execute(build)
|
||||
# implement inside child
|
||||
end
|
||||
|
||||
# Provide convenient accessor methods
|
||||
# for each serialized property.
|
||||
def self.prop_accessor(*args)
|
||||
args.each do |arg|
|
||||
class_eval %{
|
||||
def #{arg}
|
||||
(properties || {})['#{arg}']
|
||||
end
|
||||
|
||||
def #{arg}=(value)
|
||||
self.properties ||= {}
|
||||
self.properties['#{arg}'] = value
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def self.boolean_accessor(*args)
|
||||
self.prop_accessor(*args)
|
||||
|
||||
args.each do |arg|
|
||||
class_eval %{
|
||||
def #{arg}?
|
||||
ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES.include?(#{arg})
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
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
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: ci_web_hooks
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# url :string(255) not null
|
||||
# project_id :integer not null
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
#
|
||||
|
||||
module Ci
|
||||
class WebHook < ActiveRecord::Base
|
||||
extend Ci::Model
|
||||
|
||||
include HTTParty
|
||||
|
||||
belongs_to :project, class_name: 'Ci::Project'
|
||||
|
||||
# HTTParty timeout
|
||||
default_timeout 10
|
||||
|
||||
validates :url, presence: true, url: true
|
||||
|
||||
def execute(data)
|
||||
parsed_url = URI.parse(url)
|
||||
if parsed_url.userinfo.blank?
|
||||
Ci::WebHook.post(url, body: data.to_json, headers: { "Content-Type" => "application/json" }, verify: false)
|
||||
else
|
||||
post_url = url.gsub("#{parsed_url.userinfo}@", "")
|
||||
auth = {
|
||||
username: URI.decode(parsed_url.user),
|
||||
password: URI.decode(parsed_url.password),
|
||||
}
|
||||
Ci::WebHook.post(post_url,
|
||||
body: data.to_json,
|
||||
headers: { "Content-Type" => "application/json" },
|
||||
verify: false,
|
||||
basic_auth: auth)
|
||||
end
|
||||
end
|
||||
end
|
||||
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
|
||||
|
||||
@@ -25,4 +25,5 @@ class ProjectHook < WebHook
|
||||
scope :issue_hooks, -> { where(issues_events: true) }
|
||||
scope :note_hooks, -> { where(note_events: true) }
|
||||
scope :merge_request_hooks, -> { where(merge_requests_events: true) }
|
||||
scope :build_hooks, -> { where(build_events: true) }
|
||||
end
|
||||
|
||||
@@ -26,6 +26,7 @@ class WebHook < ActiveRecord::Base
|
||||
default_value_for :note_events, false
|
||||
default_value_for :merge_requests_events, false
|
||||
default_value_for :tag_push_events, false
|
||||
default_value_for :build_events, false
|
||||
default_value_for :enable_ssl_verification, true
|
||||
|
||||
# HTTParty timeout
|
||||
|
||||
+51
-26
@@ -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,10 +78,10 @@ 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
|
||||
has_one :builds_email_service, dependent: :destroy
|
||||
has_one :irker_service, dependent: :destroy
|
||||
has_one :pivotaltracker_service, dependent: :destroy
|
||||
has_one :hipchat_service, dependent: :destroy
|
||||
@@ -121,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
|
||||
@@ -161,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
|
||||
@@ -256,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
|
||||
@@ -790,28 +807,6 @@ 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
|
||||
)
|
||||
end
|
||||
|
||||
# TODO: this should be migrated to Project table,
|
||||
# the same as issues_enabled
|
||||
def builds_enabled
|
||||
gitlab_ci_service && gitlab_ci_service.active
|
||||
end
|
||||
|
||||
def builds_enabled?
|
||||
builds_enabled
|
||||
end
|
||||
|
||||
def builds_enabled=(value)
|
||||
service = gitlab_ci_service || create_gitlab_ci_service
|
||||
service.active = value
|
||||
service.save
|
||||
end
|
||||
|
||||
def enable_ci
|
||||
self.builds_enabled = true
|
||||
end
|
||||
@@ -825,4 +820,34 @@ class Project < ActiveRecord::Base
|
||||
forked_project_link.destroy
|
||||
end
|
||||
end
|
||||
|
||||
def any_runners?(&block)
|
||||
if runners.active.any?(&block)
|
||||
return true
|
||||
end
|
||||
|
||||
shared_runners_enabled? && Ci::Runner.shared.active.any?(&block)
|
||||
end
|
||||
|
||||
def valid_runners_token? token
|
||||
self.runners_token && self.runners_token == token
|
||||
end
|
||||
|
||||
# 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 build_coverage_enabled?
|
||||
build_coverage_regex.present?
|
||||
end
|
||||
|
||||
def build_timeout_in_minutes
|
||||
build_timeout / 60
|
||||
end
|
||||
|
||||
def build_timeout_in_minutes=(value)
|
||||
self.build_timeout = value.to_i * 60
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: services
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# type :string(255)
|
||||
# title :string(255)
|
||||
# project_id :integer
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# active :boolean default(FALSE), not null
|
||||
# properties :text
|
||||
# template :boolean default(FALSE)
|
||||
# push_events :boolean default(TRUE)
|
||||
# issues_events :boolean default(TRUE)
|
||||
# merge_requests_events :boolean default(TRUE)
|
||||
# tag_push_events :boolean default(TRUE)
|
||||
# note_events :boolean default(TRUE), not null
|
||||
#
|
||||
|
||||
class BuildsEmailService < Service
|
||||
prop_accessor :recipients
|
||||
boolean_accessor :add_pusher
|
||||
boolean_accessor :notify_only_broken_builds
|
||||
validates :recipients, presence: true, if: :activated?
|
||||
|
||||
def initialize_properties
|
||||
if properties.nil?
|
||||
self.properties = {}
|
||||
self.notify_only_broken_builds = true
|
||||
end
|
||||
end
|
||||
|
||||
def title
|
||||
'Builds emails'
|
||||
end
|
||||
|
||||
def description
|
||||
'Email the builds status to a list of recipients.'
|
||||
end
|
||||
|
||||
def to_param
|
||||
'builds_email'
|
||||
end
|
||||
|
||||
def supported_events
|
||||
%w(build)
|
||||
end
|
||||
|
||||
def execute(push_data)
|
||||
return unless supported_events.include?(push_data[:object_kind])
|
||||
|
||||
if should_build_be_notified?(push_data)
|
||||
BuildEmailWorker.perform_async(
|
||||
push_data[:build_id],
|
||||
all_recipients(push_data),
|
||||
push_data,
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def fields
|
||||
[
|
||||
{ type: 'textarea', name: 'recipients', placeholder: 'Emails separated by comma' },
|
||||
{ type: 'checkbox', name: 'add_pusher', label: 'Add pusher to recipients list' },
|
||||
{ type: 'checkbox', name: 'notify_only_broken_builds' },
|
||||
]
|
||||
end
|
||||
|
||||
def should_build_be_notified?(data)
|
||||
case data[:build_status]
|
||||
when 'success'
|
||||
!notify_only_broken_builds?
|
||||
when 'failed'
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def all_recipients(data)
|
||||
all_recipients = recipients.split(',')
|
||||
|
||||
if add_pusher? && data[:user][:email]
|
||||
all_recipients << "#{data[:user][:email]}"
|
||||
end
|
||||
|
||||
all_recipients
|
||||
end
|
||||
end
|
||||
@@ -1,73 +0,0 @@
|
||||
module Ci
|
||||
class HipChatMessage
|
||||
include Gitlab::Application.routes.url_helpers
|
||||
|
||||
attr_reader :build
|
||||
|
||||
def initialize(build)
|
||||
@build = build
|
||||
end
|
||||
|
||||
def to_s
|
||||
lines = Array.new
|
||||
lines.push("<a href=\"#{ci_project_url(project)}\">#{project.name}</a> - ")
|
||||
lines.push("<a href=\"#{builds_namespace_project_commit_url(commit.gl_project.namespace, commit.gl_project, commit.sha)}\">Commit ##{commit.id}</a></br>")
|
||||
lines.push("#{commit.short_sha} #{commit.git_author_name} - #{commit.git_commit_message}</br>")
|
||||
lines.push("#{humanized_status(commit_status)} in #{commit.duration} second(s).")
|
||||
lines.join('')
|
||||
end
|
||||
|
||||
def status_color(build_or_commit=nil)
|
||||
build_or_commit ||= commit_status
|
||||
case build_or_commit
|
||||
when :success
|
||||
'green'
|
||||
when :failed, :canceled
|
||||
'red'
|
||||
else # :pending, :running or unknown
|
||||
'yellow'
|
||||
end
|
||||
end
|
||||
|
||||
def notify?
|
||||
[:failed, :canceled].include?(commit_status)
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def commit
|
||||
build.commit
|
||||
end
|
||||
|
||||
def project
|
||||
commit.project
|
||||
end
|
||||
|
||||
def build_status
|
||||
build.status.to_sym
|
||||
end
|
||||
|
||||
def commit_status
|
||||
commit.status.to_sym
|
||||
end
|
||||
|
||||
def humanized_status(build_or_commit=nil)
|
||||
build_or_commit ||= commit_status
|
||||
case build_or_commit
|
||||
when :pending
|
||||
"Pending"
|
||||
when :running
|
||||
"Running"
|
||||
when :failed
|
||||
"Failed"
|
||||
when :success
|
||||
"Successful"
|
||||
when :canceled
|
||||
"Canceled"
|
||||
else
|
||||
"Unknown"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,93 +0,0 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: ci_services
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# type :string(255)
|
||||
# title :string(255)
|
||||
# project_id :integer not null
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# active :boolean default(FALSE), not null
|
||||
# properties :text
|
||||
#
|
||||
|
||||
module Ci
|
||||
class HipChatService < Ci::Service
|
||||
prop_accessor :hipchat_token, :hipchat_room, :hipchat_server
|
||||
boolean_accessor :notify_only_broken_builds
|
||||
validates :hipchat_token, presence: true, if: :activated?
|
||||
validates :hipchat_room, presence: true, if: :activated?
|
||||
default_value_for :notify_only_broken_builds, true
|
||||
|
||||
def title
|
||||
"HipChat"
|
||||
end
|
||||
|
||||
def description
|
||||
"Private group chat, video chat, instant messaging for teams"
|
||||
end
|
||||
|
||||
def help
|
||||
end
|
||||
|
||||
def to_param
|
||||
'hip_chat'
|
||||
end
|
||||
|
||||
def fields
|
||||
[
|
||||
{ type: 'text', name: 'hipchat_token', label: 'Token', placeholder: '' },
|
||||
{ type: 'text', name: 'hipchat_room', label: 'Room', placeholder: '' },
|
||||
{ type: 'text', name: 'hipchat_server', label: 'Server', placeholder: 'https://hipchat.example.com', help: 'Leave blank for default' },
|
||||
{ type: 'checkbox', name: 'notify_only_broken_builds', label: 'Notify only broken builds' }
|
||||
]
|
||||
end
|
||||
|
||||
def can_execute?(build)
|
||||
return if build.allow_failure?
|
||||
|
||||
commit = build.commit
|
||||
return unless commit
|
||||
return unless commit.latest_builds.include? build
|
||||
|
||||
case commit.status.to_sym
|
||||
when :failed
|
||||
true
|
||||
when :success
|
||||
true unless notify_only_broken_builds?
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def execute(build)
|
||||
msg = Ci::HipChatMessage.new(build)
|
||||
opts = default_options.merge(
|
||||
token: hipchat_token,
|
||||
room: hipchat_room,
|
||||
server: server_url,
|
||||
color: msg.status_color,
|
||||
notify: msg.notify?
|
||||
)
|
||||
Ci::HipChatNotifierWorker.perform_async(msg.to_s, opts)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def default_options
|
||||
{
|
||||
service_name: 'GitLab CI',
|
||||
message_format: 'html'
|
||||
}
|
||||
end
|
||||
|
||||
def server_url
|
||||
if hipchat_server.blank?
|
||||
'https://api.hipchat.com'
|
||||
else
|
||||
hipchat_server
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,84 +0,0 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: ci_services
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# type :string(255)
|
||||
# title :string(255)
|
||||
# project_id :integer not null
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# active :boolean default(FALSE), not null
|
||||
# properties :text
|
||||
#
|
||||
|
||||
module Ci
|
||||
class MailService < Ci::Service
|
||||
delegate :email_recipients, :email_recipients=,
|
||||
:email_add_pusher, :email_add_pusher=,
|
||||
:email_only_broken_builds, :email_only_broken_builds=, to: :project, prefix: false
|
||||
|
||||
before_save :update_project
|
||||
|
||||
default_value_for :active, true
|
||||
|
||||
def title
|
||||
'Mail'
|
||||
end
|
||||
|
||||
def description
|
||||
'Email notification'
|
||||
end
|
||||
|
||||
def to_param
|
||||
'mail'
|
||||
end
|
||||
|
||||
def fields
|
||||
[
|
||||
{ type: 'text', name: 'email_recipients', label: 'Recipients', help: 'Whitespace-separated list of recipient addresses' },
|
||||
{ type: 'checkbox', name: 'email_add_pusher', label: 'Add pusher to recipients list' },
|
||||
{ type: 'checkbox', name: 'email_only_broken_builds', label: 'Notify only broken builds' }
|
||||
]
|
||||
end
|
||||
|
||||
def can_execute?(build)
|
||||
return if build.allow_failure?
|
||||
|
||||
# it doesn't make sense to send emails for retried builds
|
||||
commit = build.commit
|
||||
return unless commit
|
||||
return unless commit.latest_builds.include?(build)
|
||||
|
||||
case build.status.to_sym
|
||||
when :failed
|
||||
true
|
||||
when :success
|
||||
true unless email_only_broken_builds
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def execute(build)
|
||||
build.project_recipients.each do |recipient|
|
||||
case build.status.to_sym
|
||||
when :success
|
||||
mailer.build_success_email(build.id, recipient).deliver_later
|
||||
when :failed
|
||||
mailer.build_fail_email(build.id, recipient).deliver_later
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def update_project
|
||||
project.save!
|
||||
end
|
||||
|
||||
def mailer
|
||||
Ci::Notify
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,92 +0,0 @@
|
||||
require 'slack-notifier'
|
||||
|
||||
module Ci
|
||||
class SlackMessage
|
||||
include Gitlab::Application.routes.url_helpers
|
||||
|
||||
def initialize(commit)
|
||||
@commit = commit
|
||||
end
|
||||
|
||||
def pretext
|
||||
''
|
||||
end
|
||||
|
||||
def color
|
||||
attachment_color
|
||||
end
|
||||
|
||||
def fallback
|
||||
format(attachment_message)
|
||||
end
|
||||
|
||||
def attachments
|
||||
fields = []
|
||||
|
||||
commit.latest_builds.each do |build|
|
||||
next if build.allow_failure?
|
||||
next unless build.failed?
|
||||
fields << {
|
||||
title: build.name,
|
||||
value: "Build <#{namespace_project_build_url(build.gl_project.namespace, build.gl_project, build)}|\##{build.id}> failed in #{build.duration.to_i} second(s)."
|
||||
}
|
||||
end
|
||||
|
||||
[{
|
||||
text: attachment_message,
|
||||
color: attachment_color,
|
||||
fields: fields
|
||||
}]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :commit
|
||||
|
||||
def attachment_message
|
||||
out = "<#{ci_project_url(project)}|#{project_name}>: "
|
||||
out << "Commit <#{builds_namespace_project_commit_url(commit.gl_project.namespace, commit.gl_project, commit.sha)}|\##{commit.id}> "
|
||||
out << "(<#{commit_sha_link}|#{commit.short_sha}>) "
|
||||
out << "of <#{commit_ref_link}|#{commit.ref}> "
|
||||
out << "by #{commit.git_author_name} " if commit.git_author_name
|
||||
out << "#{commit_status} in "
|
||||
out << "#{commit.duration} second(s)"
|
||||
end
|
||||
|
||||
def format(string)
|
||||
Slack::Notifier::LinkFormatter.format(string)
|
||||
end
|
||||
|
||||
def project
|
||||
commit.project
|
||||
end
|
||||
|
||||
def project_name
|
||||
project.name
|
||||
end
|
||||
|
||||
def commit_sha_link
|
||||
"#{project.gitlab_url}/commit/#{commit.sha}"
|
||||
end
|
||||
|
||||
def commit_ref_link
|
||||
"#{project.gitlab_url}/commits/#{commit.ref}"
|
||||
end
|
||||
|
||||
def attachment_color
|
||||
if commit.success?
|
||||
'good'
|
||||
else
|
||||
'danger'
|
||||
end
|
||||
end
|
||||
|
||||
def commit_status
|
||||
if commit.success?
|
||||
'succeeded'
|
||||
else
|
||||
'failed'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,81 +0,0 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: ci_services
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# type :string(255)
|
||||
# title :string(255)
|
||||
# project_id :integer not null
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# active :boolean default(FALSE), not null
|
||||
# properties :text
|
||||
#
|
||||
|
||||
module Ci
|
||||
class SlackService < Ci::Service
|
||||
prop_accessor :webhook
|
||||
boolean_accessor :notify_only_broken_builds
|
||||
validates :webhook, presence: true, if: :activated?
|
||||
|
||||
default_value_for :notify_only_broken_builds, true
|
||||
|
||||
def title
|
||||
'Slack'
|
||||
end
|
||||
|
||||
def description
|
||||
'A team communication tool for the 21st century'
|
||||
end
|
||||
|
||||
def to_param
|
||||
'slack'
|
||||
end
|
||||
|
||||
def help
|
||||
'Visit https://www.slack.com/services/new/incoming-webhook. Then copy link and save project!' unless webhook.present?
|
||||
end
|
||||
|
||||
def fields
|
||||
[
|
||||
{ type: 'text', name: 'webhook', label: 'Webhook URL', placeholder: '' },
|
||||
{ type: 'checkbox', name: 'notify_only_broken_builds', label: 'Notify only broken builds' }
|
||||
]
|
||||
end
|
||||
|
||||
def can_execute?(build)
|
||||
return if build.allow_failure?
|
||||
|
||||
commit = build.commit
|
||||
return unless commit
|
||||
return unless commit.latest_builds.include?(build)
|
||||
|
||||
case commit.status.to_sym
|
||||
when :failed
|
||||
true
|
||||
when :success
|
||||
true unless notify_only_broken_builds?
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def execute(build)
|
||||
message = Ci::SlackMessage.new(build.commit)
|
||||
options = default_options.merge(
|
||||
color: message.color,
|
||||
fallback: message.fallback,
|
||||
attachments: message.attachments
|
||||
)
|
||||
Ci::SlackNotifierWorker.perform_async(webhook, message.pretext, options)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def default_options
|
||||
{
|
||||
username: 'GitLab CI'
|
||||
}
|
||||
end
|
||||
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
|
||||
|
||||
@@ -22,8 +22,16 @@ class HipchatService < Service
|
||||
MAX_COMMITS = 3
|
||||
|
||||
prop_accessor :token, :room, :server, :notify, :color, :api_version
|
||||
boolean_accessor :notify_only_broken_builds
|
||||
validates :token, presence: true, if: :activated?
|
||||
|
||||
def initialize_properties
|
||||
if properties.nil?
|
||||
self.properties = {}
|
||||
self.notify_only_broken_builds = true
|
||||
end
|
||||
end
|
||||
|
||||
def title
|
||||
'HipChat'
|
||||
end
|
||||
@@ -45,12 +53,13 @@ class HipchatService < Service
|
||||
{ type: 'text', name: 'api_version',
|
||||
placeholder: 'Leave blank for default (v2)' },
|
||||
{ type: 'text', name: 'server',
|
||||
placeholder: 'Leave blank for default. https://hipchat.example.com' }
|
||||
placeholder: 'Leave blank for default. https://hipchat.example.com' },
|
||||
{ type: 'checkbox', name: 'notify_only_broken_builds' },
|
||||
]
|
||||
end
|
||||
|
||||
def supported_events
|
||||
%w(push issue merge_request note tag_push)
|
||||
%w(push issue merge_request note tag_push build)
|
||||
end
|
||||
|
||||
def execute(data)
|
||||
@@ -94,6 +103,8 @@ class HipchatService < Service
|
||||
create_merge_request_message(data) unless is_update?(data)
|
||||
when "note"
|
||||
create_note_message(data)
|
||||
when "build"
|
||||
create_build_message(data) if should_build_be_notified?(data)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -235,6 +246,20 @@ class HipchatService < Service
|
||||
message
|
||||
end
|
||||
|
||||
def create_build_message(data)
|
||||
ref_type = data[:tag] ? 'tag' : 'branch'
|
||||
ref = data[:ref]
|
||||
sha = data[:sha]
|
||||
user_name = data[:commit][:author_name]
|
||||
status = data[:commit][:status]
|
||||
duration = data[:commit][:duration]
|
||||
|
||||
branch_link = "<a href=\"#{project_url}/commits/#{URI.escape(ref)}\">#{ref}</a>"
|
||||
commit_link = "<a href=\"#{project_url}/commit/#{URI.escape(sha)}/builds\">#{Commit.truncate_sha(sha)}</a>"
|
||||
|
||||
"#{project_link}: Commit #{commit_link} of #{branch_link} #{ref_type} by #{user_name} #{humanized_status(status)} in #{duration} second(s)"
|
||||
end
|
||||
|
||||
def project_name
|
||||
project.name_with_namespace.gsub(/\s/, '')
|
||||
end
|
||||
@@ -250,4 +275,24 @@ class HipchatService < Service
|
||||
def is_update?(data)
|
||||
data[:object_attributes][:action] == 'update'
|
||||
end
|
||||
|
||||
def humanized_status(status)
|
||||
case status
|
||||
when 'success'
|
||||
'passed'
|
||||
else
|
||||
status
|
||||
end
|
||||
end
|
||||
|
||||
def should_build_be_notified?(data)
|
||||
case data[:commit][:status]
|
||||
when 'success'
|
||||
!notify_only_broken_builds?
|
||||
when 'failed'
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -20,8 +20,16 @@
|
||||
|
||||
class SlackService < Service
|
||||
prop_accessor :webhook, :username, :channel
|
||||
boolean_accessor :notify_only_broken_builds
|
||||
validates :webhook, presence: true, if: :activated?
|
||||
|
||||
def initialize_properties
|
||||
if properties.nil?
|
||||
self.properties = {}
|
||||
self.notify_only_broken_builds = true
|
||||
end
|
||||
end
|
||||
|
||||
def title
|
||||
'Slack'
|
||||
end
|
||||
@@ -45,12 +53,13 @@ class SlackService < Service
|
||||
{ type: 'text', name: 'webhook',
|
||||
placeholder: 'https://hooks.slack.com/services/...' },
|
||||
{ type: 'text', name: 'username', placeholder: 'username' },
|
||||
{ type: 'text', name: 'channel', placeholder: '#channel' }
|
||||
{ type: 'text', name: 'channel', placeholder: '#channel' },
|
||||
{ type: 'checkbox', name: 'notify_only_broken_builds' },
|
||||
]
|
||||
end
|
||||
|
||||
def supported_events
|
||||
%w(push issue merge_request note tag_push)
|
||||
%w(push issue merge_request note tag_push build)
|
||||
end
|
||||
|
||||
def execute(data)
|
||||
@@ -78,6 +87,8 @@ class SlackService < Service
|
||||
MergeMessage.new(data) unless is_update?(data)
|
||||
when "note"
|
||||
NoteMessage.new(data)
|
||||
when "build"
|
||||
BuildMessage.new(data) if should_build_be_notified?(data)
|
||||
end
|
||||
|
||||
opt = {}
|
||||
@@ -86,7 +97,7 @@ class SlackService < Service
|
||||
|
||||
if message
|
||||
notifier = Slack::Notifier.new(webhook, opt)
|
||||
notifier.ping(message.pretext, attachments: message.attachments)
|
||||
notifier.ping(message.pretext, attachments: message.attachments, fallback: message.fallback)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -103,9 +114,21 @@ class SlackService < Service
|
||||
def is_update?(data)
|
||||
data[:object_attributes][:action] == 'update'
|
||||
end
|
||||
|
||||
def should_build_be_notified?(data)
|
||||
case data[:commit][:status]
|
||||
when 'success'
|
||||
!notify_only_broken_builds?
|
||||
when 'failed'
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require "slack_service/issue_message"
|
||||
require "slack_service/push_message"
|
||||
require "slack_service/merge_message"
|
||||
require "slack_service/note_message"
|
||||
require "slack_service/build_message"
|
||||
|
||||
@@ -10,6 +10,9 @@ class SlackService
|
||||
format(message)
|
||||
end
|
||||
|
||||
def fallback
|
||||
end
|
||||
|
||||
def attachments
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
class SlackService
|
||||
class BuildMessage < BaseMessage
|
||||
attr_reader :sha
|
||||
attr_reader :ref_type
|
||||
attr_reader :ref
|
||||
attr_reader :status
|
||||
attr_reader :project_name
|
||||
attr_reader :project_url
|
||||
attr_reader :user_name
|
||||
attr_reader :duration
|
||||
|
||||
def initialize(params, commit = true)
|
||||
@sha = params[:sha]
|
||||
@ref_type = params[:tag] ? 'tag' : 'branch'
|
||||
@ref = params[:ref]
|
||||
@project_name = params[:project_name]
|
||||
@project_url = params[:project_url]
|
||||
@status = params[:commit][:status]
|
||||
@user_name = params[:commit][:author_name]
|
||||
@duration = params[:commit][:duration]
|
||||
end
|
||||
|
||||
def pretext
|
||||
''
|
||||
end
|
||||
|
||||
def fallback
|
||||
format(message)
|
||||
end
|
||||
|
||||
def attachments
|
||||
[{ text: format(message), color: attachment_color }]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def message
|
||||
"#{project_link}: Commit #{commit_link} of #{branch_link} #{ref_type} by #{user_name} #{humanized_status} in #{duration} second(s)"
|
||||
end
|
||||
|
||||
def format(string)
|
||||
Slack::Notifier::LinkFormatter.format(string)
|
||||
end
|
||||
|
||||
def humanized_status
|
||||
case status
|
||||
when 'success'
|
||||
'passed'
|
||||
else
|
||||
status
|
||||
end
|
||||
end
|
||||
|
||||
def attachment_color
|
||||
if status == 'success'
|
||||
'good'
|
||||
else
|
||||
'danger'
|
||||
end
|
||||
end
|
||||
|
||||
def branch_url
|
||||
"#{project_url}/commits/#{ref}"
|
||||
end
|
||||
|
||||
def branch_link
|
||||
"[#{ref}](#{branch_url})"
|
||||
end
|
||||
|
||||
def project_link
|
||||
"[#{project_name}](#{project_url})"
|
||||
end
|
||||
|
||||
def commit_url
|
||||
"#{project_url}/commit/#{sha}/builds"
|
||||
end
|
||||
|
||||
def commit_link
|
||||
"[#{Commit.truncate_sha(sha)}](#{commit_url})"
|
||||
end
|
||||
end
|
||||
end
|
||||
+19
-2
@@ -30,6 +30,7 @@ class Service < ActiveRecord::Base
|
||||
default_value_for :merge_requests_events, true
|
||||
default_value_for :tag_push_events, true
|
||||
default_value_for :note_events, true
|
||||
default_value_for :build_events, true
|
||||
|
||||
after_initialize :initialize_properties
|
||||
|
||||
@@ -40,13 +41,14 @@ 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) }
|
||||
scope :issue_hooks, -> { where(issues_events: true, active: true) }
|
||||
scope :merge_request_hooks, -> { where(merge_requests_events: true, active: true) }
|
||||
scope :note_hooks, -> { where(note_events: true, active: true) }
|
||||
scope :build_hooks, -> { where(build_events: true, active: true) }
|
||||
|
||||
def activated?
|
||||
active
|
||||
@@ -133,6 +135,21 @@ class Service < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
# Provide convenient boolean accessor methods
|
||||
# for each serialized property.
|
||||
# Also keep track of updated properties in a similar way as ActiveModel::Dirty
|
||||
def self.boolean_accessor(*args)
|
||||
self.prop_accessor(*args)
|
||||
|
||||
args.each do |arg|
|
||||
class_eval %{
|
||||
def #{arg}?
|
||||
ActiveRecord::ConnectionAdapters::Column::TRUE_VALUES.include?(#{arg})
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
# Returns a hash of the properties that have been assigned a new value since last save,
|
||||
# indicating their original values (attr => original value).
|
||||
# ActiveRecord does not provide a mechanism to track changes in serialized keys,
|
||||
@@ -163,6 +180,7 @@ class Service < ActiveRecord::Base
|
||||
assembla
|
||||
bamboo
|
||||
buildkite
|
||||
builds_email
|
||||
campfire
|
||||
custom_issue_tracker
|
||||
drone_ci
|
||||
@@ -170,7 +188,6 @@ class Service < ActiveRecord::Base
|
||||
external_wiki
|
||||
flowdock
|
||||
gemnasium
|
||||
gitlab_ci
|
||||
hipchat
|
||||
irker
|
||||
jira
|
||||
|
||||
+3
-4
@@ -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,9 +29,11 @@ module Ci
|
||||
build_attrs.merge!(ref: ref,
|
||||
tag: tag,
|
||||
trigger_request: trigger_request,
|
||||
user: user)
|
||||
user: user,
|
||||
project: commit.project)
|
||||
|
||||
commit.builds.create!(build_attrs)
|
||||
build = commit.builds.create!(build_attrs)
|
||||
build.execute_hooks
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
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
|
||||
@@ -1,13 +1,13 @@
|
||||
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,
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
module Ci
|
||||
class TestHookService
|
||||
def execute(hook, current_user)
|
||||
Ci::WebHookService.new.build_end(hook.project.commits.last.last_build)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,28 @@
|
||||
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
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
- 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
|
||||
@@ -0,0 +1,50 @@
|
||||
.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'
|
||||
|
||||
+6
-6
@@ -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'
|
||||
|
||||
- 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'
|
||||
|
||||
+2
-2
@@ -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
|
||||
+17
-22
@@ -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}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
= 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'
|
||||
@@ -1,3 +0,0 @@
|
||||
%h3.page-title Settings
|
||||
%hr
|
||||
= render 'form'
|
||||
@@ -1,34 +0,0 @@
|
||||
- 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
|
||||
@@ -1,28 +0,0 @@
|
||||
%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
|
||||
@@ -1,18 +0,0 @@
|
||||
.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
|
||||
@@ -1,29 +0,0 @@
|
||||
- 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
|
||||
·
|
||||
= 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
|
||||
@@ -1,16 +0,0 @@
|
||||
.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
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
%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?
|
||||
- if commit.coverage
|
||||
%td.coverage
|
||||
- if commit.coverage
|
||||
#{commit.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.
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
.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' )
|
||||
@@ -1,35 +0,0 @@
|
||||
%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
|
||||
@@ -1,12 +0,0 @@
|
||||
%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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user