Commit e40c13ae authored by Tomasz Maczukin's avatar Tomasz Maczukin

Merge branch 'master' into fix/visibility-level-setting-in-forked-projects

* master:
  Add CI permissions and api links to README [ci skip]
  Remove duplicate documentation links
  make migrations reversible
  Add missing stage to builds view
  CI details cleanup
  Allow groups to appear in the search results if the group owner allows it
  Update installation.md
  update example of regex for pytest-cov
parents 3a52662c 193bc5fb
...@@ -22,6 +22,7 @@ v 8.2.0 (unreleased) ...@@ -22,6 +22,7 @@ v 8.2.0 (unreleased)
- Include commit logs in project search - Include commit logs in project search
- Add "added", "modified" and "removed" properties to commit object in webhook - Add "added", "modified" and "removed" properties to commit object in webhook
- Rename "Back to" links to "Go to" because its not always a case it point to place user come from - Rename "Back to" links to "Go to" because its not always a case it point to place user come from
- Allow groups to appear in the search results if the group owner allows it
v 8.1.3 v 8.1.3
- Spread out runner contacted_at updates - Spread out runner contacted_at updates
......
...@@ -4,12 +4,12 @@ class GroupsController < Groups::ApplicationController ...@@ -4,12 +4,12 @@ class GroupsController < Groups::ApplicationController
before_action :group, except: [:new, :create] before_action :group, except: [:new, :create]
# Authorize # Authorize
before_action :authorize_read_group!, except: [:show, :new, :create] before_action :authorize_read_group!, except: [:show, :new, :create, :autocomplete]
before_action :authorize_admin_group!, only: [:edit, :update, :destroy, :projects] before_action :authorize_admin_group!, only: [:edit, :update, :destroy, :projects]
before_action :authorize_create_group!, only: [:new, :create] before_action :authorize_create_group!, only: [:new, :create]
# Load group projects # Load group projects
before_action :load_projects, except: [:new, :create, :projects, :edit, :update] before_action :load_projects, except: [:new, :create, :projects, :edit, :update, :autocomplete]
before_action :event_filter, only: :show before_action :event_filter, only: :show
layout :determine_layout layout :determine_layout
...@@ -133,7 +133,7 @@ class GroupsController < Groups::ApplicationController ...@@ -133,7 +133,7 @@ class GroupsController < Groups::ApplicationController
end end
def group_params def group_params
params.require(:group).permit(:name, :description, :path, :avatar) params.require(:group).permit(:name, :description, :path, :avatar, :public)
end end
def load_events def load_events
......
...@@ -30,7 +30,7 @@ class Projects::BuildsController < Projects::ApplicationController ...@@ -30,7 +30,7 @@ class Projects::BuildsController < Projects::ApplicationController
def show def show
@builds = @ci_project.commits.find_by_sha(@build.sha).builds.order('id DESC') @builds = @ci_project.commits.find_by_sha(@build.sha).builds.order('id DESC')
@builds = @builds.where("id not in (?)", @build.id).page(params[:page]).per(20) @builds = @builds.where("id not in (?)", @build.id)
@commit = @build.commit @commit = @build.commit
respond_to do |format| respond_to do |format|
...@@ -42,17 +42,13 @@ class Projects::BuildsController < Projects::ApplicationController ...@@ -42,17 +42,13 @@ class Projects::BuildsController < Projects::ApplicationController
end end
def retry def retry
if @build.commands.blank? unless @build.retryable?
return page_404 return page_404
end end
build = Ci::Build.retry(@build) build = Ci::Build.retry(@build)
if params[:return_to] redirect_to build_path(build)
redirect_to URI.parse(params[:return_to]).path
else
redirect_to build_path(build)
end
end end
def status def status
......
...@@ -7,14 +7,14 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -7,14 +7,14 @@ class Projects::CommitController < Projects::ApplicationController
before_action :authorize_download_code!, except: [:cancel_builds] before_action :authorize_download_code!, except: [:cancel_builds]
before_action :authorize_manage_builds!, only: [:cancel_builds] before_action :authorize_manage_builds!, only: [:cancel_builds]
before_action :commit before_action :commit
before_action :authorize_manage_builds!, only: [:cancel_builds, :retry_builds]
before_action :define_show_vars, only: [:show, :builds]
def show def show
return git_not_found! unless @commit return git_not_found! unless @commit
@line_notes = commit.notes.inline @line_notes = commit.notes.inline
@diffs = @commit.diffs
@note = @project.build_commit_note(commit) @note = @project.build_commit_note(commit)
@notes_count = commit.notes.count
@notes = commit.notes.not_inline.fresh @notes = commit.notes.not_inline.fresh
@noteable = @commit @noteable = @commit
@comments_allowed = @reply_allowed = true @comments_allowed = @reply_allowed = true
...@@ -23,8 +23,6 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -23,8 +23,6 @@ class Projects::CommitController < Projects::ApplicationController
commit_id: @commit.id commit_id: @commit.id
} }
@ci_commit = project.ci_commit(commit.sha)
respond_to do |format| respond_to do |format|
format.html format.html
format.diff { render text: @commit.to_diff } format.diff { render text: @commit.to_diff }
...@@ -32,20 +30,25 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -32,20 +30,25 @@ class Projects::CommitController < Projects::ApplicationController
end end
end end
def ci def builds
@ci_commit = @project.ci_commit(@commit.sha)
@builds = @ci_commit.builds if @ci_commit
@notes_count = @commit.notes.count
@ci_project = @project.gitlab_ci_project @ci_project = @project.gitlab_ci_project
end end
def cancel_builds def cancel_builds
@ci_commit = @project.ci_commit(@commit.sha) ci_commit.builds.running_or_pending.each(&:cancel)
@ci_commit.builds.running_or_pending.each(&:cancel)
redirect_to ci_namespace_project_commit_path(project.namespace, project, commit.sha) redirect_to builds_namespace_project_commit_path(project.namespace, project, commit.sha)
end end
def retry_builds
ci_commit.builds.latest.failed.each do |build|
if build.retryable?
Ci::Build.retry(build)
end
end
redirect_to builds_namespace_project_commit_path(project.namespace, project, commit.sha)
end
def branches def branches
@branches = @project.repository.branch_names_contains(commit.id) @branches = @project.repository.branch_names_contains(commit.id)
...@@ -53,11 +56,22 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -53,11 +56,22 @@ class Projects::CommitController < Projects::ApplicationController
render layout: false render layout: false
end end
private
def commit def commit
@commit ||= @project.commit(params[:id]) @commit ||= @project.commit(params[:id])
end end
private def ci_commit
@ci_commit ||= project.ci_commit(commit.sha)
end
def define_show_vars
@diffs = commit.diffs
@notes_count = commit.notes.count
@builds = ci_commit.builds if ci_commit
end
def authorize_manage_builds! def authorize_manage_builds!
unless can?(current_user, :manage_builds, project) unless can?(current_user, :manage_builds, project)
......
...@@ -6,33 +6,34 @@ class GroupsFinder ...@@ -6,33 +6,34 @@ class GroupsFinder
private private
def all_groups(current_user) def all_groups(current_user)
if current_user group_ids = if current_user
if current_user.authorized_groups.any? if current_user.authorized_groups.any?
# User has access to groups # User has access to groups
# #
# Return only: # Return only:
# groups with public projects # groups with public projects
# groups with internal projects # groups with internal projects
# groups with joined projects # groups with joined projects
# #
group_ids = Project.public_and_internal_only.pluck(:namespace_id) + Project.public_and_internal_only.pluck(:namespace_id) +
current_user.authorized_groups.pluck(:id) current_user.authorized_groups.pluck(:id)
Group.where(id: group_ids) else
else # User has no group membership
# User has no group membership #
# # Return only:
# Return only: # groups with public projects
# groups with public projects # groups with internal projects
# groups with internal projects #
# Project.public_and_internal_only.pluck(:namespace_id)
Group.where(id: Project.public_and_internal_only.pluck(:namespace_id)) end
end else
else # Not authenticated
# Not authenticated #
# # Return only:
# Return only: # groups with public projects
# groups with public projects Project.public_only.pluck(:namespace_id)
Group.where(id: Project.public_only.pluck(:namespace_id)) end
end
Group.where("public IS TRUE OR id IN(?)", group_ids)
end end
end end
module BuildsHelper
def build_ref_link build
gitlab_ref_link build.project, build.ref
end
def build_commit_link build
gitlab_commit_link build.project, build.short_sha
end
def build_url(build)
namespace_project_build_path(build.gl_project, build.project, build)
end
end
...@@ -4,25 +4,6 @@ module Ci ...@@ -4,25 +4,6 @@ module Ci
{ :"data-no-turbolink" => "data-no-turbolink" } { :"data-no-turbolink" => "data-no-turbolink" }
end end
def gitlab_ref_link project, ref
gitlab_url = project.gitlab_url.dup
gitlab_url << "/commits/#{ref}"
link_to ref, gitlab_url, no_turbolink
end
def gitlab_compare_link project, before, after
gitlab_url = project.gitlab_url.dup
gitlab_url << "/compare/#{before}...#{after}"
link_to "#{before}...#{after}", gitlab_url, no_turbolink
end
def gitlab_commit_link project, sha
gitlab_url = project.gitlab_url.dup
gitlab_url << "/commit/#{sha}"
link_to Ci::Commit.truncate_sha(sha), gitlab_url, no_turbolink
end
def yaml_web_editor_link(project) def yaml_web_editor_link(project)
commits = project.commits commits = project.commits
......
module CiStatusHelper module CiStatusHelper
def ci_status_path(ci_commit) def ci_status_path(ci_commit)
project = ci_commit.gl_project project = ci_commit.gl_project
ci_namespace_project_commit_path(project.namespace, project, ci_commit.sha) builds_namespace_project_commit_path(project.namespace, project, ci_commit.sha)
end end
def ci_status_icon(ci_commit) def ci_status_icon(ci_commit)
......
...@@ -70,7 +70,7 @@ module SearchHelper ...@@ -70,7 +70,7 @@ module SearchHelper
# Autocomplete results for the current user's groups # Autocomplete results for the current user's groups
def groups_autocomplete(term, limit = 5) def groups_autocomplete(term, limit = 5)
current_user.authorized_groups.search(term).limit(limit).map do |group| GroupsFinder.new.execute(current_user).search(term).limit(limit).map do |group|
{ {
label: "group: #{search_result_sanitize(group.name)}", label: "group: #{search_result_sanitize(group.name)}",
url: group_path(group) url: group_path(group)
......
...@@ -106,6 +106,14 @@ module Ci ...@@ -106,6 +106,14 @@ module Ci
failed? && allow_failure? failed? && allow_failure?
end end
def retryable?
commands.present?
end
def retried?
!self.commit.latest_builds_for_ref(self.ref).include?(self)
end
def trace_html def trace_html
html = Ci::Ansi2html::convert(trace) if trace.present? html = Ci::Ansi2html::convert(trace) if trace.present?
html || '' html || ''
...@@ -222,7 +230,7 @@ module Ci ...@@ -222,7 +230,7 @@ module Ci
end end
def retry_url def retry_url
if commands.present? if retryable?
Gitlab::Application.routes.url_helpers. Gitlab::Application.routes.url_helpers.
retry_namespace_project_build_path(gl_project.namespace, gl_project, self) retry_namespace_project_build_path(gl_project.namespace, gl_project, self)
end end
......
...@@ -15,8 +15,8 @@ class CommitStatus < ActiveRecord::Base ...@@ -15,8 +15,8 @@ class CommitStatus < ActiveRecord::Base
scope :pending, -> { where(status: 'pending') } scope :pending, -> { where(status: 'pending') }
scope :success, -> { where(status: 'success') } scope :success, -> { where(status: 'success') }
scope :failed, -> { where(status: 'failed') } scope :failed, -> { where(status: 'failed') }
scope :running_or_pending, -> { where(status:[:running, :pending]) } scope :running_or_pending, -> { where(status: [:running, :pending]) }
scope :finished, -> { where(status:[:success, :failed, :canceled]) } scope :finished, -> { where(status: [:success, :failed, :canceled]) }
scope :latest, -> { where(id: unscope(:select).select('max(id)').group(:name, :ref)) } scope :latest, -> { where(id: unscope(:select).select('max(id)').group(:name, :ref)) }
scope :ordered, -> { order(:ref, :stage_idx, :name) } scope :ordered, -> { order(:ref, :stage_idx, :name) }
scope :for_ref, ->(ref) { where(ref: ref) } scope :for_ref, ->(ref) { where(ref: ref) }
......
...@@ -120,7 +120,7 @@ class Group < Namespace ...@@ -120,7 +120,7 @@ class Group < Namespace
end end
def public_profile? def public_profile?
projects.public_only.any? self.public || projects.public_only.any?
end end
def post_create_hook def post_create_hook
......
...@@ -11,7 +11,7 @@ module Ci ...@@ -11,7 +11,7 @@ module Ci
def to_s def to_s
lines = Array.new lines = Array.new
lines.push("<a href=\"#{ci_project_url(project)}\">#{project.name}</a> - ") lines.push("<a href=\"#{ci_project_url(project)}\">#{project.name}</a> - ")
lines.push("<a href=\"#{ci_namespace_project_commit_url(commit.gl_project.namespace, commit.gl_project, commit.sha)}\">Commit ##{commit.id}</a></br>") 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("#{commit.short_sha} #{commit.git_author_name} - #{commit.git_commit_message}</br>")
lines.push("#{humanized_status(commit_status)} in #{commit.duration} second(s).") lines.push("#{humanized_status(commit_status)} in #{commit.duration} second(s).")
lines.join('') lines.join('')
......
...@@ -45,7 +45,7 @@ module Ci ...@@ -45,7 +45,7 @@ module Ci
def attachment_message def attachment_message
out = "<#{ci_project_url(project)}|#{project_name}>: " out = "<#{ci_project_url(project)}|#{project_name}>: "
out << "Commit <#{ci_namespace_project_commit_url(commit.gl_project.namespace, commit.gl_project, commit.sha)}|\##{commit.id}> " 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 << "(<#{commit_sha_link}|#{commit.short_sha}>) "
out << "of <#{commit_ref_link}|#{commit.ref}> " out << "of <#{commit_ref_link}|#{commit.ref}> "
out << "by #{commit.git_author_name} " if commit.git_author_name out << "by #{commit.git_author_name} " if commit.git_author_name
......
...@@ -71,7 +71,7 @@ class GitlabCiService < CiService ...@@ -71,7 +71,7 @@ class GitlabCiService < CiService
def build_page(sha, ref) def build_page(sha, ref)
if project.gitlab_ci_project.present? if project.gitlab_ci_project.present?
ci_namespace_project_commit_url(project.namespace, project, sha) builds_namespace_project_commit_url(project.namespace, project, sha)
end end
end end
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
= @project.name = @project.name
%p %p
Commit link: #{gitlab_commit_link(@project, @build.commit.short_sha)} Commit: #{link_to @build.short_sha, namespace_project_commit_path(@build.gl_project.namespace, @build.gl_project, @build.sha)}
%p %p
Author: #{@build.commit.git_author_name} Author: #{@build.commit.git_author_name}
%p %p
...@@ -16,4 +16,4 @@ ...@@ -16,4 +16,4 @@
Message: #{@build.commit.git_commit_message} Message: #{@build.commit.git_commit_message}
%p %p
Url: #{link_to @build.short_sha, namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build)} Build details: #{link_to "Build #{@build.id}", namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build)}
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
= @project.name = @project.name
%p %p
Commit link: #{gitlab_commit_link(@project, @build.commit.short_sha)} Commit: #{link_to @build.short_sha, namespace_project_commit_path(@build.gl_project.namespace, @build.gl_project, @build.sha)}
%p %p
Author: #{@build.commit.git_author_name} Author: #{@build.commit.git_author_name}
%p %p
...@@ -17,4 +17,4 @@ ...@@ -17,4 +17,4 @@
Message: #{@build.commit.git_commit_message} Message: #{@build.commit.git_commit_message}
%p %p
Url: #{link_to @build.short_sha, namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build)} Build details: #{link_to "Build #{@build.id}", namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build)}
...@@ -16,4 +16,4 @@ ...@@ -16,4 +16,4 @@
- group = group_member.group - group = group_member.group
= render 'shared/groups/group', group: group, group_member: group_member = render 'shared/groups/group', group: group, group_member: group_member
= paginate @group_members = paginate @group_members, theme: 'gitlab'
...@@ -25,6 +25,15 @@ ...@@ -25,6 +25,15 @@
%hr %hr
= link_to 'Remove avatar', group_avatar_path(@group.to_param), data: { confirm: "Group avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar" = link_to 'Remove avatar', group_avatar_path(@group.to_param), data: { confirm: "Group avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar"
.form-group
%hr
= f.label :public, class: 'control-label' do
Public
.col-sm-10
.checkbox
= f.check_box :public
%span.descr Make this group public (even if there is no any public project inside this group)
.form-actions .form-actions
= f.submit 'Save group', class: "btn btn-save" = f.submit 'Save group', class: "btn btn-save"
......
...@@ -9,23 +9,25 @@ ...@@ -9,23 +9,25 @@
= nav_link path: 'projects#index' do = nav_link path: 'projects#index' do
= link_to ci_admin_projects_path do = link_to ci_admin_projects_path do
= icon('list-alt fw') = icon('list-alt fw')
Projects %span
Projects
= nav_link path: 'events#index' do = nav_link path: 'events#index' do
= link_to ci_admin_events_path do = link_to ci_admin_events_path do
= icon('book fw') = icon('book fw')
Events %span
Events
= nav_link path: ['runners#index', 'runners#show'] do = nav_link path: ['runners#index', 'runners#show'] do
= link_to ci_admin_runners_path do = link_to ci_admin_runners_path do
= icon('cog fw') = icon('cog fw')
Runners %span
%small.pull-right Runners
= Ci::Runner.count(:all) %span.count= Ci::Runner.count(:all)
= nav_link path: 'builds#index' do = nav_link path: 'builds#index' do
= link_to ci_admin_builds_path do = link_to ci_admin_builds_path do
= icon('link fw') = icon('link fw')
Builds %span
%small.pull-right Builds
= Ci::Build.count(:all) %span.count= Ci::Build.count(:all)
= nav_link(controller: :application_settings, html_options: { class: 'separate-item'}) do = nav_link(controller: :application_settings, html_options: { class: 'separate-item'}) do
= link_to ci_admin_application_settings_path do = link_to ci_admin_application_settings_path do
= icon('cogs fw') = icon('cogs fw')
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
= ci_commit.status = ci_commit.status
= link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id" = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id"
= link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit.id), class: "commit-row-message" = link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit), class: "commit-row-message"
&middot; &middot;
#{time_ago_with_tooltip(commit.committed_date, skip_js: true)} by #{time_ago_with_tooltip(commit.committed_date, skip_js: true)} by
= commit_author_link(commit, avatar: true, size: 24) = commit_author_link(commit, avatar: true, size: 24)
%tr.build
%td.status
= ci_status_with_icon(build.status)
%td.commit_status-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
= link_to build.short_sha, namespace_project_commit_path(@project.namespace, @project, build.sha)
%td
= link_to build.ref, namespace_project_commits_path(@project.namespace, @project, build.ref)
%td
- if build.runner
= runner_link(build.runner)
- else
.light none
%td
= build.name
.pull-right
- if build.tags.any?
- build.tags.each do |tag|
%span.label.label-primary
= tag
- if build.trigger_request
%span.label.label-info triggered
- if build.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_in_words build.finished_at} ago
%td
.pull-right
- if current_user && can?(current_user, :manage_builds, @project)
- if build.cancel_url
= link_to build.cancel_url, title: 'Cancel' do
%i.fa.fa-remove.cred
- header_title project_title(@project, "Builds", project_builds_path(@project))
- page_title "Builds" - page_title "Builds"
- header_title project_title(@project, "Builds", project_builds_path(@project)) = render "header_title"
.project-issuable-filter .project-issuable-filter
.controls .controls
- if @ci_project && current_user && can?(current_user, :manage_builds, @project) - if @ci_project && current_user && can?(current_user, :manage_builds, @project)
.pull-left.hidden-xs .pull-left.hidden-xs
- if @all_builds.running_or_pending.any? - if @all_builds.running_or_pending.any?
= link_to 'Cancel all', cancel_all_namespace_project_builds_path(@project.namespace, @project), data: { confirm: 'Are you sure?' }, class: 'btn btn-danger' = link_to 'Cancel all', cancel_all_namespace_project_builds_path(@project.namespace, @project), data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post
%ul.center-top-menu %ul.center-top-menu
%li{class: ('active' if @scope.nil?)} %li{class: ('active' if @scope.nil?)}
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
%span.badge.js-totalbuilds-count= @all_builds.count(:id) %span.badge.js-totalbuilds-count= @all_builds.count(:id)
.gray-content-block .gray-content-block
List of #{@scope || 'running'} builds from this project #{(@scope || 'running').capitalize} builds from this project
%ul.content-list %ul.content-list
- if @builds.blank? - if @builds.blank?
...@@ -40,14 +40,14 @@ ...@@ -40,14 +40,14 @@
%th Build ID %th Build ID
%th Commit %th Commit
%th Ref %th Ref
%th Runner %th Stage
%th Name %th Name
%th Duration %th Duration
%th Finished at %th Finished at
%th %th
- @builds.each do |build| - @builds.each do |build|
= render 'projects/builds/build', build: build = render 'projects/commit_statuses/commit_status', commit_status: build, commit_sha: true, stage: true, allow_retry: true
= paginate @builds = paginate @builds, theme: 'gitlab'
- page_title "#{@build.name} (#{@build.id})", "Builds"
= render "header_title"
.build-page .build-page
.gray-content-block .gray-content-block
Build for commit Build ##{@build.id} for commit
%strong.monospace %strong.monospace
= link_to @build.commit.short_sha, ci_status_path(@build.commit) = link_to @build.commit.short_sha, ci_status_path(@build.commit)
from from
%code #{@build.ref} = link_to @build.ref, namespace_project_commits_path(@project.namespace, @project, @build.ref)
#up-build-trace #up-build-trace
- if @commit.matrix_for_ref?(@build.ref) - if @commit.matrix_for_ref?(@build.ref)
...@@ -20,7 +23,7 @@ ...@@ -20,7 +23,7 @@
= build.id = build.id
- unless @commit.latest_builds_for_ref(@build.ref).include?(@build) - if @build.retried?
%li.active %li.active
%a %a
Build ##{@build.id} Build ##{@build.id}
...@@ -37,7 +40,7 @@ ...@@ -37,7 +40,7 @@
%i.fa.fa-time %i.fa.fa-time
#{duration_in_words(@build.finished_at, @build.started_at)} #{duration_in_words(@build.finished_at, @build.started_at)}
.pull-right .pull-right
= @build.updated_at.stamp('19:00 Aug 27') #{time_ago_with_tooltip(@build.finished_at) if @build.finished_at}
- if @build.show_warning? - if @build.show_warning?
- unless @build.any_runners_online? - unless @build.any_runners_online?
...@@ -87,13 +90,13 @@ ...@@ -87,13 +90,13 @@
.build-widget .build-widget
%h4.title %h4.title
Build Build ##{@build.id}
- if current_user && can?(current_user, :manage_builds, @project) - if current_user && can?(current_user, :manage_builds, @project)
.pull-right .pull-right
- if @build.active? - if @build.cancel_url
= link_to "Cancel", cancel_namespace_project_build_path(@project.namespace, @project, @build), class: 'btn btn-sm btn-danger' = link_to "Cancel", @build.cancel_url, class: 'btn btn-sm btn-danger', method: :post
- elsif @build.commands.present? - elsif @build.retry_url
= link_to "Retry", retry_namespace_project_build_path(@project.namespace, @project, @build), class: 'btn btn-sm btn-primary', method: :post = link_to "Retry", @build.retry_url, class: 'btn btn-sm btn-primary', method: :post
- if @build.duration - if @build.duration
%p %p
...@@ -101,15 +104,15 @@ ...@@ -101,15 +104,15 @@
#{duration_in_words(@build.finished_at, @build.started_at)} #{duration_in_words(@build.finished_at, @build.started_at)}
%p %p
%span.attr-name Created: %span.attr-name Created:
#{time_ago_in_words(@build.created_at)} ago #{time_ago_with_tooltip(@build.created_at)}
- if @build.finished_at - if @build.finished_at
%p %p
%span.attr-name Finished: %span.attr-name Finished:
#{time_ago_in_words(@build.finished_at)} ago #{time_ago_with_tooltip(@build.finished_at)}
%p %p
%span.attr-name Runner: %span.attr-name Runner:
- if @build.runner && current_user && current_user.admin - if @build.runner && current_user && current_user.admin
\#{link_to "##{@build.runner.id}", ci_admin_runner_path(@build.runner.id)} = link_to "##{@build.runner.id}", ci_admin_runner_path(@build.runner.id)
- elsif @build.runner - elsif @build.runner
\##{@build.runner.id} \##{@build.runner.id}
...@@ -134,10 +137,11 @@ ...@@ -134,10 +137,11 @@
%h4.title %h4.title
Commit Commit
.pull-right .pull-right
%small #{build_commit_link @build} %small
= link_to @build.commit.short_sha, ci_status_path(@build.commit), class: "monospace"
%p %p
%span.attr-name Branch: %span.attr-name Branch:
#{build_ref_link @build} = link_to @build.ref, namespace_project_commits_path(@project.namespace, @project, @build.ref)
%p %p
%span.attr-name Author: %span.attr-name Author:
#{@build.commit.git_author_name} #{@build.commit.git_author_name}
...@@ -155,7 +159,9 @@ ...@@ -155,7 +159,9 @@
- if @builds.present? - if @builds.present?
.build-widget .build-widget
%h4.title #{pluralize(@builds.count(:id), "other build")} for #{@build.short_sha}: %h4.title #{pluralize(@builds.count(:id), "other build")} for
= succeed ":" do
= link_to @build.commit.short_sha, ci_status_path(@build.commit), class: "monospace"
%table.table.builds %table.table.builds
- @builds.each_with_index do |build, i| - @builds.each_with_index do |build, i|
%tr.build %tr.build
...@@ -171,8 +177,5 @@ ...@@ -171,8 +177,5 @@
%td.status= build.status %td.status= build.status
= paginate @builds
:javascript :javascript
new CiBuild("#{namespace_project_build_url(@project.namespace, @project, @build)}", "#{@build.status}") new CiBuild("#{namespace_project_build_url(@project.namespace, @project, @build)}", "#{@build.status}")
- page_title @service.title, "CI Services"
= render 'form' = render 'form'
- page_title "CI Services"
%h3.page-title Project services %h3.page-title Project services
%p.light Project services allow you to integrate GitLab CI with other applications %p.light Project services allow you to integrate GitLab CI with other applications
......
...@@ -102,7 +102,7 @@ ...@@ -102,7 +102,7 @@
%code \(\d+.\d+\%\) covered %code \(\d+.\d+\%\) covered
%li %li
pytest-cov (Python) - pytest-cov (Python) -
%code \d+\%$ %code \d+\%\s*$
......
- page_title "CI Settings"
- if @ci_project.generated_yaml_config - if @ci_project.generated_yaml_config
%p.alert.alert-danger %p.alert.alert-danger
CI Jobs are deprecated now, you can #{link_to "download", dumped_yaml_ci_project_path(@ci_project)} CI Jobs are deprecated now, you can #{link_to "download", dumped_yaml_ci_project_path(@ci_project)}
......
- page_title "CI Web Hooks"
%h3.page-title %h3.page-title
CI Web hooks CI Web hooks
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
= nav_link(path: 'commit#show') do = nav_link(path: 'commit#show') do
= link_to namespace_project_commit_path(@project.namespace, @project, @commit.id) do = link_to namespace_project_commit_path(@project.namespace, @project, @commit.id) do
Changes Changes
= nav_link(path: 'commit#ci') do %span.badge= @diffs.count
= link_to ci_namespace_project_commit_path(@project.namespace, @project, @commit.id) do = nav_link(path: 'commit#builds') do
= link_to builds_namespace_project_commit_path(@project.namespace, @project, @commit.id) do
Builds Builds
%span.badge= @builds.count(:id)
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
%p %p
%span.light Commit %span.light Commit
= link_to @commit.id, namespace_project_commit_path(@project.namespace, @project, @commit) = link_to @commit.id, namespace_project_commit_path(@project.namespace, @project, @commit), class: "monospace"
.commit-info-row .commit-info-row
%span.light Authored by %span.light Authored by
%strong %strong
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
.commit-info-row .commit-info-row
%span.cgray= pluralize(@commit.parents.count, "parent") %span.cgray= pluralize(@commit.parents.count, "parent")
- @commit.parents.each do |parent| - @commit.parents.each do |parent|
= link_to parent.short_id, namespace_project_commit_path(@project.namespace, @project, parent) = link_to parent.short_id, namespace_project_commit_path(@project.namespace, @project, parent), class: "monospace"
- if @ci_commit - if @ci_commit
.pull-right .pull-right
......
- page_title "#{@commit.title} (#{@commit.short_id})", "Commits" - page_title "Builds", "#{@commit.title} (#{@commit.short_id})", "Commits"
= render "projects/commits/header_title" = render "projects/commits/header_title"
= render "commit_box" = render "commit_box"
= render "ci_menu" = render "ci_menu"
...@@ -26,8 +26,11 @@ ...@@ -26,8 +26,11 @@
&nbsp; &nbsp;
- if @ci_project && current_user && can?(current_user, :manage_builds, @project) - if @ci_project && current_user && can?(current_user, :manage_builds, @project)
- if @ci_commit.builds.latest.failed.any?(&:retryable?)
= link_to "Retry failed", retry_builds_namespace_project_commit_path(@project.namespace, @project, @commit.sha), class: 'btn btn-xs btn-primary', method: :post
- if @ci_commit.builds.running_or_pending.any? - if @ci_commit.builds.running_or_pending.any?
= link_to "Cancel all", cancel_builds_namespace_project_commit_path(@project.namespace, @project, @commit.sha), class: 'btn btn-xs btn-danger' = link_to "Cancel running", cancel_builds_namespace_project_commit_path(@project.namespace, @project, @commit.sha), class: 'btn btn-xs btn-danger', method: :post
.table-holder .table-holder
%table.table.builds %table.table.builds
...@@ -45,7 +48,7 @@ ...@@ -45,7 +48,7 @@
%th %th
- @ci_commit.refs.each do |ref| - @ci_commit.refs.each do |ref|
= render partial: "projects/commit_statuses/commit_status", collection: @ci_commit.statuses.for_ref(ref).latest.ordered, = render partial: "projects/commit_statuses/commit_status", collection: @ci_commit.statuses.for_ref(ref).latest.ordered,
locals: { coverage: @ci_project.try(:coverage_enabled?), allow_retry: true } locals: { coverage: @ci_project.try(:coverage_enabled?), stage: true, allow_retry: true }
- if @ci_commit.retried.any? - if @ci_commit.retried.any?
.gray-content-block.second-block .gray-content-block.second-block
...@@ -66,4 +69,4 @@ ...@@ -66,4 +69,4 @@
%th Coverage %th Coverage
%th %th
= render partial: "projects/commit_statuses/commit_status", collection: @ci_commit.retried, = render partial: "projects/commit_statuses/commit_status", collection: @ci_commit.retried,
locals: { coverage: @ci_project.try(:coverage_enabled?) } locals: { coverage: @ci_project.try(:coverage_enabled?), stage: true }
...@@ -12,14 +12,30 @@ ...@@ -12,14 +12,30 @@
- if commit_status.show_warning? - if commit_status.show_warning?
%i.fa.fa-warning.text-warning %i.fa.fa-warning.text-warning
%td - if defined?(commit_sha) && commit_sha
= commit_status.ref %td
= link_to commit_status.short_sha, namespace_project_commit_path(@project.namespace, @project, commit_status.sha), class: "monospace"
%td %td
= commit_status.stage - if commit_status.ref
= link_to commit_status.ref, namespace_project_commits_path(@project.namespace, @project, commit_status.ref)
- else
.light none
- if defined?(runner) && runner
%td
- if commit_status.try(:runner)
= runner_link(commit_status.runner)
- else
.light none
- if defined?(stage) && stage
%td
= commit_status.stage
%td %td
= commit_status.name = commit_status.name
.pull-right .pull-right
- if commit_status.tags.any? - if commit_status.tags.any?
- commit_status.tags.each do |tag| - commit_status.tags.each do |tag|
...@@ -36,7 +52,7 @@ ...@@ -36,7 +52,7 @@
%td.timestamp %td.timestamp
- if commit_status.finished_at - if commit_status.finished_at
%span #{time_ago_in_words commit_status.finished_at} ago %span #{time_ago_with_tooltip(commit_status.finished_at)}
- if defined?(coverage) && coverage - if defined?(coverage) && coverage
%td.coverage %td.coverage
...@@ -46,9 +62,10 @@ ...@@ -46,9 +62,10 @@
%td %td
.pull-right .pull-right
- if current_user && can?(current_user, :manage_builds, commit_status.gl_project) - if current_user && can?(current_user, :manage_builds, commit_status.gl_project)
- if commit_status.cancel_url - if commit_status.active?
= link_to commit_status.cancel_url, title: 'Cancel' do - if commit_status.cancel_url
%i.fa.fa-remove.cred = link_to commit_status.cancel_url, method: :post, title: 'Cancel' do
%i.fa.fa-remove.cred
- elsif defined?(allow_retry) && allow_retry && commit_status.retry_url - elsif defined?(allow_retry) && allow_retry && commit_status.retry_url
= link_to commit_status.retry_url, method: :post, title: 'Retry' do = link_to commit_status.retry_url, method: :post, title: 'Retry' do
%i.fa.fa-repeat %i.fa.fa-repeat
- page_title "Edit", "#{@runner.description} ##{@runner.id}", "Runners"
%h4 Runner ##{@runner.id} %h4 Runner ##{@runner.id}
%hr %hr
= form_for @runner, url: runner_path(@runner), html: { class: 'form-horizontal' } do |f| = form_for @runner, url: runner_path(@runner), html: { class: 'form-horizontal' } do |f|
......
- page_title "Runners"
.light .light
%p %p
A 'runner' is a process which runs a build. A 'runner' is a process which runs a build.
......
= content_for :title do - page_title "#{@runner.description} ##{@runner.id}", "Runners"
%h3.project-title
Runner ##{@runner.id} %h3.page-title
.pull-right Runner ##{@runner.id}
- if @runner.shared? .pull-right
%span.runner-state.runner-state-shared - if @runner.shared?
Shared %span.runner-state.runner-state-shared
- else Shared
%span.runner-state.runner-state-specific - else
Specific %span.runner-state.runner-state-specific
Specific
.table-holder .table-holder
%table.table %table.table
......
- page_title "Triggers"
%h3.page-title %h3.page-title
Triggers Triggers
......
- page_title "Variables"
%h3.page-title %h3.page-title
Secret Variables Secret Variables
......
...@@ -472,8 +472,9 @@ Gitlab::Application.routes.draw do ...@@ -472,8 +472,9 @@ Gitlab::Application.routes.draw do
resources :commit, only: [:show], constraints: { id: /[[:alnum:]]{6,40}/ } do resources :commit, only: [:show], constraints: { id: /[[:alnum:]]{6,40}/ } do
member do member do
get :branches get :branches
get :ci get :builds
get :cancel_builds post :cancel_builds
post :retry_builds
end end
end end
...@@ -588,12 +589,12 @@ Gitlab::Application.routes.draw do ...@@ -588,12 +589,12 @@ Gitlab::Application.routes.draw do
resources :builds, only: [:index, :show] do resources :builds, only: [:index, :show] do
collection do collection do
get :cancel_all post :cancel_all
end end
member do member do
get :cancel
get :status get :status
post :cancel
post :retry post :retry
end end
end end
......
class FixBuildTags < ActiveRecord::Migration class FixBuildTags < ActiveRecord::Migration
def change def up
execute("UPDATE taggings SET taggable_type='CommitStatus' WHERE taggable_type='Ci::Build'") execute("UPDATE taggings SET taggable_type='CommitStatus' WHERE taggable_type='Ci::Build'")
end end
def down
execute("UPDATE taggings SET taggable_type='Ci::Build' WHERE taggable_type='CommitStatus'")
end
end end
class FailBuildWithoutNames < ActiveRecord::Migration class FailBuildWithoutNames < ActiveRecord::Migration
def change def up
execute("UPDATE ci_builds SET status='failed' WHERE name IS NULL AND status='pending'") execute("UPDATE ci_builds SET status='failed' WHERE name IS NULL AND status='pending'")
end end
def down
end
end end
class FailBuildWithEmptyName < ActiveRecord::Migration class FailBuildWithEmptyName < ActiveRecord::Migration
def change def up
execute("UPDATE ci_builds SET status='failed' WHERE (name IS NULL OR name='') AND status='pending'") execute("UPDATE ci_builds SET status='failed' WHERE (name IS NULL OR name='') AND status='pending'")
end end
def down
end
end end
class AddPublicToGroup < ActiveRecord::Migration
def change
add_column :namespaces, :public, :boolean, default: false
end
end
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20151026182941) do ActiveRecord::Schema.define(version: 20151103001141) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
...@@ -501,14 +501,15 @@ ActiveRecord::Schema.define(version: 20151026182941) do ...@@ -501,14 +501,15 @@ ActiveRecord::Schema.define(version: 20151026182941) do
add_index "milestones", ["project_id"], name: "index_milestones_on_project_id", using: :btree add_index "milestones", ["project_id"], name: "index_milestones_on_project_id", using: :btree
create_table "namespaces", force: true do |t| create_table "namespaces", force: true do |t|
t.string "name", null: false t.string "name", null: false
t.string "path", null: false t.string "path", null: false
t.integer "owner_id" t.integer "owner_id"
t.datetime "created_at" t.datetime "created_at"
t.datetime "updated_at" t.datetime "updated_at"
t.string "type" t.string "type"
t.string "description", default: "", null: false t.string "description", default: "", null: false
t.string "avatar" t.string "avatar"
t.boolean "public", default: false
end end
add_index "namespaces", ["created_at", "id"], name: "index_namespaces_on_created_at_and_id", using: :btree add_index "namespaces", ["created_at", "id"], name: "index_namespaces_on_created_at_and_id", using: :btree
......
...@@ -17,20 +17,22 @@ ...@@ -17,20 +17,22 @@
## CI Documentation ## CI Documentation
+ [Quick Start](ci/quick_start/README.md) - [Quick Start](ci/quick_start/README.md)
+ [Configuring project (.gitlab-ci.yml)](ci/yaml/README.md) - [Configuring project (.gitlab-ci.yml)](ci/yaml/README.md)
+ [Configuring runner](ci/runners/README.md) - [Configuring runner](ci/runners/README.md)
+ [Configuring deployment](ci/deployment/README.md) - [Configuring deployment](ci/deployment/README.md)
+ [Using Docker Images](ci/docker/using_docker_images.md) - [Using Docker Images](ci/docker/using_docker_images.md)
+ [Using Docker Build](ci/docker/using_docker_build.md) - [Using Docker Build](ci/docker/using_docker_build.md)
+ [Using Variables](ci/variables/README.md) - [Using Variables](ci/variables/README.md)
- [User permissions](ci/permissions/README.md)
- [API](ci/api/README.md)
### CI Examples ### CI Examples
+ [Test and deploy Ruby applications to Heroku](ci/examples/test-and-deploy-ruby-application-to-heroku.md) - [Test and deploy Ruby applications to Heroku](ci/examples/test-and-deploy-ruby-application-to-heroku.md)
+ [Test and deploy Python applications to Heroku](ci/examples/test-and-deploy-python-application-to-heroku.md) - [Test and deploy Python applications to Heroku](ci/examples/test-and-deploy-python-application-to-heroku.md)
+ [Test Clojure applications](ci/examples/test-clojure-application.md) - [Test Clojure applications](ci/examples/test-clojure-application.md)
+ Help your favorite programming language and GitLab by sending a merge request with a guide for that language. - Help your favorite programming language and GitLab by sending a merge request with a guide for that language.
## Administrator documentation ## Administrator documentation
...@@ -49,11 +51,6 @@ ...@@ -49,11 +51,6 @@
- [Reply by email](incoming_email/README.md) Allow users to comment on issues and merge requests by replying to notification emails. - [Reply by email](incoming_email/README.md) Allow users to comment on issues and merge requests by replying to notification emails.
- [Migrate GitLab CI to CE/EE](migrate_ci_to_ce/README.md) Follow this guide to migrate your existing GitLab CI data to GitLab CE/EE. - [Migrate GitLab CI to CE/EE](migrate_ci_to_ce/README.md) Follow this guide to migrate your existing GitLab CI data to GitLab CE/EE.
### Administrator documentation
+ [User permissions](permissions/permissions.md)
+ [API](api/README.md)
## Contributor documentation ## Contributor documentation
- [Development](development/README.md) Explains the architecture and the guidelines for shell commands. - [Development](development/README.md) Explains the architecture and the guidelines for shell commands.
......
...@@ -332,7 +332,7 @@ GitLab Shell is an SSH access and repository management software developed speci ...@@ -332,7 +332,7 @@ GitLab Shell is an SSH access and repository management software developed speci
# Go to Gitlab installation folder # Go to Gitlab installation folder
cd /home/git/gilab cd /home/git/gitlab
sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production
......
...@@ -47,10 +47,11 @@ describe "Builds" do ...@@ -47,10 +47,11 @@ describe "Builds" do
end end
end end
describe "GET /:project/builds/:id/cancel_all" do describe "POST /:project/builds/:id/cancel_all" do
before do before do
@build.run! @build.run!
visit cancel_all_namespace_project_builds_path(@gl_project.namespace, @gl_project) visit namespace_project_builds_path(@gl_project.namespace, @gl_project)
click_link "Cancel all"
end end
it { expect(page).to have_content 'No builds to show' } it { expect(page).to have_content 'No builds to show' }
...@@ -67,10 +68,11 @@ describe "Builds" do ...@@ -67,10 +68,11 @@ describe "Builds" do
it { expect(page).to have_content @commit.git_author_name } it { expect(page).to have_content @commit.git_author_name }
end end
describe "GET /:project/builds/:id/cancel" do describe "POST /:project/builds/:id/cancel" do
before do before do
@build.run! @build.run!
visit cancel_namespace_project_build_path(@gl_project.namespace, @gl_project, @build) visit namespace_project_build_path(@gl_project.namespace, @gl_project, @build)
click_link "Cancel"
end end
it { expect(page).to have_content 'canceled' } it { expect(page).to have_content 'canceled' }
...@@ -79,7 +81,9 @@ describe "Builds" do ...@@ -79,7 +81,9 @@ describe "Builds" do
describe "POST /:project/builds/:id/retry" do describe "POST /:project/builds/:id/retry" do
before do before do
visit cancel_namespace_project_build_path(@gl_project.namespace, @gl_project, @build) @build.run!
visit namespace_project_build_path(@gl_project.namespace, @gl_project, @build)
click_link "Cancel"
click_link 'Retry' click_link 'Retry'
end end
......
...@@ -32,7 +32,7 @@ describe "Commits" do ...@@ -32,7 +32,7 @@ describe "Commits" do
describe "Cancel all builds" do describe "Cancel all builds" do
it "cancels commit" do it "cancels commit" do
visit ci_status_path(@commit) visit ci_status_path(@commit)
click_on "Cancel all" click_on "Cancel running"
expect(page).to have_content "canceled" expect(page).to have_content "canceled"
end end
end end
......
require 'spec_helper'
describe GroupsFinder do
let(:user) { create :user }
let!(:group) { create :group }
let!(:public_group) { create :group, public: true }
describe :execute do
it 'finds public group' do
groups = GroupsFinder.new.execute(user)
expect(groups.size).to eq(1)
expect(groups.first).to eq(public_group)
end
end
end
...@@ -42,6 +42,11 @@ describe SearchHelper do ...@@ -42,6 +42,11 @@ describe SearchHelper do
expect(search_autocomplete_opts(project.name).size).to eq(1) expect(search_autocomplete_opts(project.name).size).to eq(1)
end end
it "includes the public group" do
group = create(:group, public: true)
expect(search_autocomplete_opts(group.name).size).to eq(1)
end
context "with a current project" do context "with a current project" do
before { @project = create(:project) } before { @project = create(:project) }
......
...@@ -84,4 +84,23 @@ describe Group do ...@@ -84,4 +84,23 @@ describe Group do
expect(group.avatar_type).to eq(["only images allowed"]) expect(group.avatar_type).to eq(["only images allowed"])
end end
end end
describe "public_profile?" do
it "returns true for public group" do
group = create(:group, public: true)
expect(group.public_profile?).to be_truthy
end
it "returns true for non-public group with public project" do
group = create(:group)
create(:project, :public, group: group)
expect(group.public_profile?).to be_truthy
end
it "returns false for non-public group with no public projects" do
group = create(:group)
create(:project, group: group)
expect(group.public_profile?).to be_falsy
end
end
end end
...@@ -39,7 +39,7 @@ describe GitlabCiService do ...@@ -39,7 +39,7 @@ describe GitlabCiService do
end end
describe :build_page do describe :build_page do
it { expect(@service.build_page("2ab7834c", 'master')).to eq("http://localhost/#{@ci_project.gl_project.path_with_namespace}/commit/2ab7834c/ci")} it { expect(@service.build_page("2ab7834c", 'master')).to eq("http://localhost/#{@ci_project.gl_project.path_with_namespace}/commit/2ab7834c/builds")}
end end
describe "execute" do describe "execute" do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment