BigW Consortium Gitlab

Commit 076cdd20 by Valery Sizov

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into bitbucket-oauth2

parents c756e62b 6910bf29
...@@ -232,6 +232,7 @@ ...@@ -232,6 +232,7 @@
&:hover:not(.active) { &:hover:not(.active) {
background-color: $gray-lightest; background-color: $gray-lightest;
box-shadow: inset 2px 0 0 0 $border-color; box-shadow: inset 2px 0 0 0 $border-color;
cursor: pointer;
} }
&:first-child { &:first-child {
......
...@@ -4,25 +4,7 @@ module CiStatusHelper ...@@ -4,25 +4,7 @@ module CiStatusHelper
builds_namespace_project_commit_path(project.namespace, project, pipeline.sha) builds_namespace_project_commit_path(project.namespace, project, pipeline.sha)
end end
def ci_status_with_icon(status, target = nil) # Is used by Commit and Merge Request Widget
content = ci_icon_for_status(status) + ci_text_for_status(status)
klass = "ci-status ci-#{status}"
if target
link_to content, target, class: klass
else
content_tag :span, content, class: klass
end
end
def ci_text_for_status(status)
if detailed_status?(status)
status.text
else
status
end
end
def ci_label_for_status(status) def ci_label_for_status(status)
if detailed_status?(status) if detailed_status?(status)
return status.label return status.label
......
...@@ -100,6 +100,12 @@ module Ci ...@@ -100,6 +100,12 @@ module Ci
end end
end end
def detailed_status(current_user)
Gitlab::Ci::Status::Build::Factory
.new(self, current_user)
.fabricate!
end
def manual? def manual?
self.when == 'manual' self.when == 'manual'
end end
...@@ -123,8 +129,13 @@ module Ci ...@@ -123,8 +129,13 @@ module Ci
end end
end end
def cancelable?
active?
end
def retryable? def retryable?
project.builds_enabled? && commands.present? && complete? project.builds_enabled? && commands.present? &&
(success? || failed? || canceled?)
end end
def retried? def retried?
...@@ -148,7 +159,7 @@ module Ci ...@@ -148,7 +159,7 @@ module Ci
end end
def environment_action def environment_action
self.options.fetch(:environment, {}).fetch(:action, 'start') self.options.fetch(:environment, {}).fetch(:action, 'start') if self.options
end end
def outdated_deployment? def outdated_deployment?
......
...@@ -336,8 +336,10 @@ module Ci ...@@ -336,8 +336,10 @@ module Ci
.select { |merge_request| merge_request.head_pipeline.try(:id) == self.id } .select { |merge_request| merge_request.head_pipeline.try(:id) == self.id }
end end
def detailed_status def detailed_status(current_user)
Gitlab::Ci::Status::Pipeline::Factory.new(self).fabricate! Gitlab::Ci::Status::Pipeline::Factory
.new(self, current_user)
.fabricate!
end end
private private
......
...@@ -22,8 +22,10 @@ module Ci ...@@ -22,8 +22,10 @@ module Ci
@status ||= statuses.latest.status @status ||= statuses.latest.status
end end
def detailed_status def detailed_status(current_user)
Gitlab::Ci::Status::Stage::Factory.new(self).fabricate! Gitlab::Ci::Status::Stage::Factory
.new(self, current_user)
.fabricate!
end end
def statuses def statuses
......
...@@ -131,4 +131,10 @@ class CommitStatus < ActiveRecord::Base ...@@ -131,4 +131,10 @@ class CommitStatus < ActiveRecord::Base
def has_trace? def has_trace?
false false
end end
def detailed_status(current_user)
Gitlab::Ci::Status::Factory
.new(self, current_user)
.fabricate!
end
end end
...@@ -17,14 +17,13 @@ class Namespace < ActiveRecord::Base ...@@ -17,14 +17,13 @@ class Namespace < ActiveRecord::Base
validates :owner, presence: true, unless: ->(n) { n.type == "Group" } validates :owner, presence: true, unless: ->(n) { n.type == "Group" }
validates :name, validates :name,
presence: true, presence: true,
uniqueness: true, uniqueness: { scope: :parent_id },
length: { maximum: 255 }, length: { maximum: 255 },
namespace_name: true namespace_name: true
validates :description, length: { maximum: 255 } validates :description, length: { maximum: 255 }
validates :path, validates :path,
presence: true, presence: true,
uniqueness: { case_sensitive: false },
length: { maximum: 255 }, length: { maximum: 255 },
namespace: true namespace: true
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
%span %span
Overview Overview
= nav_link(controller: [:admin, :projects]) do = nav_link(controller: [:admin, :projects]) do
= link_to admin_namespaces_projects_path, title: 'Projects' do = link_to admin_projects_path, title: 'Projects' do
%span %span
Projects Projects
= nav_link(controller: :users) do = nav_link(controller: :users) do
......
...@@ -116,7 +116,7 @@ ...@@ -116,7 +116,7 @@
.light-well.well-centered .light-well.well-centered
%h4 Projects %h4 Projects
.data .data
= link_to admin_namespaces_projects_path do = link_to admin_projects_path do
%h1= number_with_delimiter(Project.cached_count) %h1= number_with_delimiter(Project.cached_count)
%hr %hr
= link_to('New Project', new_project_path, class: "btn btn-new") = link_to('New Project', new_project_path, class: "btn btn-new")
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
%li.group-row{ class: css_class } %li.group-row{ class: css_class }
.controls .controls
= link_to 'Edit', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: 'btn' = link_to 'Edit', admin_group_edit_path(group), id: "edit_#{dom_id(group)}", class: 'btn'
= link_to 'Delete', [:admin, group], data: { confirm: "Are you sure you want to remove #{group.name}?" }, method: :delete, class: 'btn btn-remove' = link_to 'Delete', [:admin, group], data: { confirm: "Are you sure you want to remove #{group.name}?" }, method: :delete, class: 'btn btn-remove'
.stats .stats
%span %span
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
%h3.page-title %h3.page-title
Group: #{@group.name} Group: #{@group.name}
= link_to edit_admin_group_path(@group), class: "btn pull-right" do = link_to admin_group_edit_path(@group), class: "btn pull-right" do
%i.fa.fa-pencil-square-o %i.fa.fa-pencil-square-o
Edit Edit
%hr %hr
...@@ -88,7 +88,7 @@ ...@@ -88,7 +88,7 @@
Read more about project permissions Read more about project permissions
%strong= link_to "here", help_page_path("user/permissions"), class: "vlink" %strong= link_to "here", help_page_path("user/permissions"), class: "vlink"
= form_tag members_update_admin_group_path(@group), id: "new_project_member", class: "bulk_import", method: :put do = form_tag admin_group_members_update_path(@group), id: "new_project_member", class: "bulk_import", method: :put do
%div %div
= users_select_tag(:user_ids, multiple: true, email_user: true, scope: :all) = users_select_tag(:user_ids, multiple: true, email_user: true, scope: :all)
%div.prepend-top-10 %div.prepend-top-10
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
%div{ class: container_class } %div{ class: container_class }
.top-area .top-area
.prepend-top-default .prepend-top-default
= form_tag admin_namespaces_projects_path, method: :get do |f| = form_tag admin_projects_path, method: :get do |f|
.search-holder .search-holder
.search-field-holder .search-field-holder
= search_field_tag :name, params[:name], class: "form-control search-text-input js-search-input", id: "dashboard_search", autofocus: true, spellcheck: false, placeholder: 'Search by name' = search_field_tag :name, params[:name], class: "form-control search-text-input js-search-input", id: "dashboard_search", autofocus: true, spellcheck: false, placeholder: 'Search by name'
...@@ -41,19 +41,19 @@ ...@@ -41,19 +41,19 @@
= button_tag "Search", class: "btn btn-primary btn-search" = button_tag "Search", class: "btn btn-primary btn-search"
%ul.nav-links %ul.nav-links
- opts = params[:visibility_level].present? ? {} : { page: admin_namespaces_projects_path } - opts = params[:visibility_level].present? ? {} : { page: admin_projects_path }
= nav_link(opts) do = nav_link(opts) do
= link_to admin_namespaces_projects_path do = link_to admin_projects_path do
All All
= nav_link(html_options: { class: params[:visibility_level] == Gitlab::VisibilityLevel::PRIVATE.to_s ? 'active' : '' }) do = nav_link(html_options: { class: params[:visibility_level] == Gitlab::VisibilityLevel::PRIVATE.to_s ? 'active' : '' }) do
= link_to admin_namespaces_projects_path(visibility_level: Gitlab::VisibilityLevel::PRIVATE) do = link_to admin_projects_path(visibility_level: Gitlab::VisibilityLevel::PRIVATE) do
Private Private
= nav_link(html_options: { class: params[:visibility_level] == Gitlab::VisibilityLevel::INTERNAL.to_s ? 'active' : '' }) do = nav_link(html_options: { class: params[:visibility_level] == Gitlab::VisibilityLevel::INTERNAL.to_s ? 'active' : '' }) do
= link_to admin_namespaces_projects_path(visibility_level: Gitlab::VisibilityLevel::INTERNAL) do = link_to admin_projects_path(visibility_level: Gitlab::VisibilityLevel::INTERNAL) do
Internal Internal
= nav_link(html_options: { class: params[:visibility_level] == Gitlab::VisibilityLevel::PUBLIC.to_s ? 'active' : '' }) do = nav_link(html_options: { class: params[:visibility_level] == Gitlab::VisibilityLevel::PUBLIC.to_s ? 'active' : '' }) do
= link_to admin_namespaces_projects_path(visibility_level: Gitlab::VisibilityLevel::PUBLIC) do = link_to admin_projects_path(visibility_level: Gitlab::VisibilityLevel::PUBLIC) do
Public Public
.nav-controls .nav-controls
......
...@@ -91,7 +91,7 @@ ...@@ -91,7 +91,7 @@
%strong ##{build.id} %strong ##{build.id}
%td.status %td.status
= ci_status_with_icon(build.status) = render 'ci/status/badge', status: build.detailed_status(current_user)
%td.status %td.status
- if project - if project
......
- status = local_assigns.fetch(:status)
- if status.has_details?
= link_to status.details_path, class: "ci-status ci-#{status}" do
= custom_icon(status.icon)
= status.text
- else
%span{ class: "ci-status ci-#{status}" }
= custom_icon(status.icon)
= status.text
.content-block.build-header .content-block.build-header
.header-content .header-content
= ci_status_with_icon(@build.status) = render 'ci/status/badge', status: @build.detailed_status(current_user)
Build Build
%strong ##{@build.id} %strong ##{@build.id}
in pipeline in pipeline
......
...@@ -9,10 +9,7 @@ ...@@ -9,10 +9,7 @@
%tr.build.commit{class: ('retried' if retried)} %tr.build.commit{class: ('retried' if retried)}
%td.status %td.status
- if can?(current_user, :read_build, build) = render "ci/status/badge", status: build.detailed_status(current_user)
= ci_status_with_icon(build.status, namespace_project_build_url(build.project.namespace, build.project, build))
- else
= ci_status_with_icon(build.status)
%td.branch-commit %td.branch-commit
- if can?(current_user, :read_build, build) - if can?(current_user, :read_build, build)
......
- status = pipeline.status - status = pipeline.status
- detailed_status = pipeline.detailed_status
- show_commit = local_assigns.fetch(:show_commit, true) - show_commit = local_assigns.fetch(:show_commit, true)
- show_branch = local_assigns.fetch(:show_branch, true) - show_branch = local_assigns.fetch(:show_branch, true)
%tr.commit %tr.commit
%td.commit-link %td.commit-link
= link_to namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id), class: "ci-status ci-#{detailed_status}" do = render 'ci/status/badge', status: pipeline.detailed_status(current_user)
= ci_icon_for_status(detailed_status)
= ci_text_for_status(detailed_status)
%td %td
= link_to namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id) do = link_to namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id) do
......
...@@ -8,10 +8,7 @@ ...@@ -8,10 +8,7 @@
%tr.generic_commit_status{class: ('retried' if retried)} %tr.generic_commit_status{class: ('retried' if retried)}
%td.status %td.status
- if can?(current_user, :read_commit_status, generic_commit_status) && generic_commit_status.target_url = render 'ci/status/badge', status: generic_commit_status.detailed_status(current_user)
= ci_status_with_icon(generic_commit_status.status, generic_commit_status.target_url)
- else
= ci_status_with_icon(generic_commit_status.status)
%td.generic_commit_status-link %td.generic_commit_status-link
- if can?(current_user, :read_commit_status, generic_commit_status) && generic_commit_status.target_url - if can?(current_user, :read_commit_status, generic_commit_status) && generic_commit_status.target_url
......
.page-content-header .page-content-header
.header-main-content .header-main-content
= ci_status_with_icon(@pipeline.detailed_status) = render 'ci/status/badge', status: @pipeline.detailed_status(current_user)
%strong Pipeline ##{@commit.pipelines.last.id} %strong Pipeline ##{@commit.pipelines.last.id}
triggered #{time_ago_with_tooltip(@commit.authored_date)} by triggered #{time_ago_with_tooltip(@commit.authored_date)} by
= author_avatar(@commit, size: 24) = author_avatar(@commit, size: 24)
......
...@@ -19,4 +19,4 @@ ...@@ -19,4 +19,4 @@
%li.build %li.build
.curve .curve
.dropdown.inline.build-content .dropdown.inline.build-content
= render "projects/stage/in_stage_group", name: group_name, subject: grouped_statuses = render 'projects/stage/in_stage_group', name: group_name, subject: grouped_statuses
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
#{@message}. #{@message}.
%p %p
= link_to "See the affected projects in the GitLab admin panel", admin_namespaces_projects_url(last_repository_check_failed: 1) = link_to "See the affected projects in the GitLab admin panel", admin_projects_url(last_repository_check_failed: 1)
%p %p
You are receiving this message because you are a GitLab administrator for #{Gitlab.config.gitlab.url}. You are receiving this message because you are a GitLab administrator for #{Gitlab.config.gitlab.url}.
#{@message}. #{@message}.
\ \
View details: #{admin_namespaces_projects_url(last_repository_check_failed: 1)} View details: #{admin_projects_url(last_repository_check_failed: 1)}
You are receiving this message because you are a GitLab administrator You are receiving this message because you are a GitLab administrator
for #{Gitlab.config.gitlab.url}. for #{Gitlab.config.gitlab.url}.
<svg width="14" height="14" viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="M0 7a7 7 0 1 1 14 0A7 7 0 0 1 0 7z"/><path d="M13 7A6 6 0 1 0 1 7a6 6 0 0 0 12 0z" fill="#FFF"/><path d="M10.5 7.63V6.37l-.787-.13c-.044-.175-.132-.349-.263-.61l.481-.652-.918-.913-.657.478a2.346 2.346 0 0 0-.612-.26L7.656 3.5H6.388l-.132.783c-.219.043-.394.13-.612.26l-.657-.478-.918.913.437.652c-.131.218-.175.392-.262.61l-.744.086v1.261l.787.13c.044.218.132.392.263.61l-.438.651.92.913.655-.434c.175.086.394.173.613.26l.131.783h1.313l.131-.783c.219-.043.394-.13.613-.26l.656.478.918-.913-.48-.652c.13-.218.218-.435.262-.61l.656-.13zM7 8.283a1.285 1.285 0 0 1-1.313-1.305c0-.739.57-1.304 1.313-1.304.744 0 1.313.565 1.313 1.304 0 .74-.57 1.305-1.313 1.305z"/></g></svg>
---
title: Changed cursor icon to pointer when mousing over stages on the Cycle Analytics
pages
merge_request:
author: Ryan Harris
---
title: Adds tests for custom event polyfill
merge_request: 7996
author:
...@@ -28,9 +28,19 @@ namespace :admin do ...@@ -28,9 +28,19 @@ namespace :admin do
resources :applications resources :applications
resources :groups, constraints: { id: /[^\/]+/ } do resources :groups, only: [:index, :new, :create]
member do
scope(path: 'groups/*id',
controller: :groups,
constraints: { id: Gitlab::Regex.namespace_route_regex }) do
scope(as: :group) do
put :members_update put :members_update
get :edit, action: :edit
get '/', action: :show
patch '/', action: :update
put '/', action: :update
delete '/', action: :destroy
end end
end end
...@@ -50,14 +60,13 @@ namespace :admin do ...@@ -50,14 +60,13 @@ namespace :admin do
resource :system_info, controller: 'system_info', only: [:show] resource :system_info, controller: 'system_info', only: [:show]
resources :requests_profiles, only: [:index, :show], param: :name, constraints: { name: /.+\.html/ } resources :requests_profiles, only: [:index, :show], param: :name, constraints: { name: /.+\.html/ }
resources :namespaces, path: '/projects', constraints: { id: /[a-zA-Z.0-9_\-]+/ }, only: [] do resources :projects, only: [:index]
root to: 'projects#index', as: :projects
scope(path: 'projects/*namespace_id', as: :namespace) do
resources(:projects, resources(:projects,
path: '/', path: '/',
constraints: { id: /[a-zA-Z.0-9_\-]+/ }, constraints: { id: Gitlab::Regex.project_route_regex },
only: [:index, :show]) do only: [:show]) do
root to: 'projects#show'
member do member do
put :transfer put :transfer
......
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class RemoveUniqPathIndexFromNamespace < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
DOWNTIME = false
def up
constraint_name = 'namespaces_path_key'
transaction do
if index_exists?(:namespaces, :path)
remove_index(:namespaces, :path)
end
# In some bizarre cases PostgreSQL might have a separate unique constraint
# that we'll need to drop.
if constraint_exists?(constraint_name) && Gitlab::Database.postgresql?
execute("ALTER TABLE namespaces DROP CONSTRAINT IF EXISTS #{constraint_name};")
end
end
end
def down
unless index_exists?(:namespaces, :path)
add_concurrent_index(:namespaces, :path, unique: true)
end
end
def constraint_exists?(name)
indexes(:namespaces).map(&:name).include?(name)
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddPathIndexToNamespace < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
DOWNTIME = false
def up
add_concurrent_index :namespaces, :path
end
def down
if index_exists?(:namespaces, :path)
remove_index :namespaces, :path
end
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class RemoveUniqNameIndexFromNamespace < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
DOWNTIME = false
def up
constraint_name = 'namespaces_name_key'
transaction do
if index_exists?(:namespaces, :name)
remove_index(:namespaces, :name)
end
# In some bizarre cases PostgreSQL might have a separate unique constraint
# that we'll need to drop.
if constraint_exists?(constraint_name) && Gitlab::Database.postgresql?
execute("ALTER TABLE namespaces DROP CONSTRAINT IF EXISTS #{constraint_name};")
end
end
end
def down
unless index_exists?(:namespaces, :name)
add_concurrent_index(:namespaces, :name, unique: true)
end
end
def constraint_exists?(name)
indexes(:namespaces).map(&:name).include?(name)
end
end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddNameIndexToNamespace < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
DOWNTIME = false
def up
add_concurrent_index(:namespaces, [:name, :parent_id], unique: true)
end
def down
if index_exists?(:namespaces, :name)
remove_index :namespaces, [:name, :parent_id]
end
end
end
...@@ -744,11 +744,11 @@ ActiveRecord::Schema.define(version: 20161212142807) do ...@@ -744,11 +744,11 @@ ActiveRecord::Schema.define(version: 20161212142807) do
add_index "namespaces", ["created_at"], name: "index_namespaces_on_created_at", using: :btree add_index "namespaces", ["created_at"], name: "index_namespaces_on_created_at", using: :btree
add_index "namespaces", ["deleted_at"], name: "index_namespaces_on_deleted_at", using: :btree add_index "namespaces", ["deleted_at"], name: "index_namespaces_on_deleted_at", using: :btree
add_index "namespaces", ["name"], name: "index_namespaces_on_name", unique: true, using: :btree add_index "namespaces", ["name", "parent_id"], name: "index_namespaces_on_name_and_parent_id", unique: true, using: :btree
add_index "namespaces", ["name"], name: "index_namespaces_on_name_trigram", using: :gin, opclasses: {"name"=>"gin_trgm_ops"} add_index "namespaces", ["name"], name: "index_namespaces_on_name_trigram", using: :gin, opclasses: {"name"=>"gin_trgm_ops"}
add_index "namespaces", ["owner_id"], name: "index_namespaces_on_owner_id", using: :btree add_index "namespaces", ["owner_id"], name: "index_namespaces_on_owner_id", using: :btree
add_index "namespaces", ["parent_id", "id"], name: "index_namespaces_on_parent_id_and_id", unique: true, using: :btree add_index "namespaces", ["parent_id", "id"], name: "index_namespaces_on_parent_id_and_id", unique: true, using: :btree
add_index "namespaces", ["path"], name: "index_namespaces_on_path", unique: true, using: :btree add_index "namespaces", ["path"], name: "index_namespaces_on_path", using: :btree
add_index "namespaces", ["path"], name: "index_namespaces_on_path_trigram", using: :gin, opclasses: {"path"=>"gin_trgm_ops"} add_index "namespaces", ["path"], name: "index_namespaces_on_path_trigram", using: :gin, opclasses: {"path"=>"gin_trgm_ops"}
add_index "namespaces", ["type"], name: "index_namespaces_on_type", using: :btree add_index "namespaces", ["type"], name: "index_namespaces_on_type", using: :btree
...@@ -1290,4 +1290,4 @@ ActiveRecord::Schema.define(version: 20161212142807) do ...@@ -1290,4 +1290,4 @@ ActiveRecord::Schema.define(version: 20161212142807) do
add_foreign_key "subscriptions", "projects", on_delete: :cascade add_foreign_key "subscriptions", "projects", on_delete: :cascade
add_foreign_key "trending_projects", "projects", on_delete: :cascade add_foreign_key "trending_projects", "projects", on_delete: :cascade
add_foreign_key "u2f_registrations", "users" add_foreign_key "u2f_registrations", "users"
end end
\ No newline at end of file
...@@ -72,7 +72,7 @@ sudo -u git -H git checkout 8-14-stable-ee ...@@ -72,7 +72,7 @@ sudo -u git -H git checkout 8-14-stable-ee
```bash ```bash
cd /home/git/gitlab-shell cd /home/git/gitlab-shell
sudo -u git -H git fetch --all --tags sudo -u git -H git fetch --all --tags
sudo -u git -H git checkout v4.0.0 sudo -u git -H git checkout v4.0.3
``` ```
### 6. Update gitlab-workhorse ### 6. Update gitlab-workhorse
......
...@@ -168,7 +168,7 @@ module SharedPaths ...@@ -168,7 +168,7 @@ module SharedPaths
end end
step 'I visit admin projects page' do step 'I visit admin projects page' do
visit admin_namespaces_projects_path visit admin_projects_path
end end
step 'I visit admin users page' do step 'I visit admin users page' do
......
module Gitlab
module Allowable
def can?(user, action, subject)
Ability.allowed?(user, action, subject)
end
end
end
module Gitlab
module Ci
module Status
module Build
class Cancelable < SimpleDelegator
include Status::Extended
def has_action?
can?(user, :update_build, subject)
end
def action_icon
'ban'
end
def action_path
cancel_namespace_project_build_path(subject.project.namespace,
subject.project,
subject)
end
def action_method
:post
end
def action_title
'Cancel'
end
def self.matches?(build, user)
build.cancelable?
end
end
end
end
end
end
module Gitlab
module Ci
module Status
module Build
module Common
def has_details?
can?(user, :read_build, subject)
end
def details_path
namespace_project_build_path(subject.project.namespace,
subject.project,
subject)
end
end
end
end
end
end
module Gitlab
module Ci
module Status
module Build
class Factory < Status::Factory
def self.extended_statuses
[Status::Build::Stop, Status::Build::Play,
Status::Build::Cancelable, Status::Build::Retryable]
end
def self.common_helpers
Status::Build::Common
end
end
end
end
end
end
module Gitlab
module Ci
module Status
module Build
class Play < SimpleDelegator
include Status::Extended
def text
'manual'
end
def label
'manual play action'
end
def icon
'icon_status_manual'
end
def has_action?
can?(user, :update_build, subject)
end
def action_icon
'play'
end
def action_title
'Play'
end
def action_class
'ci-play-icon'
end
def action_path
play_namespace_project_build_path(subject.project.namespace,
subject.project,
subject)
end
def action_method
:post
end
def self.matches?(build, user)
build.playable? && !build.stops_environment?
end
end
end
end
end
end
module Gitlab
module Ci
module Status
module Build
class Retryable < SimpleDelegator
include Status::Extended
def has_action?
can?(user, :update_build, subject)
end
def action_icon
'refresh'
end
def action_title
'Retry'
end
def action_path
retry_namespace_project_build_path(subject.project.namespace,
subject.project,
subject)
end
def action_method
:post
end
def self.matches?(build, user)
build.retryable?
end
end
end
end
end
end
module Gitlab
module Ci
module Status
module Build
class Stop < SimpleDelegator
include Status::Extended
def text
'manual'
end
def label
'manual stop action'
end
def icon
'icon_status_manual'
end
def has_action?
can?(user, :update_build, subject)
end
def action_icon
'stop'
end
def action_title
'Stop'
end
def action_path
play_namespace_project_build_path(subject.project.namespace,
subject.project,
subject)
end
def action_method
:post
end
def self.matches?(build, user)
build.playable? && build.stops_environment?
end
end
end
end
end
end
...@@ -4,10 +4,14 @@ module Gitlab ...@@ -4,10 +4,14 @@ module Gitlab
# Base abstract class fore core status # Base abstract class fore core status
# #
class Core class Core
include Gitlab::Routing.url_helpers include Gitlab::Routing
include Gitlab::Allowable
def initialize(subject) attr_reader :subject, :user
def initialize(subject, user)
@subject = subject @subject = subject
@user = user
end end
def icon def icon
...@@ -18,10 +22,6 @@ module Gitlab ...@@ -18,10 +22,6 @@ module Gitlab
raise NotImplementedError raise NotImplementedError
end end
def title
"#{@subject.class.name.demodulize}: #{label}"
end
# Deprecation warning: this method is here because we need to maintain # Deprecation warning: this method is here because we need to maintain
# backwards compatibility with legacy statuses. We often do something # backwards compatibility with legacy statuses. We often do something
# like "ci-status ci-status-#{status}" to set CSS class. # like "ci-status ci-status-#{status}" to set CSS class.
...@@ -34,7 +34,7 @@ module Gitlab ...@@ -34,7 +34,7 @@ module Gitlab
end end
def has_details? def has_details?
raise NotImplementedError false
end end
def details_path def details_path
...@@ -42,16 +42,27 @@ module Gitlab ...@@ -42,16 +42,27 @@ module Gitlab
end end
def has_action? def has_action?
raise NotImplementedError false
end end
def action_icon def action_icon
raise NotImplementedError raise NotImplementedError
end end
def action_class
end
def action_path def action_path
raise NotImplementedError raise NotImplementedError
end end
def action_method
raise NotImplementedError
end
def action_title
raise NotImplementedError
end
end end
end end
end end
......
...@@ -2,8 +2,12 @@ module Gitlab ...@@ -2,8 +2,12 @@ module Gitlab
module Ci module Ci
module Status module Status
module Extended module Extended
def matches?(_subject) extend ActiveSupport::Concern
raise NotImplementedError
class_methods do
def matches?(_subject, _user)
raise NotImplementedError
end
end end
end end
end end
......
...@@ -2,10 +2,9 @@ module Gitlab ...@@ -2,10 +2,9 @@ module Gitlab
module Ci module Ci
module Status module Status
class Factory class Factory
attr_reader :subject def initialize(subject, user)
def initialize(subject)
@subject = subject @subject = subject
@user = user
end end
def fabricate! def fabricate!
...@@ -16,27 +15,32 @@ module Gitlab ...@@ -16,27 +15,32 @@ module Gitlab
end end
end end
def self.extended_statuses
[]
end
def self.common_helpers
Module.new
end
private private
def subject_status def simple_status
@subject_status ||= subject.status @simple_status ||= @subject.status || :created
end end
def core_status def core_status
Gitlab::Ci::Status Gitlab::Ci::Status
.const_get(subject_status.capitalize) .const_get(simple_status.capitalize)
.new(subject) .new(@subject, @user)
.extend(self.class.common_helpers)
end end
def extended_status def extended_status
@extended ||= extended_statuses.find do |status| @extended ||= self.class.extended_statuses.find do |status|
status.matches?(subject) status.matches?(@subject, @user)
end end
end end
def extended_statuses
[]
end
end end
end end
end end
......
...@@ -4,13 +4,13 @@ module Gitlab ...@@ -4,13 +4,13 @@ module Gitlab
module Pipeline module Pipeline
module Common module Common
def has_details? def has_details?
true can?(user, :read_pipeline, subject)
end end
def details_path def details_path
namespace_project_pipeline_path(@subject.project.namespace, namespace_project_pipeline_path(subject.project.namespace,
@subject.project, subject.project,
@subject) subject)
end end
def has_action? def has_action?
......
...@@ -3,14 +3,12 @@ module Gitlab ...@@ -3,14 +3,12 @@ module Gitlab
module Status module Status
module Pipeline module Pipeline
class Factory < Status::Factory class Factory < Status::Factory
private def self.extended_statuses
def extended_statuses
[Pipeline::SuccessWithWarnings] [Pipeline::SuccessWithWarnings]
end end
def core_status def self.common_helpers
super.extend(Status::Pipeline::Common) Status::Pipeline::Common
end end
end end
end end
......
...@@ -3,7 +3,7 @@ module Gitlab ...@@ -3,7 +3,7 @@ module Gitlab
module Status module Status
module Pipeline module Pipeline
class SuccessWithWarnings < SimpleDelegator class SuccessWithWarnings < SimpleDelegator
extend Status::Extended include Status::Extended
def text def text
'passed' 'passed'
...@@ -21,7 +21,7 @@ module Gitlab ...@@ -21,7 +21,7 @@ module Gitlab
'success_with_warnings' 'success_with_warnings'
end end
def self.matches?(pipeline) def self.matches?(pipeline, user)
pipeline.success? && pipeline.has_warnings? pipeline.success? && pipeline.has_warnings?
end end
end end
......
...@@ -4,14 +4,14 @@ module Gitlab ...@@ -4,14 +4,14 @@ module Gitlab
module Stage module Stage
module Common module Common
def has_details? def has_details?
true can?(user, :read_pipeline, subject.pipeline)
end end
def details_path def details_path
namespace_project_pipeline_path(@subject.project.namespace, namespace_project_pipeline_path(subject.project.namespace,
@subject.project, subject.project,
@subject.pipeline, subject.pipeline,
anchor: @subject.name) anchor: subject.name)
end end
def has_action? def has_action?
......
...@@ -3,10 +3,8 @@ module Gitlab ...@@ -3,10 +3,8 @@ module Gitlab
module Status module Status
module Stage module Stage
class Factory < Status::Factory class Factory < Status::Factory
private def self.common_helpers
Status::Stage::Common
def core_status
super.extend(Status::Stage::Common)
end end
end end
end end
......
module Gitlab module Gitlab
module Routing module Routing
extend ActiveSupport::Concern
included do
include Gitlab::Routing.url_helpers
end
# Returns the URL helpers Module. # Returns the URL helpers Module.
# #
# This method caches the output as Rails' "url_helpers" method creates an # This method caches the output as Rails' "url_helpers" method creates an
......
...@@ -12,12 +12,14 @@ FactoryGirl.define do ...@@ -12,12 +12,14 @@ FactoryGirl.define do
started_at 'Di 29. Okt 09:51:28 CET 2013' started_at 'Di 29. Okt 09:51:28 CET 2013'
finished_at 'Di 29. Okt 09:53:28 CET 2013' finished_at 'Di 29. Okt 09:53:28 CET 2013'
commands 'ls -a' commands 'ls -a'
options do options do
{ {
image: "ruby:2.1", image: "ruby:2.1",
services: ["postgres"] services: ["postgres"]
} }
end end
yaml_variables do yaml_variables do
[ [
{ key: :DB_NAME, value: 'postgres', public: true } { key: :DB_NAME, value: 'postgres', public: true }
...@@ -60,15 +62,20 @@ FactoryGirl.define do ...@@ -60,15 +62,20 @@ FactoryGirl.define do
end end
trait :teardown_environment do trait :teardown_environment do
options do environment 'staging'
{ environment: { action: 'stop' } } options environment: { name: 'staging',
end action: 'stop' }
end end
trait :allowed_to_fail do trait :allowed_to_fail do
allow_failure true allow_failure true
end end
trait :playable do
skipped
manual
end
after(:build) do |build, evaluator| after(:build) do |build, evaluator|
build.project = build.pipeline.project build.project = build.pipeline.project
end end
......
...@@ -21,7 +21,7 @@ feature 'Admin Groups', feature: true do ...@@ -21,7 +21,7 @@ feature 'Admin Groups', feature: true do
scenario 'shows the visibility level radio populated with the group visibility_level value' do scenario 'shows the visibility level radio populated with the group visibility_level value' do
group = create(:group, :private) group = create(:group, :private)
visit edit_admin_group_path(group) visit admin_group_edit_path(group)
expect_selected_visibility(group.visibility_level) expect_selected_visibility(group.visibility_level)
end end
......
...@@ -8,11 +8,11 @@ describe "Admin::Projects", feature: true do ...@@ -8,11 +8,11 @@ describe "Admin::Projects", feature: true do
describe "GET /admin/projects" do describe "GET /admin/projects" do
before do before do
visit admin_namespaces_projects_path visit admin_projects_path
end end
it "is ok" do it "is ok" do
expect(current_path).to eq(admin_namespaces_projects_path) expect(current_path).to eq(admin_projects_path)
end end
it "has projects list" do it "has projects list" do
...@@ -22,7 +22,7 @@ describe "Admin::Projects", feature: true do ...@@ -22,7 +22,7 @@ describe "Admin::Projects", feature: true do
describe "GET /admin/projects/:id" do describe "GET /admin/projects/:id" do
before do before do
visit admin_namespaces_projects_path visit admin_projects_path
click_link "#{@project.name}" click_link "#{@project.name}"
end end
......
...@@ -4,7 +4,7 @@ describe "Admin::Projects", feature: true do ...@@ -4,7 +4,7 @@ describe "Admin::Projects", feature: true do
include AccessMatchers include AccessMatchers
describe "GET /admin/projects" do describe "GET /admin/projects" do
subject { admin_namespaces_projects_path } subject { admin_projects_path }
it { is_expected.to be_allowed_for :admin } it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for :user } it { is_expected.to be_denied_for :user }
......
//= require lib/utils/custom_event_polyfill
describe('Custom Event Polyfill', () => {
it('should be defined', () => {
expect(window.CustomEvent).toBeDefined();
});
it('should create a `CustomEvent` instance', () => {
const e = new window.CustomEvent('foo');
expect(e.type).toEqual('foo');
expect(e.bubbles).toBe(false);
expect(e.cancelable).toBe(false);
expect(e.detail).toBeFalsy();
});
it('should create a `CustomEvent` instance with a `details` object', () => {
const e = new window.CustomEvent('bar', { detail: { foo: 'bar' } });
expect(e.type).toEqual('bar');
expect(e.bubbles).toBe(false);
expect(e.cancelable).toBe(false);
expect(e.detail.foo).toEqual('bar');
});
it('should create a `CustomEvent` instance with a `bubbles` boolean', () => {
const e = new window.CustomEvent('bar', { bubbles: true });
expect(e.type).toEqual('bar');
expect(e.bubbles).toBe(true);
expect(e.cancelable).toBe(false);
expect(e.detail).toBeFalsy();
});
it('should create a `CustomEvent` instance with a `cancelable` boolean', () => {
const e = new window.CustomEvent('bar', { cancelable: true });
expect(e.type).toEqual('bar');
expect(e.bubbles).toBe(false);
expect(e.cancelable).toBe(true);
expect(e.detail).toBeFalsy();
});
});
require 'spec_helper'
describe Gitlab::Allowable do
subject do
Class.new.include(described_class).new
end
describe '#can?' do
let(:user) { create(:user) }
context 'when user is allowed to do something' do
let(:project) { create(:empty_project, :public) }
it 'reports correct ability to perform action' do
expect(subject.can?(user, :read_project, project)).to be true
end
end
context 'when user is not allowed to do something' do
let(:project) { create(:empty_project, :private) }
it 'reports correct ability to perform action' do
expect(subject.can?(user, :read_project, project)).to be false
end
end
end
end
require 'spec_helper'
describe Gitlab::Ci::Status::Build::Cancelable do
let(:status) { double('core status') }
let(:user) { double('user') }
subject do
described_class.new(status)
end
describe '#text' do
it 'does not override status text' do
expect(status).to receive(:text)
subject.text
end
end
describe '#icon' do
it 'does not override status icon' do
expect(status).to receive(:icon)
subject.icon
end
end
describe '#label' do
it 'does not override status label' do
expect(status).to receive(:label)
subject.label
end
end
describe 'action details' do
let(:user) { create(:user) }
let(:build) { create(:ci_build) }
let(:status) { Gitlab::Ci::Status::Core.new(build, user) }
describe '#has_action?' do
context 'when user is allowed to update build' do
before { build.project.team << [user, :developer] }
it { is_expected.to have_action }
end
context 'when user is not allowed to update build' do
it { is_expected.not_to have_action }
end
end
describe '#action_path' do
it { expect(subject.action_path).to include "#{build.id}/cancel" }
end
describe '#action_icon' do
it { expect(subject.action_icon).to eq 'ban' }
end
describe '#action_title' do
it { expect(subject.action_title).to eq 'Cancel' }
end
end
describe '.matches?' do
subject { described_class.matches?(build, user) }
context 'when build is cancelable' do
let(:build) do
create(:ci_build, :running)
end
it 'is a correct match' do
expect(subject).to be true
end
end
context 'when build is not cancelable' do
let(:build) { create(:ci_build, :success) }
it 'does not match' do
expect(subject).to be false
end
end
end
end
require 'spec_helper'
describe Gitlab::Ci::Status::Build::Common do
let(:user) { create(:user) }
let(:build) { create(:ci_build) }
let(:project) { build.project }
subject do
Gitlab::Ci::Status::Core
.new(build, user)
.extend(described_class)
end
describe '#has_action?' do
it { is_expected.not_to have_action }
end
describe '#has_details?' do
context 'when user has access to read build' do
before { project.team << [user, :developer] }
it { is_expected.to have_details }
end
context 'when user does not have access to read build' do
before { project.update(public_builds: false) }
it { is_expected.not_to have_details }
end
end
describe '#details_path' do
it 'links to the build details page' do
expect(subject.details_path).to include "builds/#{build.id}"
end
end
end
require 'spec_helper'
describe Gitlab::Ci::Status::Build::Factory do
let(:user) { create(:user) }
let(:project) { build.project }
subject { described_class.new(build, user) }
let(:status) { subject.fabricate! }
before { project.team << [user, :developer] }
context 'when build is successful' do
let(:build) { create(:ci_build, :success) }
it 'fabricates a retryable build status' do
expect(status).to be_a Gitlab::Ci::Status::Build::Retryable
end
it 'fabricates status with correct details' do
expect(status.text).to eq 'passed'
expect(status.icon).to eq 'icon_status_success'
expect(status.label).to eq 'passed'
expect(status).to have_details
expect(status).to have_action
end
end
context 'when build is failed' do
let(:build) { create(:ci_build, :failed) }
it 'fabricates a retryable build status' do
expect(status).to be_a Gitlab::Ci::Status::Build::Retryable
end
it 'fabricates status with correct details' do
expect(status.text).to eq 'failed'
expect(status.icon).to eq 'icon_status_failed'
expect(status.label).to eq 'failed'
expect(status).to have_details
expect(status).to have_action
end
end
context 'when build is a canceled' do
let(:build) { create(:ci_build, :canceled) }
it 'fabricates a retryable build status' do
expect(status).to be_a Gitlab::Ci::Status::Build::Retryable
end
it 'fabricates status with correct details' do
expect(status.text).to eq 'canceled'
expect(status.icon).to eq 'icon_status_canceled'
expect(status.label).to eq 'canceled'
expect(status).to have_details
expect(status).to have_action
end
end
context 'when build is running' do
let(:build) { create(:ci_build, :running) }
it 'fabricates a canceable build status' do
expect(status).to be_a Gitlab::Ci::Status::Build::Cancelable
end
it 'fabricates status with correct details' do
expect(status.text).to eq 'running'
expect(status.icon).to eq 'icon_status_running'
expect(status.label).to eq 'running'
expect(status).to have_details
expect(status).to have_action
end
end
context 'when build is pending' do
let(:build) { create(:ci_build, :pending) }
it 'fabricates a cancelable build status' do
expect(status).to be_a Gitlab::Ci::Status::Build::Cancelable
end
it 'fabricates status with correct details' do
expect(status.text).to eq 'pending'
expect(status.icon).to eq 'icon_status_pending'
expect(status.label).to eq 'pending'
expect(status).to have_details
expect(status).to have_action
end
end
context 'when build is skipped' do
let(:build) { create(:ci_build, :skipped) }
it 'fabricates a core skipped status' do
expect(status).to be_a Gitlab::Ci::Status::Skipped
end
it 'fabricates status with correct details' do
expect(status.text).to eq 'skipped'
expect(status.icon).to eq 'icon_status_skipped'
expect(status.label).to eq 'skipped'
expect(status).to have_details
expect(status).not_to have_action
end
end
context 'when build is a manual action' do
context 'when build is a play action' do
let(:build) { create(:ci_build, :playable) }
it 'fabricates a core skipped status' do
expect(status).to be_a Gitlab::Ci::Status::Build::Play
end
it 'fabricates status with correct details' do
expect(status.text).to eq 'manual'
expect(status.icon).to eq 'icon_status_manual'
expect(status.label).to eq 'manual play action'
expect(status).to have_details
expect(status).to have_action
end
end
context 'when build is an environment stop action' do
let(:build) { create(:ci_build, :playable, :teardown_environment) }
it 'fabricates a core skipped status' do
expect(status).to be_a Gitlab::Ci::Status::Build::Stop
end
it 'fabricates status with correct details' do
expect(status.text).to eq 'manual'
expect(status.icon).to eq 'icon_status_manual'
expect(status.label).to eq 'manual stop action'
expect(status).to have_details
expect(status).to have_action
end
end
end
end
require 'spec_helper'
describe Gitlab::Ci::Status::Build::Play do
let(:status) { double('core') }
let(:user) { double('user') }
subject { described_class.new(status) }
describe '#text' do
it { expect(subject.text).to eq 'manual' }
end
describe '#label' do
it { expect(subject.label).to eq 'manual play action' }
end
describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_manual' }
end
describe 'action details' do
let(:user) { create(:user) }
let(:build) { create(:ci_build) }
let(:status) { Gitlab::Ci::Status::Core.new(build, user) }
describe '#has_action?' do
context 'when user is allowed to update build' do
before { build.project.team << [user, :developer] }
it { is_expected.to have_action }
end
context 'when user is not allowed to update build' do
it { is_expected.not_to have_action }
end
end
describe '#action_path' do
it { expect(subject.action_path).to include "#{build.id}/play" }
end
describe '#action_icon' do
it { expect(subject.action_icon).to eq 'play' }
end
describe '#action_title' do
it { expect(subject.action_title).to eq 'Play' }
end
end
describe '.matches?' do
subject { described_class.matches?(build, user) }
context 'when build is playable' do
context 'when build stops an environment' do
let(:build) do
create(:ci_build, :playable, :teardown_environment)
end
it 'does not match' do
expect(subject).to be false
end
end
context 'when build does not stop an environment' do
let(:build) { create(:ci_build, :playable) }
it 'is a correct match' do
expect(subject).to be true
end
end
end
context 'when build is not playable' do
let(:build) { create(:ci_build) }
it 'does not match' do
expect(subject).to be false
end
end
end
end
require 'spec_helper'
describe Gitlab::Ci::Status::Build::Retryable do
let(:status) { double('core status') }
let(:user) { double('user') }
subject do
described_class.new(status)
end
describe '#text' do
it 'does not override status text' do
expect(status).to receive(:text)
subject.text
end
end
describe '#icon' do
it 'does not override status icon' do
expect(status).to receive(:icon)
subject.icon
end
end
describe '#label' do
it 'does not override status label' do
expect(status).to receive(:label)
subject.label
end
end
describe 'action details' do
let(:user) { create(:user) }
let(:build) { create(:ci_build) }
let(:status) { Gitlab::Ci::Status::Core.new(build, user) }
describe '#has_action?' do
context 'when user is allowed to update build' do
before { build.project.team << [user, :developer] }
it { is_expected.to have_action }
end
context 'when user is not allowed to update build' do
it { is_expected.not_to have_action }
end
end
describe '#action_path' do
it { expect(subject.action_path).to include "#{build.id}/retry" }
end
describe '#action_icon' do
it { expect(subject.action_icon).to eq 'refresh' }
end
describe '#action_title' do
it { expect(subject.action_title).to eq 'Retry' }
end
end
describe '.matches?' do
subject { described_class.matches?(build, user) }
context 'when build is retryable' do
let(:build) do
create(:ci_build, :success)
end
it 'is a correct match' do
expect(subject).to be true
end
end
context 'when build is not retryable' do
let(:build) { create(:ci_build, :running) }
it 'does not match' do
expect(subject).to be false
end
end
end
end
require 'spec_helper'
describe Gitlab::Ci::Status::Build::Stop do
let(:status) { double('core status') }
let(:user) { double('user') }
subject do
described_class.new(status)
end
describe '#text' do
it { expect(subject.text).to eq 'manual' }
end
describe '#label' do
it { expect(subject.label).to eq 'manual stop action' }
end
describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_manual' }
end
describe 'action details' do
let(:user) { create(:user) }
let(:build) { create(:ci_build) }
let(:status) { Gitlab::Ci::Status::Core.new(build, user) }
describe '#has_action?' do
context 'when user is allowed to update build' do
before { build.project.team << [user, :developer] }
it { is_expected.to have_action }
end
context 'when user is not allowed to update build' do
it { is_expected.not_to have_action }
end
end
describe '#action_path' do
it { expect(subject.action_path).to include "#{build.id}/play" }
end
describe '#action_icon' do
it { expect(subject.action_icon).to eq 'stop' }
end
describe '#action_title' do
it { expect(subject.action_title).to eq 'Stop' }
end
end
describe '.matches?' do
subject { described_class.matches?(build, user) }
context 'when build is playable' do
context 'when build stops an environment' do
let(:build) do
create(:ci_build, :playable, :teardown_environment)
end
it 'is a correct match' do
expect(subject).to be true
end
end
context 'when build does not stop an environment' do
let(:build) { create(:ci_build, :playable) }
it 'does not match' do
expect(subject).to be false
end
end
end
context 'when build is not playable' do
let(:build) { create(:ci_build) }
it 'does not match' do
expect(subject).to be false
end
end
end
end
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Status::Canceled do describe Gitlab::Ci::Status::Canceled do
subject { described_class.new(double('subject')) } subject do
described_class.new(double('subject'), double('user'))
end
describe '#text' do describe '#text' do
it { expect(subject.label).to eq 'canceled' } it { expect(subject.label).to eq 'canceled' }
...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Canceled do ...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Canceled do
describe '#icon' do describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_canceled' } it { expect(subject.icon).to eq 'icon_status_canceled' }
end end
describe '#title' do
it { expect(subject.title).to eq 'Double: canceled' }
end
end end
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Status::Created do describe Gitlab::Ci::Status::Created do
subject { described_class.new(double('subject')) } subject do
described_class.new(double('subject'), double('user'))
end
describe '#text' do describe '#text' do
it { expect(subject.label).to eq 'created' } it { expect(subject.label).to eq 'created' }
...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Created do ...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Created do
describe '#icon' do describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_created' } it { expect(subject.icon).to eq 'icon_status_created' }
end end
describe '#title' do
it { expect(subject.title).to eq 'Double: created' }
end
end end
...@@ -2,11 +2,11 @@ require 'spec_helper' ...@@ -2,11 +2,11 @@ require 'spec_helper'
describe Gitlab::Ci::Status::Extended do describe Gitlab::Ci::Status::Extended do
subject do subject do
Class.new.extend(described_class) Class.new.include(described_class)
end end
it 'requires subclass to implement matcher' do it 'requires subclass to implement matcher' do
expect { subject.matches?(double) } expect { subject.matches?(double, double) }
.to raise_error(NotImplementedError) .to raise_error(NotImplementedError)
end end
end end
...@@ -2,15 +2,17 @@ require 'spec_helper' ...@@ -2,15 +2,17 @@ require 'spec_helper'
describe Gitlab::Ci::Status::Factory do describe Gitlab::Ci::Status::Factory do
subject do subject do
described_class.new(object) described_class.new(resource, user)
end end
let(:user) { create(:user) }
let(:status) { subject.fabricate! } let(:status) { subject.fabricate! }
context 'when object has a core status' do context 'when object has a core status' do
HasStatus::AVAILABLE_STATUSES.each do |core_status| HasStatus::AVAILABLE_STATUSES.each do |core_status|
context "when core status is #{core_status}" do context "when core status is #{core_status}" do
let(:object) { double(status: core_status) } let(:resource) { double(status: core_status) }
it "fabricates a core status #{core_status}" do it "fabricates a core status #{core_status}" do
expect(status).to be_a( expect(status).to be_a(
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Status::Failed do describe Gitlab::Ci::Status::Failed do
subject { described_class.new(double('subject')) } subject do
described_class.new(double('subject'), double('user'))
end
describe '#text' do describe '#text' do
it { expect(subject.label).to eq 'failed' } it { expect(subject.label).to eq 'failed' }
...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Failed do ...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Failed do
describe '#icon' do describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_failed' } it { expect(subject.icon).to eq 'icon_status_failed' }
end end
describe '#title' do
it { expect(subject.title).to eq 'Double: failed' }
end
end end
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Status::Pending do describe Gitlab::Ci::Status::Pending do
subject { described_class.new(double('subject')) } subject do
described_class.new(double('subject'), double('user'))
end
describe '#text' do describe '#text' do
it { expect(subject.label).to eq 'pending' } it { expect(subject.label).to eq 'pending' }
...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Pending do ...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Pending do
describe '#icon' do describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_pending' } it { expect(subject.icon).to eq 'icon_status_pending' }
end end
describe '#title' do
it { expect(subject.title).to eq 'Double: pending' }
end
end end
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Status::Pipeline::Common do describe Gitlab::Ci::Status::Pipeline::Common do
let(:pipeline) { create(:ci_pipeline) } let(:user) { create(:user) }
let(:project) { create(:empty_project, :private) }
let(:pipeline) { create(:ci_pipeline, project: project) }
subject do subject do
Class.new(Gitlab::Ci::Status::Core) Gitlab::Ci::Status::Core
.new(pipeline).extend(described_class) .new(pipeline, user)
.extend(described_class)
end end
it 'does not have action' do describe '#has_action?' do
expect(subject).not_to have_action it { is_expected.not_to have_action }
end end
it 'has details' do describe '#has_details?' do
expect(subject).to have_details context 'when user has access to read pipeline' do
before { project.team << [user, :developer] }
it { is_expected.to have_details }
end
context 'when user does not have access to read pipeline' do
it { is_expected.not_to have_details }
end
end end
it 'links to the pipeline details page' do describe '#details_path' do
expect(subject.details_path) it 'links to the pipeline details page' do
.to include "pipelines/#{pipeline.id}" expect(subject.details_path)
.to include "pipelines/#{pipeline.id}"
end
end end
end end
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Status::Pipeline::Factory do describe Gitlab::Ci::Status::Pipeline::Factory do
let(:user) { create(:user) }
let(:project) { pipeline.project }
subject do subject do
described_class.new(pipeline) described_class.new(pipeline, user)
end end
let(:status) do let(:status) do
subject.fabricate! subject.fabricate!
end end
before do
project.team << [user, :developer]
end
context 'when pipeline has a core status' do context 'when pipeline has a core status' do
HasStatus::AVAILABLE_STATUSES.each do |core_status| HasStatus::AVAILABLE_STATUSES.each do |core_status|
context "when core status is #{core_status}" do context "when core status is #{core_status}" do
......
...@@ -29,13 +29,13 @@ describe Gitlab::Ci::Status::Pipeline::SuccessWithWarnings do ...@@ -29,13 +29,13 @@ describe Gitlab::Ci::Status::Pipeline::SuccessWithWarnings do
end end
it 'is a correct match' do it 'is a correct match' do
expect(described_class.matches?(pipeline)).to eq true expect(described_class.matches?(pipeline, double)).to eq true
end end
end end
context 'when pipeline does not have warnings' do context 'when pipeline does not have warnings' do
it 'does not match' do it 'does not match' do
expect(described_class.matches?(pipeline)).to eq false expect(described_class.matches?(pipeline, double)).to eq false
end end
end end
end end
...@@ -51,13 +51,13 @@ describe Gitlab::Ci::Status::Pipeline::SuccessWithWarnings do ...@@ -51,13 +51,13 @@ describe Gitlab::Ci::Status::Pipeline::SuccessWithWarnings do
end end
it 'does not match' do it 'does not match' do
expect(described_class.matches?(pipeline)).to eq false expect(described_class.matches?(pipeline, double)).to eq false
end end
end end
context 'when pipeline does not have warnings' do context 'when pipeline does not have warnings' do
it 'does not match' do it 'does not match' do
expect(described_class.matches?(pipeline)).to eq false expect(described_class.matches?(pipeline, double)).to eq false
end end
end end
end end
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Status::Running do describe Gitlab::Ci::Status::Running do
subject { described_class.new(double('subject')) } subject do
described_class.new(double('subject'), double('user'))
end
describe '#text' do describe '#text' do
it { expect(subject.label).to eq 'running' } it { expect(subject.label).to eq 'running' }
...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Running do ...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Running do
describe '#icon' do describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_running' } it { expect(subject.icon).to eq 'icon_status_running' }
end end
describe '#title' do
it { expect(subject.title).to eq 'Double: running' }
end
end end
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Status::Skipped do describe Gitlab::Ci::Status::Skipped do
subject { described_class.new(double('subject')) } subject do
described_class.new(double('subject'), double('user'))
end
describe '#text' do describe '#text' do
it { expect(subject.label).to eq 'skipped' } it { expect(subject.label).to eq 'skipped' }
...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Skipped do ...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Skipped do
describe '#icon' do describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_skipped' } it { expect(subject.icon).to eq 'icon_status_skipped' }
end end
describe '#title' do
it { expect(subject.title).to eq 'Double: skipped' }
end
end end
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Status::Stage::Common do describe Gitlab::Ci::Status::Stage::Common do
let(:pipeline) { create(:ci_empty_pipeline) } let(:user) { create(:user) }
let(:stage) { build(:ci_stage, pipeline: pipeline, name: 'test') } let(:project) { create(:empty_project) }
let(:pipeline) { create(:ci_empty_pipeline, project: project) }
let(:stage) do
build(:ci_stage, pipeline: pipeline, name: 'test')
end
subject do subject do
Class.new(Gitlab::Ci::Status::Core) Class.new(Gitlab::Ci::Status::Core)
.new(stage).extend(described_class) .new(stage, user).extend(described_class)
end end
it 'does not have action' do it 'does not have action' do
expect(subject).not_to have_action expect(subject).not_to have_action
end end
it 'has details' do
expect(subject).to have_details
end
it 'links to the pipeline details page' do it 'links to the pipeline details page' do
expect(subject.details_path) expect(subject.details_path)
.to include "pipelines/#{pipeline.id}" .to include "pipelines/#{pipeline.id}"
expect(subject.details_path) expect(subject.details_path)
.to include "##{stage.name}" .to include "##{stage.name}"
end end
context 'when user has permission to read pipeline' do
before do
project.team << [user, :master]
end
it 'has details' do
expect(subject).to have_details
end
end
context 'when user does not have permission to read pipeline' do
it 'does not have details' do
expect(subject).not_to have_details
end
end
end end
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Status::Stage::Factory do describe Gitlab::Ci::Status::Stage::Factory do
let(:pipeline) { create(:ci_empty_pipeline) } let(:user) { create(:user) }
let(:stage) { build(:ci_stage, pipeline: pipeline, name: 'test') } let(:project) { create(:empty_project) }
let(:pipeline) { create(:ci_empty_pipeline, project: project) }
let(:stage) do
build(:ci_stage, pipeline: pipeline, name: 'test')
end
subject do subject do
described_class.new(stage) described_class.new(stage, user)
end end
let(:status) do let(:status) do
subject.fabricate! subject.fabricate!
end end
before do
project.team << [user, :developer]
end
context 'when stage has a core status' do context 'when stage has a core status' do
HasStatus::AVAILABLE_STATUSES.each do |core_status| HasStatus::AVAILABLE_STATUSES.each do |core_status|
context "when core status is #{core_status}" do context "when core status is #{core_status}" do
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Status::Success do describe Gitlab::Ci::Status::Success do
subject { described_class.new(double('subject')) } subject do
described_class.new(double('subject'), double('user'))
end
describe '#text' do describe '#text' do
it { expect(subject.label).to eq 'passed' } it { expect(subject.label).to eq 'passed' }
...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Success do ...@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Success do
describe '#icon' do describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_success' } it { expect(subject.icon).to eq 'icon_status_success' }
end end
describe '#title' do
it { expect(subject.title).to eq 'Double: passed' }
end
end end
require 'spec_helper'
describe Gitlab::Routing do
context 'when module is included' do
subject do
Class.new.include(described_class).new
end
it 'makes it possible to access url helpers' do
expect(subject).to respond_to(:namespace_project_path)
end
end
context 'when module is not included' do
subject do
Class.new.include(described_class.url_helpers).new
end
it 'exposes url helpers module through a method' do
expect(subject).to respond_to(:namespace_project_path)
end
end
end
...@@ -899,21 +899,87 @@ describe Ci::Build, models: true do ...@@ -899,21 +899,87 @@ describe Ci::Build, models: true do
end end
end end
describe '#cancelable?' do
subject { build }
context 'when build is cancelable' do
context 'when build is pending' do
it { is_expected.to be_cancelable }
end
context 'when build is running' do
before do
build.run!
end
it { is_expected.to be_cancelable }
end
end
context 'when build is not cancelable' do
context 'when build is successful' do
before do
build.success!
end
it { is_expected.not_to be_cancelable }
end
context 'when build is failed' do
before do
build.drop!
end
it { is_expected.not_to be_cancelable }
end
end
end
describe '#retryable?' do describe '#retryable?' do
context 'when build is running' do subject { build }
before do
build.run! context 'when build is retryable' do
context 'when build is successful' do
before do
build.success!
end
it { is_expected.to be_retryable }
end
context 'when build is failed' do
before do
build.drop!
end
it { is_expected.to be_retryable }
end end
it { expect(build).not_to be_retryable } context 'when build is canceled' do
before do
build.cancel!
end
it { is_expected.to be_retryable }
end
end end
context 'when build is finished' do context 'when build is not retryable' do
before do context 'when build is running' do
build.success! before do
build.run!
end
it { is_expected.not_to be_retryable }
end end
it { expect(build).to be_retryable } context 'when build is skipped' do
before do
build.skip!
end
it { is_expected.not_to be_retryable }
end
end end
end end
...@@ -1180,4 +1246,13 @@ describe Ci::Build, models: true do ...@@ -1180,4 +1246,13 @@ describe Ci::Build, models: true do
it { is_expected.to eq('review/master') } it { is_expected.to eq('review/master') }
end end
end end
describe '#detailed_status' do
let(:user) { create(:user) }
it 'returns a detailed status' do
expect(build.detailed_status(user))
.to be_a Gitlab::Ci::Status::Build::Cancelable
end
end
end end
...@@ -442,11 +442,15 @@ describe Ci::Pipeline, models: true do ...@@ -442,11 +442,15 @@ describe Ci::Pipeline, models: true do
end end
describe '#detailed_status' do describe '#detailed_status' do
let(:user) { create(:user) }
subject { pipeline.detailed_status(user) }
context 'when pipeline is created' do context 'when pipeline is created' do
let(:pipeline) { create(:ci_pipeline, status: :created) } let(:pipeline) { create(:ci_pipeline, status: :created) }
it 'returns detailed status for created pipeline' do it 'returns detailed status for created pipeline' do
expect(pipeline.detailed_status.text).to eq 'created' expect(subject.text).to eq 'created'
end end
end end
...@@ -454,7 +458,7 @@ describe Ci::Pipeline, models: true do ...@@ -454,7 +458,7 @@ describe Ci::Pipeline, models: true do
let(:pipeline) { create(:ci_pipeline, status: :pending) } let(:pipeline) { create(:ci_pipeline, status: :pending) }
it 'returns detailed status for pending pipeline' do it 'returns detailed status for pending pipeline' do
expect(pipeline.detailed_status.text).to eq 'pending' expect(subject.text).to eq 'pending'
end end
end end
...@@ -462,7 +466,7 @@ describe Ci::Pipeline, models: true do ...@@ -462,7 +466,7 @@ describe Ci::Pipeline, models: true do
let(:pipeline) { create(:ci_pipeline, status: :running) } let(:pipeline) { create(:ci_pipeline, status: :running) }
it 'returns detailed status for running pipeline' do it 'returns detailed status for running pipeline' do
expect(pipeline.detailed_status.text).to eq 'running' expect(subject.text).to eq 'running'
end end
end end
...@@ -470,7 +474,7 @@ describe Ci::Pipeline, models: true do ...@@ -470,7 +474,7 @@ describe Ci::Pipeline, models: true do
let(:pipeline) { create(:ci_pipeline, status: :success) } let(:pipeline) { create(:ci_pipeline, status: :success) }
it 'returns detailed status for successful pipeline' do it 'returns detailed status for successful pipeline' do
expect(pipeline.detailed_status.text).to eq 'passed' expect(subject.text).to eq 'passed'
end end
end end
...@@ -478,7 +482,7 @@ describe Ci::Pipeline, models: true do ...@@ -478,7 +482,7 @@ describe Ci::Pipeline, models: true do
let(:pipeline) { create(:ci_pipeline, status: :failed) } let(:pipeline) { create(:ci_pipeline, status: :failed) }
it 'returns detailed status for failed pipeline' do it 'returns detailed status for failed pipeline' do
expect(pipeline.detailed_status.text).to eq 'failed' expect(subject.text).to eq 'failed'
end end
end end
...@@ -486,7 +490,7 @@ describe Ci::Pipeline, models: true do ...@@ -486,7 +490,7 @@ describe Ci::Pipeline, models: true do
let(:pipeline) { create(:ci_pipeline, status: :canceled) } let(:pipeline) { create(:ci_pipeline, status: :canceled) }
it 'returns detailed status for canceled pipeline' do it 'returns detailed status for canceled pipeline' do
expect(pipeline.detailed_status.text).to eq 'canceled' expect(subject.text).to eq 'canceled'
end end
end end
...@@ -494,7 +498,7 @@ describe Ci::Pipeline, models: true do ...@@ -494,7 +498,7 @@ describe Ci::Pipeline, models: true do
let(:pipeline) { create(:ci_pipeline, status: :skipped) } let(:pipeline) { create(:ci_pipeline, status: :skipped) }
it 'returns detailed status for skipped pipeline' do it 'returns detailed status for skipped pipeline' do
expect(pipeline.detailed_status.text).to eq 'skipped' expect(subject.text).to eq 'skipped'
end end
end end
...@@ -506,7 +510,7 @@ describe Ci::Pipeline, models: true do ...@@ -506,7 +510,7 @@ describe Ci::Pipeline, models: true do
end end
it 'retruns detailed status for successful pipeline with warnings' do it 'retruns detailed status for successful pipeline with warnings' do
expect(pipeline.detailed_status.label).to eq 'passed with warnings' expect(subject.label).to eq 'passed with warnings'
end end
end end
end end
......
...@@ -68,7 +68,9 @@ describe Ci::Stage, models: true do ...@@ -68,7 +68,9 @@ describe Ci::Stage, models: true do
end end
describe '#detailed_status' do describe '#detailed_status' do
subject { stage.detailed_status } let(:user) { create(:user) }
subject { stage.detailed_status(user) }
context 'when build is created' do context 'when build is created' do
let!(:stage_build) { create_job(:ci_build, status: :created) } let!(:stage_build) { create_job(:ci_build, status: :created) }
......
...@@ -234,4 +234,13 @@ describe CommitStatus, models: true do ...@@ -234,4 +234,13 @@ describe CommitStatus, models: true do
end end
end end
end end
describe '#detailed_status' do
let(:user) { create(:user) }
it 'returns a detailed status' do
expect(commit_status.detailed_status(user))
.to be_a Gitlab::Ci::Status::Success
end
end
end end
require 'spec_helper' require 'spec_helper'
describe GenericCommitStatus, models: true do describe GenericCommitStatus, models: true do
let(:pipeline) { FactoryGirl.create :ci_pipeline } let(:pipeline) { create(:ci_pipeline) }
let(:generic_commit_status) { FactoryGirl.create :generic_commit_status, pipeline: pipeline }
let(:generic_commit_status) do
create(:generic_commit_status, pipeline: pipeline)
end
describe '#context' do describe '#context' do
subject { generic_commit_status.context } subject { generic_commit_status.context }
...@@ -17,6 +20,15 @@ describe GenericCommitStatus, models: true do ...@@ -17,6 +20,15 @@ describe GenericCommitStatus, models: true do
it { is_expected.to eq([:external]) } it { is_expected.to eq([:external]) }
end end
describe '#detailed_status' do
let(:user) { create(:user) }
it 'returns detailed status object' do
expect(generic_commit_status.detailed_status(user))
.to be_a Gitlab::Ci::Status::Success
end
end
describe 'set_default_values' do describe 'set_default_values' do
before do before do
generic_commit_status.context = nil generic_commit_status.context = nil
......
...@@ -50,9 +50,8 @@ describe Group, models: true do ...@@ -50,9 +50,8 @@ describe Group, models: true do
describe 'validations' do describe 'validations' do
it { is_expected.to validate_presence_of :name } it { is_expected.to validate_presence_of :name }
it { is_expected.to validate_uniqueness_of(:name) } it { is_expected.to validate_uniqueness_of(:name).scoped_to(:parent_id) }
it { is_expected.to validate_presence_of :path } it { is_expected.to validate_presence_of :path }
it { is_expected.to validate_uniqueness_of(:path) }
it { is_expected.not_to validate_presence_of :owner } it { is_expected.not_to validate_presence_of :owner }
end end
......
...@@ -6,20 +6,16 @@ describe Namespace, models: true do ...@@ -6,20 +6,16 @@ describe Namespace, models: true do
it { is_expected.to have_many :projects } it { is_expected.to have_many :projects }
it { is_expected.to validate_presence_of(:name) } it { is_expected.to validate_presence_of(:name) }
it { is_expected.to validate_uniqueness_of(:name) } it { is_expected.to validate_uniqueness_of(:name).scoped_to(:parent_id) }
it { is_expected.to validate_length_of(:name).is_at_most(255) } it { is_expected.to validate_length_of(:name).is_at_most(255) }
it { is_expected.to validate_length_of(:description).is_at_most(255) } it { is_expected.to validate_length_of(:description).is_at_most(255) }
it { is_expected.to validate_presence_of(:path) } it { is_expected.to validate_presence_of(:path) }
it { is_expected.to validate_uniqueness_of(:path) }
it { is_expected.to validate_length_of(:path).is_at_most(255) } it { is_expected.to validate_length_of(:path).is_at_most(255) }
it { is_expected.to validate_presence_of(:owner) } it { is_expected.to validate_presence_of(:owner) }
describe "Mass assignment" do
end
describe "Respond to" do describe "Respond to" do
it { is_expected.to respond_to(:human_name) } it { is_expected.to respond_to(:human_name) }
it { is_expected.to respond_to(:to_param) } it { is_expected.to respond_to(:to_param) }
......
...@@ -475,7 +475,7 @@ describe API::Commits, api: true do ...@@ -475,7 +475,7 @@ describe API::Commits, api: true do
expect(response).to have_http_status(400) expect(response).to have_http_status(400)
expect(json_response['message']).to eq('Sorry, we cannot cherry-pick this commit automatically. expect(json_response['message']).to eq('Sorry, we cannot cherry-pick this commit automatically.
It may have already been cherry-pick, or a more recent commit may have updated some of its content.') A cherry-pick may have already been performed with this commit, or a more recent commit may have updated some of its content.')
end end
it 'returns 400 if you are not allowed to push to the target branch' do it 'returns 400 if you are not allowed to push to the target branch' do
......
...@@ -66,7 +66,8 @@ describe Admin::ProjectsController, "routing" do ...@@ -66,7 +66,8 @@ describe Admin::ProjectsController, "routing" do
end end
it "to #show" do it "to #show" do
expect(get("/admin/projects/gitlab")).to route_to('admin/projects#show', namespace_id: 'gitlab') expect(get("/admin/projects/gitlab/gitlab-ce")).to route_to('admin/projects#show', namespace_id: 'gitlab', id: 'gitlab-ce')
expect(get("/admin/projects/gitlab/subgroup/gitlab-ce")).to route_to('admin/projects#show', namespace_id: 'gitlab/subgroup', id: 'gitlab-ce')
end end
end end
...@@ -119,3 +120,14 @@ describe Admin::HealthCheckController, "routing" do ...@@ -119,3 +120,14 @@ describe Admin::HealthCheckController, "routing" do
expect(get("/admin/health_check")).to route_to('admin/health_check#show') expect(get("/admin/health_check")).to route_to('admin/health_check#show')
end end
end end
describe Admin::GroupsController, "routing" do
it "to #index" do
expect(get("/admin/groups")).to route_to('admin/groups#index')
end
it "to #show" do
expect(get("/admin/groups/gitlab")).to route_to('admin/groups#show', id: 'gitlab')
expect(get("/admin/groups/gitlab/subgroup")).to route_to('admin/groups#show', id: 'gitlab/subgroup')
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment