Commit 427f5907 authored by Valery Sizov's avatar Valery Sizov

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

parents cb6ffd9c 7572a314
...@@ -16,6 +16,7 @@ variables: ...@@ -16,6 +16,7 @@ variables:
USE_BUNDLE_INSTALL: "true" USE_BUNDLE_INSTALL: "true"
GIT_DEPTH: "20" GIT_DEPTH: "20"
PHANTOMJS_VERSION: "2.1.1" PHANTOMJS_VERSION: "2.1.1"
GET_SOURCES_ATTEMPTS: "3"
before_script: before_script:
- source ./scripts/prepare_build.sh - source ./scripts/prepare_build.sh
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
gitignorePath: "/api/:version/templates/gitignores/:key", gitignorePath: "/api/:version/templates/gitignores/:key",
gitlabCiYmlPath: "/api/:version/templates/gitlab_ci_ymls/:key", gitlabCiYmlPath: "/api/:version/templates/gitlab_ci_ymls/:key",
ldapGroupsPath: "/api/:version/ldap/:provider/groups.json", ldapGroupsPath: "/api/:version/ldap/:provider/groups.json",
dockerfilePath: "/api/:version/dockerfiles/:key",
issuableTemplatePath: "/:namespace_path/:project_path/templates/:type/:key", issuableTemplatePath: "/:namespace_path/:project_path/templates/:type/:key",
group: function(group_id, callback) { group: function(group_id, callback) {
var url = Api.buildUrl(Api.groupPath) var url = Api.buildUrl(Api.groupPath)
...@@ -121,6 +122,10 @@ ...@@ -121,6 +122,10 @@
return callback(file); return callback(file);
}); });
}, },
dockerfileYml: function(key, callback) {
var url = Api.buildUrl(Api.dockerfilePath).replace(':key', key);
$.get(url, callback);
},
issueTemplate: function(namespacePath, projectPath, key, type, callback) { issueTemplate: function(namespacePath, projectPath, key, type, callback) {
var url = Api.buildUrl(Api.issuableTemplatePath) var url = Api.buildUrl(Api.issuableTemplatePath)
.replace(':key', key) .replace(':key', key)
......
/* global Api */
/*= require blob/template_selector */
(() => {
const global = window.gl || (window.gl = {});
class BlobDockerfileSelector extends gl.TemplateSelector {
requestFile(query) {
return Api.dockerfileYml(query.name, this.requestFileSuccess.bind(this));
}
requestFileSuccess(file) {
return super.requestFileSuccess(file);
}
}
global.BlobDockerfileSelector = BlobDockerfileSelector;
})();
(() => {
const global = window.gl || (window.gl = {});
class BlobDockerfileSelectors {
constructor({ editor, $dropdowns } = {}) {
this.editor = editor;
this.$dropdowns = $dropdowns || $('.js-dockerfile-selector');
this.initSelectors();
}
initSelectors() {
const editor = this.editor;
this.$dropdowns.each((i, dropdown) => {
const $dropdown = $(dropdown);
return new gl.BlobDockerfileSelector({
editor,
pattern: /(Dockerfile)/,
data: $dropdown.data('data'),
wrapper: $dropdown.closest('.js-dockerfile-selector-wrap'),
dropdown: $dropdown,
});
});
}
}
global.BlobDockerfileSelectors = BlobDockerfileSelectors;
})();
...@@ -36,6 +36,9 @@ ...@@ -36,6 +36,9 @@
new gl.BlobCiYamlSelectors({ new gl.BlobCiYamlSelectors({
editor: this.editor editor: this.editor
}); });
new gl.BlobDockerfileSelectors({
editor: this.editor
});
} }
EditBlob.prototype.initModePanesAndLinks = function() { EditBlob.prototype.initModePanesAndLinks = function() {
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
}); });
$(document).off('ajax:success', '.notification-form').on('ajax:success', '.notification-form', function(e, data) { $(document).off('ajax:success', '.notification-form').on('ajax:success', '.notification-form', function(e, data) {
if (data.saved) { if (data.saved) {
return $(e.currentTarget).closest('.notification-dropdown').replaceWith(data.html); return $(e.currentTarget).closest('.js-notification-dropdown').replaceWith(data.html);
} else { } else {
return new Flash('Failed to save new settings', 'alert'); return new Flash('Failed to save new settings', 'alert');
} }
......
...@@ -49,3 +49,11 @@ ...@@ -49,3 +49,11 @@
fill: $gray-darkest; fill: $gray-darkest;
} }
} }
.ci-status-icon-manual {
color: $gl-text-color;
svg {
fill: $gl-text-color;
}
}
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
} }
// Display Star and Fork buttons without counters on mobile. // Display Star and Fork buttons without counters on mobile.
.project-action-buttons { .project-repo-buttons {
display: block; display: block;
.count-buttons .btn { .count-buttons .btn {
......
...@@ -57,7 +57,6 @@ ...@@ -57,7 +57,6 @@
} }
.ci-status-link { .ci-status-link {
svg { svg {
position: relative; position: relative;
top: 2px; top: 2px;
......
...@@ -18,6 +18,20 @@ ...@@ -18,6 +18,20 @@
margin-top: -2px; margin-top: -2px;
margin-left: 5px; margin-left: 5px;
} }
&.split {
display: flex;
align-items: center;
}
.left {
flex: 1 1 auto;
}
.right {
flex: 0 0 auto;
text-align: right;
}
} }
.panel-body { .panel-body {
......
...@@ -24,6 +24,7 @@ $gray-lightest: #fdfdfd; ...@@ -24,6 +24,7 @@ $gray-lightest: #fdfdfd;
$gray-light: #fafafa; $gray-light: #fafafa;
$gray-lighter: #f9f9f9; $gray-lighter: #f9f9f9;
$gray-normal: #f5f5f5; $gray-normal: #f5f5f5;
$gray-dark: darken($gray-light, $darken-dark-factor);
$gray-darker: #eee; $gray-darker: #eee;
$gray-darkest: #c4c4c4; $gray-darkest: #c4c4c4;
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
padding: $gl-padding-top 0; padding: $gl-padding-top 0;
border-bottom: 1px solid $border-color; border-bottom: 1px solid $border-color;
color: $gl-text-color-dark; color: $gl-text-color-dark;
font-size: 16px;
line-height: 34px; line-height: 34px;
.author { .author {
......
...@@ -75,7 +75,8 @@ ...@@ -75,7 +75,8 @@
.soft-wrap-toggle, .soft-wrap-toggle,
.license-selector, .license-selector,
.gitignore-selector, .gitignore-selector,
.gitlab-ci-yml-selector { .gitlab-ci-yml-selector,
.dockerfile-selector {
display: inline-block; display: inline-block;
vertical-align: top; vertical-align: top;
font-family: $regular_font; font-family: $regular_font;
...@@ -105,7 +106,8 @@ ...@@ -105,7 +106,8 @@
.gitignore-selector, .gitignore-selector,
.license-selector, .license-selector,
.gitlab-ci-yml-selector { .gitlab-ci-yml-selector,
.dockerfile-selector {
.dropdown { .dropdown {
line-height: 21px; line-height: 21px;
} }
......
...@@ -32,11 +32,6 @@ ...@@ -32,11 +32,6 @@
} }
} }
.group-buttons {
.notification-dropdown {
display: inline-block;
}
}
.ldap-group-links { .ldap-group-links {
.form-actions { .form-actions {
......
...@@ -428,7 +428,7 @@ ...@@ -428,7 +428,7 @@
width: 21px; width: 21px;
height: 25px; height: 25px;
position: absolute; position: absolute;
top: -32px; top: -31px;
border-top: 2px solid $border-color; border-top: 2px solid $border-color;
} }
...@@ -456,32 +456,31 @@ ...@@ -456,32 +456,31 @@
} }
.build { .build {
border: 1px solid $border-color;
border-radius: 30px;
background-color: $white-light;
position: relative; position: relative;
padding: 8px 4px 9px 10px;
width: 186px; width: 186px;
margin-bottom: 10px; margin-bottom: 10px;
white-space: normal; white-space: normal;
color: $gl-text-color-light;
&:hover { > .build-content {
background-color: $stage-hover-bg; display: inline-block;
border: 1px solid $stage-hover-border; padding: 8px 10px 9px;
width: 100%;
border: 1px solid $border-color;
border-radius: 30px;
background-color: $white-light;
a, &:hover {
.dropdown-counter-badge, background-color: $stage-hover-bg;
.dropdown-menu-toggle { border: 1px solid $stage-hover-border;
color: $gl-text-color; color: $gl-text-color;
} }
}
.grouped-pipeline-dropdown a { > .ci-action-icon-container {
color: $gl-text-color-light; position: absolute;
right: 4px;
&:hover { top: 5px;
color: $gl-text-color;
}
}
} }
.ci-status-icon { .ci-status-icon {
...@@ -621,8 +620,8 @@ ...@@ -621,8 +620,8 @@
padding: 0; padding: 0;
width: 191px; width: 191px;
left: auto; left: auto;
right: -206px; right: -195px;
top: -11px; top: -4px;
box-shadow: 0 1px 5px $black-transparent; box-shadow: 0 1px 5px $black-transparent;
a { a {
...@@ -650,30 +649,20 @@ ...@@ -650,30 +649,20 @@
.dropdown-build { .dropdown-build {
color: $gl-text-color-light; color: $gl-text-color-light;
a.ci-action-icon-container { .build-content {
padding: 0; width: 100%;
font-size: 11px;
float: right;
margin-top: 4px;
display: inline-block;
position: relative;
i {
font-size: 11px;
margin-top: 0;
}
}
&:hover {
background-color: $stage-hover-bg;
border-radius: 3px;
color: $gl-text-color;
} }
.ci-action-icon-container { .ci-action-icon-container {
font-size: 11px;
position: absolute;
right: 4px;
i { i {
width: 25px; width: 25px;
height: 25px; height: 25px;
font-size: 11px;
margin-top: 0;
&::before { &::before {
top: 1px; top: 1px;
...@@ -682,6 +671,12 @@ ...@@ -682,6 +671,12 @@
} }
} }
&:hover {
background-color: $stage-hover-bg;
border-radius: 3px;
color: $gl-text-color;
}
.stage { .stage {
max-width: 100px; max-width: 100px;
width: 100px; width: 100px;
...@@ -704,9 +699,6 @@ ...@@ -704,9 +699,6 @@
// Action Icons // Action Icons
.ci-action-icon-container .ci-action-icon-wrapper { .ci-action-icon-container .ci-action-icon-wrapper {
float: right;
margin-top: -4px;
i { i {
color: $border-color; color: $border-color;
border-radius: 100%; border-radius: 100%;
......
...@@ -145,8 +145,6 @@ ...@@ -145,8 +145,6 @@
.project-repo-buttons, .project-repo-buttons,
.group-buttons { .group-buttons {
margin-top: 15px;
.btn { .btn {
@include btn-gray; @include btn-gray;
padding: 3px 10px; padding: 3px 10px;
...@@ -175,11 +173,9 @@ ...@@ -175,11 +173,9 @@
} }
} }
.download-button, .project-action-button {
.dropdown-toggle, margin: 15px 5px 0;
.notification-dropdown, vertical-align: top;
.project-dropdown {
margin-left: 10px;
} }
.notification-dropdown .dropdown-menu { .notification-dropdown .dropdown-menu {
...@@ -195,13 +191,15 @@ ...@@ -195,13 +191,15 @@
.count-buttons { .count-buttons {
display: inline-block; display: inline-block;
vertical-align: top; vertical-align: top;
margin-top: 15px;
} }
.project-clone-holder { .project-clone-holder {
display: inline-block; display: inline-block;
margin: 15px 5px 0 0;
input { input {
height: 29px; height: 28px;
} }
} }
...@@ -255,7 +253,7 @@ ...@@ -255,7 +253,7 @@
line-height: 13px; line-height: 13px;
padding: $gl-vert-padding $gl-padding; padding: $gl-vert-padding $gl-padding;
letter-spacing: .4px; letter-spacing: .4px;
padding: 7px 14px; padding: 6px 14px;
text-align: center; text-align: center;
vertical-align: middle; vertical-align: middle;
touch-action: manipulation; touch-action: manipulation;
...@@ -492,6 +490,7 @@ a.deploy-project-label { ...@@ -492,6 +490,7 @@ a.deploy-project-label {
.project-stats { .project-stats {
font-size: 0; font-size: 0;
text-align: center;
border-bottom: 1px solid $border-color; border-bottom: 1px solid $border-color;
.nav { .nav {
......
...@@ -15,8 +15,7 @@ ...@@ -15,8 +15,7 @@
height: 13px; height: 13px;
width: 13px; width: 13px;
position: relative; position: relative;
top: 1px; top: 2px;
margin-right: 3px;
overflow: visible; overflow: visible;
} }
...@@ -25,7 +24,7 @@ ...@@ -25,7 +24,7 @@
border-color: $gl-danger; border-color: $gl-danger;
&:not(span):hover { &:not(span):hover {
background-color: rgba( $gl-danger, .07); background-color: rgba($gl-danger, .07);
} }
svg { svg {
...@@ -39,7 +38,7 @@ ...@@ -39,7 +38,7 @@
border-color: $gl-success; border-color: $gl-success;
&:not(span):hover { &:not(span):hover {
background-color: rgba( $gl-success, .07); background-color: rgba($gl-success, .07);
} }
svg { svg {
...@@ -52,7 +51,7 @@ ...@@ -52,7 +51,7 @@
border-color: $gl-info; border-color: $gl-info;
&:not(span):hover { &:not(span):hover {
background-color: rgba( $gl-info, .07); background-color: rgba($gl-info, .07);
} }
svg { svg {
...@@ -66,7 +65,7 @@ ...@@ -66,7 +65,7 @@
border-color: $gl-gray; border-color: $gl-gray;
&:not(span):hover { &:not(span):hover {
background-color: rgba( $gl-gray, .07); background-color: rgba($gl-gray, .07);
} }
svg { svg {
...@@ -79,7 +78,7 @@ ...@@ -79,7 +78,7 @@
border-color: $gl-warning; border-color: $gl-warning;
&:not(span):hover { &:not(span):hover {
background-color: rgba( $gl-warning, .07); background-color: rgba($gl-warning, .07);
} }
svg { svg {
...@@ -92,7 +91,7 @@ ...@@ -92,7 +91,7 @@
border-color: $blue-normal; border-color: $blue-normal;
&:not(span):hover { &:not(span):hover {
background-color: rgba( $blue-normal, .07); background-color: rgba($blue-normal, .07);
} }
svg { svg {
...@@ -106,13 +105,26 @@ ...@@ -106,13 +105,26 @@
border-color: $gl-gray-light; border-color: $gl-gray-light;
&:not(span):hover { &:not(span):hover {
background-color: rgba( $gl-gray-light, .07); background-color: rgba($gl-gray-light, .07);
} }
svg { svg {
fill: $gl-gray-light; fill: $gl-gray-light;
} }
} }
&.ci-manual {
color: $gl-text-color;
border-color: $gl-text-color;
&:not(span):hover {
background-color: rgba($gl-text-color, .07);
}
svg {
fill: $gl-text-color;
}
}
} }
} }
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
.add-to-tree { .add-to-tree {
vertical-align: top; vertical-align: top;
padding: 6px 10px;
} }
.tree-table { .tree-table {
...@@ -172,7 +173,7 @@ ...@@ -172,7 +173,7 @@
position: relative; position: relative;
z-index: 2; z-index: 2;
.download-button { .project-action-button {
margin-left: $btn-side-margin; margin-left: $btn-side-margin;
} }
} }
...@@ -8,6 +8,9 @@ class Projects::BlameController < Projects::ApplicationController ...@@ -8,6 +8,9 @@ class Projects::BlameController < Projects::ApplicationController
def show def show
@blob = @repository.blob_at(@commit.id, @path) @blob = @repository.blob_at(@commit.id, @path)
return render_404 unless @blob
@blame_groups = Gitlab::Blame.new(@blob, @commit).groups @blame_groups = Gitlab::Blame.new(@blob, @commit).groups
end end
end end
...@@ -191,6 +191,10 @@ module BlobHelper ...@@ -191,6 +191,10 @@ module BlobHelper
@gitlab_ci_ymls ||= Gitlab::Template::GitlabCiYmlTemplate.dropdown_names @gitlab_ci_ymls ||= Gitlab::Template::GitlabCiYmlTemplate.dropdown_names
end end
def dockerfile_names
@dockerfile_names ||= Gitlab::Template::DockerfileTemplate.dropdown_names
end
def blob_editor_paths def blob_editor_paths
{ {
'relative-url-root' => Rails.application.config.relative_url_root, 'relative-url-root' => Rails.application.config.relative_url_root,
......
...@@ -18,7 +18,7 @@ module Ci ...@@ -18,7 +18,7 @@ module Ci
end end
serialize :options serialize :options
serialize :yaml_variables serialize :yaml_variables, Gitlab::Serialize::Ci::Variables
validates :coverage, numericality: true, allow_blank: true validates :coverage, numericality: true, allow_blank: true
validates_presence_of :ref validates_presence_of :ref
......
...@@ -102,7 +102,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -102,7 +102,7 @@ class MergeRequest < ActiveRecord::Base
validates :source_branch, presence: true validates :source_branch, presence: true
validates :target_project, presence: true validates :target_project, presence: true
validates :target_branch, presence: true validates :target_branch, presence: true
validates :merge_user, presence: true, if: :merge_when_build_succeeds? validates :merge_user, presence: true, if: :merge_when_build_succeeds?, unless: :importing?
validate :validate_branches, unless: [:allow_broken, :importing?, :closed_without_fork?] validate :validate_branches, unless: [:allow_broken, :importing?, :closed_without_fork?]
validate :validate_fork, unless: :closed_without_fork? validate :validate_fork, unless: :closed_without_fork?
validate :validate_approvals_before_merge validate :validate_approvals_before_merge
......
...@@ -13,7 +13,7 @@ class Route < ActiveRecord::Base ...@@ -13,7 +13,7 @@ class Route < ActiveRecord::Base
def rename_children def rename_children
# We update each row separately because MySQL does not have regexp_replace. # We update each row separately because MySQL does not have regexp_replace.
# rubocop:disable Rails/FindEach # rubocop:disable Rails/FindEach
Route.where('path LIKE ?', "#{path_was}%").each do |route| Route.where('path LIKE ?', "#{path_was}/%").each do |route|
# Note that update column skips validation and callbacks. # Note that update column skips validation and callbacks.
# We need this to avoid recursive call of rename_children method # We need this to avoid recursive call of rename_children method
route.update_column(:path, route.path.sub(path_was, path)) route.update_column(:path, route.path.sub(path_was, path))
......
- status = local_assigns.fetch(:status) - status = local_assigns.fetch(:status)
- css_classes = "ci-status ci-#{status.group}"
- if status.has_details? - if status.has_details?
= link_to status.details_path, class: "ci-status ci-#{status}" do = link_to status.details_path, class: css_classes do
= custom_icon(status.icon) = custom_icon(status.icon)
= status.text = status.text
- else - else
%span{ class: "ci-status ci-#{status}" } %span{ class: css_classes }
= custom_icon(status.icon) = custom_icon(status.icon)
= status.text = status.text
...@@ -2,15 +2,16 @@ ...@@ -2,15 +2,16 @@
- subject = local_assigns.fetch(:subject) - subject = local_assigns.fetch(:subject)
- status = subject.detailed_status(current_user) - status = subject.detailed_status(current_user)
- klass = "ci-status-icon ci-status-icon-#{status}" - klass = "ci-status-icon ci-status-icon-#{status.group}"
- if status.has_details? - if status.has_details?
= link_to status.details_path, data: { toggle: 'tooltip', title: "#{subject.name} - #{status.label}" } do = link_to status.details_path, class: 'build-content' do
%span{ class: klass }= custom_icon(status.icon) %span{ class: klass }= custom_icon(status.icon)
.ci-status-text= subject.name .ci-status-text{ 'data-toggle' => 'tooltip', 'data-title' => "#{subject.name} - #{status.label}" }= subject.name
- else - else
%span{ class: klass }= custom_icon(status.icon) .build-content
.ci-status-text= subject.name %span{ class: klass }= custom_icon(status.icon)
.ci-status-text{ 'data-toggle' => 'tooltip', 'data-title' => "#{subject.name} - #{status.label}" }= subject.name
- if status.has_action? - if status.has_action?
= link_to status.action_path, method: status.action_method, = link_to status.action_path, method: status.action_method,
......
...@@ -24,11 +24,19 @@ ...@@ -24,11 +24,19 @@
%br %br
= render "shared/mirror_status" = render "shared/mirror_status"
.project-repo-buttons.project-action-buttons .project-repo-buttons
.count-buttons .count-buttons
= render 'projects/buttons/star' = render 'projects/buttons/star'
= render 'projects/buttons/fork' = render 'projects/buttons/fork'
- if @project.feature_available?(:repository, current_user) %span.hidden-xs
.project-clone-holder - if @project.feature_available?(:repository, current_user)
= render "shared/clone_panel" .project-clone-holder
= render "shared/clone_panel"
- if current_user && can?(current_user, :download_code, @project)
= render 'projects/buttons/download', project: @project, ref: @ref
= render 'projects/buttons/dropdown'
= render 'shared/notifications/button', notification_setting: @notification_setting
= render 'projects/buttons/koding'
= render 'shared/members/access_request_buttons', source: @project
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
= dropdown_tag("Choose a .gitignore template", options: { toggle_class: 'btn js-gitignore-selector', title: "Choose a template", filter: true, placeholder: "Filter", data: { data: gitignore_names } } ) = dropdown_tag("Choose a .gitignore template", options: { toggle_class: 'btn js-gitignore-selector', title: "Choose a template", filter: true, placeholder: "Filter", data: { data: gitignore_names } } )
.gitlab-ci-yml-selector.js-gitlab-ci-yml-selector-wrap.hidden .gitlab-ci-yml-selector.js-gitlab-ci-yml-selector-wrap.hidden
= dropdown_tag("Choose a GitLab CI Yaml template", options: { toggle_class: 'btn js-gitlab-ci-yml-selector', title: "Choose a template", filter: true, placeholder: "Filter", data: { data: gitlab_ci_ymls } } ) = dropdown_tag("Choose a GitLab CI Yaml template", options: { toggle_class: 'btn js-gitlab-ci-yml-selector', title: "Choose a template", filter: true, placeholder: "Filter", data: { data: gitlab_ci_ymls } } )
.dockerfile-selector.js-dockerfile-selector-wrap.hidden
= dropdown_tag("Choose a Dockerfile template", options: { toggle_class: 'btn js-dockerfile-selector', title: "Choose a template", filter: true, placeholder: "Filter", data: { data: dockerfile_names } } )
= button_tag class: 'soft-wrap-toggle btn', type: 'button' do = button_tag class: 'soft-wrap-toggle btn', type: 'button' do
%span.no-wrap %span.no-wrap
= custom_icon('icon_no_wrap') = custom_icon('icon_no_wrap')
......
- if !project.empty_repo? && can?(current_user, :download_code, project) - if !project.empty_repo? && can?(current_user, :download_code, project)
.dropdown.inline.download-button .project-action-button.dropdown.inline
%button.btn{ 'data-toggle' => 'dropdown' } %button.btn{ 'data-toggle' => 'dropdown' }
= icon('download') = icon('download')
= icon("caret-down") = icon("caret-down")
......
- if current_user - if current_user
.dropdown.inline .project-action-button.dropdown.inline
%a.btn.dropdown-toggle{href: '#', "data-toggle" => "dropdown"} %a.btn.dropdown-toggle{href: '#', "data-toggle" => "dropdown"}
= icon('plus') = icon('plus')
= icon("caret-down") = icon("caret-down")
......
- if koding_enabled? && current_user && can_push_branch?(@project, @project.default_branch) - if koding_enabled? && current_user && @repository.koding_yml && can_push_branch?(@project, @project.default_branch)
- if @repository.koding_yml = link_to koding_project_url(@project), class: 'btn project-action-button inline', target: '_blank' do
= link_to koding_project_url(@project), class: 'btn', target: '_blank' do Run in IDE (Koding)
Run in IDE (Koding)
- else
= link_to add_koding_stack_path(@project), class: 'btn' do
Set Up Koding
- pretty_path_with_namespace = "#{@project ? @project.namespace.name : 'namespace'} / #{@project ? @project.name : 'name'}" - run_actions_text = "Perform common operations on this project: #{@project.name_with_namespace}"
- run_actions_text = "Perform common operations on this project: #{pretty_path_with_namespace}"
.well .well
This service allows GitLab users to perform common operations on this This service allows GitLab users to perform common operations on this
...@@ -27,7 +26,7 @@ ...@@ -27,7 +26,7 @@
.form-group .form-group
= label_tag :display_name, 'Display name', class: 'col-sm-2 col-xs-12 control-label' = label_tag :display_name, 'Display name', class: 'col-sm-2 col-xs-12 control-label'
.col-sm-10.col-xs-12.input-group .col-sm-10.col-xs-12.input-group
= text_field_tag :display_name, "GitLab / #{pretty_path_with_namespace}", class: 'form-control input-sm', readonly: 'readonly' = text_field_tag :display_name, "GitLab / #{@project.name_with_namespace}", class: 'form-control input-sm', readonly: 'readonly'
.input-group-btn .input-group-btn
= clipboard_button(clipboard_target: '#display_name') = clipboard_button(clipboard_target: '#display_name')
......
...@@ -66,20 +66,11 @@ ...@@ -66,20 +66,11 @@
- unless @repository.gitlab_ci_yml - unless @repository.gitlab_ci_yml
%li.missing %li.missing
= link_to add_special_file_path(@project, file_name: '.gitlab-ci.yml') do = link_to add_special_file_path(@project, file_name: '.gitlab-ci.yml') do
Set Up CI Set up CI
- if koding_enabled? && @repository.koding_yml.blank?
%li.project-repo-buttons.right %li.missing
.project-right-buttons = link_to 'Set up Koding', add_koding_stack_path(@project)
- if current_user
= render 'shared/members/access_request_buttons', source: @project
= render "projects/buttons/koding"
.btn-group.project-repo-btn-group
= render 'projects/buttons/download', project: @project, ref: @ref
= render 'projects/buttons/dropdown'
.pull-right
= render 'shared/notifications/button', notification_setting: @notification_setting
- if @repository.commit - if @repository.commit
.project-last-commit{ class: container_class } .project-last-commit{ class: container_class }
= render 'projects/last_commit', commit: @repository.commit, ref: current_ref, project: @project = render 'projects/last_commit', commit: @repository.commit, ref: current_ref, project: @project
......
...@@ -10,12 +10,11 @@ ...@@ -10,12 +10,11 @@
- status_groups.each do |group_name, grouped_statuses| - status_groups.each do |group_name, grouped_statuses|
- if grouped_statuses.one? - if grouped_statuses.one?
- status = grouped_statuses.first - status = grouped_statuses.first
%li.build %li.build{ 'id' => "ci-badge-#{group_name}" }
.curve .curve
.build-content = render 'ci/status/graph_badge', subject: status
= render 'ci/status/graph_badge', subject: status
- else - else
%li.build %li.build{ 'id' => "ci-badge-#{group_name}" }
.curve .curve
.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
- group_status = CommitStatus.where(id: subject).status - group_status = CommitStatus.where(id: subject).status
%button.dropdown-menu-toggle.has-tooltip{ type: 'button', data: { toggle: 'dropdown', title: "#{name} - #{group_status}" } } %button.dropdown-menu-toggle.build-content.has-tooltip{ type: 'button', data: { toggle: 'dropdown'} }
%span{class: "ci-status-icon ci-status-icon-#{group_status}"} %span{class: "ci-status-icon ci-status-icon-#{group_status}"}
= ci_icon_for_status(group_status) = ci_icon_for_status(group_status)
%span.ci-status-text %span.ci-status-text{ 'data-toggle' => 'tooltip', 'data-title' => "#{name} - #{group_status}" }
= name = name
%span.dropdown-counter-badge= subject.size %span.dropdown-counter-badge= subject.size
.dropdown-menu.grouped-pipeline-dropdown .dropdown-menu.grouped-pipeline-dropdown
......
- model_name = source.model_name.to_s.downcase - model_name = source.model_name.to_s.downcase
- if can?(current_user, :"destroy_#{model_name}_member", source.members.find_by(user_id: current_user.id)) .project-action-button.inline
= link_to "Leave #{model_name}", polymorphic_path([:leave, source, :members]), - if can?(current_user, :"destroy_#{model_name}_member", source.members.find_by(user_id: current_user.id))
method: :delete, = link_to "Leave #{model_name}", polymorphic_path([:leave, source, :members]),
data: { confirm: leave_confirmation_message(source) }, method: :delete,
class: 'btn' data: { confirm: leave_confirmation_message(source) },
- elsif requester = source.requesters.find_by(user_id: current_user.id) class: 'btn'
= link_to 'Withdraw Access Request', polymorphic_path([:leave, source, :members]), - elsif requester = source.requesters.find_by(user_id: current_user.id)
method: :delete, = link_to 'Withdraw Access Request', polymorphic_path([:leave, source, :members]),
data: { confirm: remove_member_message(requester) }, method: :delete,
class: 'btn' data: { confirm: remove_member_message(requester) },
- elsif source.request_access_enabled && can?(current_user, :request_access, source) class: 'btn'
= link_to 'Request Access', polymorphic_path([:request_access, source, :members]), - elsif source.request_access_enabled && can?(current_user, :request_access, source)
method: :post, = link_to 'Request Access', polymorphic_path([:request_access, source, :members]),
class: 'btn' method: :post,
class: 'btn'
...@@ -3,10 +3,12 @@ ...@@ -3,10 +3,12 @@
- panel_class = primary ? 'panel-primary' : 'panel-default' - panel_class = primary ? 'panel-primary' : 'panel-default'
.panel{ class: panel_class } .panel{ class: panel_class }
.panel-heading .panel-heading.split
= title .left
= title
- if show_counter - if show_counter
.pull-right= issuables.size .right
= issuables.size
- class_prefix = dom_class(issuables).pluralize - class_prefix = dom_class(issuables).pluralize
%ul{ class: "well-list #{class_prefix}-sortable-list", id: "#{class_prefix}-list-#{id}", "data-state" => id } %ul{ class: "well-list #{class_prefix}-sortable-list", id: "#{class_prefix}-list-#{id}", "data-state" => id }
......
- if notification_setting - if notification_setting
.dropdown.notification-dropdown .js-notification-dropdown.notification-dropdown.project-action-button.dropdown.inline
= form_for notification_setting, remote: true, html: { class: "inline notification-form" } do |f| = form_for notification_setting, remote: true, html: { class: "inline notification-form" } do |f|
= hidden_setting_source_input(notification_setting) = hidden_setting_source_input(notification_setting)
= f.hidden_field :level, class: "notification_setting_level" = f.hidden_field :level, class: "notification_setting_level"
......
---
title: Made the padding on the plus button in the breadcrumb menu even
merge_request:
author: Ryan Harris
---
title: Add support for Dockerfile templates
merge_request: 7247
author:
---
title: Fix Route#rename_children behavior
merge_request:
author:
---
title: Fix blame 500 error on invalid path.
merge_request: 25761
author: Jeff Stubler
---
title: Fix Import/Export duplicated builds error
merge_request:
author:
---
title: Fix missing service error importing from EE to CE
merge_request: 8144
author:
---
title: Fix Import/Export merge requests error while importing
merge_request:
author:
---
title: Convert CI YAML variables keys into strings
merge_request: 8088
author:
---
title: Add LDAP Rake task to rename a provider
merge_request: 2181
author:
---
title: Move all action buttons to project header
merge_request:
author:
---
title: Make CI badge hitboxes match parent
merge_request:
author:
---
title: Avoid escaping relative links in Markdown twice
merge_request: 7940
author: winniehell
class Gitlab::Seeder::Pipelines class Gitlab::Seeder::Pipelines
STAGES = %w[build test deploy notify] STAGES = %w[build test deploy notify]
BUILDS = [ BUILDS = [
{ name: 'build:linux', stage: 'build', status: :success }, # build stage
{ name: 'build:osx', stage: 'build', status: :success }, { name: 'build:linux', stage: 'build', status: :success,
{ name: 'rspec:linux 0 3', stage: 'test', status: :success }, queued_at: 10.hour.ago, started_at: 9.hour.ago, finished_at: 8.hour.ago },
{ name: 'rspec:linux 1 3', stage: 'test', status: :success }, { name: 'build:osx', stage: 'build', status: :success,
{ name: 'rspec:linux 2 3', stage: 'test', status: :success }, queued_at: 10.hour.ago, started_at: 10.hour.ago, finished_at: 9.hour.ago },
{ name: 'rspec:windows 0 3', stage: 'test', status: :success },
{ name: 'rspec:windows 1 3', stage: 'test', status: :success }, # test stage
{ name: 'rspec:windows 2 3', stage: 'test', status: :success }, { name: 'rspec:linux 0 3', stage: 'test', status: :success,
{ name: 'rspec:windows 2 3', stage: 'test', status: :success }, queued_at: 8.hour.ago, started_at: 8.hour.ago, finished_at: 7.hour.ago },
{ name: 'rspec:osx', stage: 'test', status_event: :success }, { name: 'rspec:linux 1 3', stage: 'test', status: :success,
{ name: 'spinach:linux', stage: 'test', status: :success }, queued_at: 8.hour.ago, started_at: 8.hour.ago, finished_at: 7.hour.ago },
{ name: 'spinach:osx', stage: 'test', status: :failed, allow_failure: true}, { name: 'rspec:linux 2 3', stage: 'test', status: :success,
{ name: 'env:alpha', stage: 'deploy', environment: 'alpha', status: :pending }, queued_at: 8.hour.ago, started_at: 8.hour.ago, finished_at: 7.hour.ago },
{ name: 'env:beta', stage: 'deploy', environment: 'beta', status: :running }, { name: 'rspec:windows 0 3', stage: 'test', status: :success,
{ name: 'env:gamma', stage: 'deploy', environment: 'gamma', status: :canceled }, queued_at: 8.hour.ago, started_at: 8.hour.ago, finished_at: 7.hour.ago },
{ name: 'staging', stage: 'deploy', environment: 'staging', status_event: :success, options: { environment: { on_stop: 'stop staging' } } }, { name: 'rspec:windows 1 3', stage: 'test', status: :success,
{ name: 'stop staging', stage: 'deploy', environment: 'staging', when: 'manual', status: :skipped }, queued_at: 8.hour.ago, started_at: 8.hour.ago, finished_at: 7.hour.ago },
{ name: 'production', stage: 'deploy', environment: 'production', when: 'manual', status: :skipped }, { name: 'rspec:windows 2 3', stage: 'test', status: :success,
queued_at: 8.hour.ago, started_at: 8.hour.ago, finished_at: 7.hour.ago },
{ name: 'rspec:windows 2 3', stage: 'test', status: :success,
queued_at: 8.hour.ago, started_at: 8.hour.ago, finished_at: 7.hour.ago },
{ name: 'rspec:osx', stage: 'test', status_event: :success,
queued_at: 8.hour.ago, started_at: 8.hour.ago, finished_at: 7.hour.ago },
{ name: 'spinach:linux', stage: 'test', status: :success,
queued_at: 8.hour.ago, started_at: 8.hour.ago, finished_at: 7.hour.ago },
{ name: 'spinach:osx', stage: 'test', status: :failed, allow_failure: true,
queued_at: 8.hour.ago, started_at: 8.hour.ago, finished_at: 7.hour.ago },
# deploy stage
{ name: 'staging', stage: 'deploy', environment: 'staging', status_event: :success,
options: { environment: { action: 'start', on_stop: 'stop staging' } },
queued_at: 7.hour.ago, started_at: 6.hour.ago, finished_at: 4.hour.ago },
{ name: 'stop staging', stage: 'deploy', environment: 'staging',
when: 'manual', status: :skipped },
{ name: 'production', stage: 'deploy', environment: 'production',
when: 'manual', status: :skipped },
# notify stage
{ name: 'slack', stage: 'notify', when: 'manual', status: :created }, { name: 'slack', stage: 'notify', when: 'manual', status: :created },
] ]
EXTERNAL_JOBS = [
{ name: 'jenkins', stage: 'test', status: :success,
queued_at: 7.hour.ago, started_at: 6.hour.ago, finished_at: 4.hour.ago },
]
def initialize(project) def initialize(project)
@project = project @project = project
...@@ -30,11 +54,12 @@ class Gitlab::Seeder::Pipelines ...@@ -30,11 +54,12 @@ class Gitlab::Seeder::Pipelines
pipelines.each do |pipeline| pipelines.each do |pipeline|
begin begin
BUILDS.each { |opts| build_create!(pipeline, opts) } BUILDS.each { |opts| build_create!(pipeline, opts) }
commit_status_create!(pipeline, name: 'jenkins', stage: 'test', status: :success) EXTERNAL_JOBS.each { |opts| commit_status_create!(pipeline, opts) }
print '.' print '.'
rescue ActiveRecord::RecordInvalid rescue ActiveRecord::RecordInvalid
print 'F' print 'F'
ensure ensure
pipeline.update_duration
pipeline.update_status pipeline.update_status
end end
end end
......
...@@ -74,24 +74,5 @@ Example output: ...@@ -74,24 +74,5 @@ Example output:
The LDAP check Rake task will test the bind_dn and password credentials The LDAP check Rake task will test the bind_dn and password credentials
(if configured) and will list a sample of LDAP users. This task is also (if configured) and will list a sample of LDAP users. This task is also
executed as part of the `gitlab:check` task, but can run independently executed as part of the `gitlab:check` task, but can run independently.
using the command below. See [LDAP Rake Tasks - LDAP Check](ldap.md#check) for details.
**Omnibus Installation**
```
sudo gitlab-rake gitlab:ldap:check
```
**Source Installation**
```bash
sudo -u git -H bundle exec rake gitlab:ldap:check RAILS_ENV=production
```
By default, the task will return a sample of 100 LDAP users. Change this
limit by passing a number to the check task:
```bash
rake gitlab:ldap:check[50]
```
# LDAP Rake Tasks
## Check
The LDAP check Rake task will test the `bind_dn` and `password` credentials
(if configured) and will list a sample of LDAP users. This task is also
executed as part of the `gitlab:check` task, but can run independently
using the command below.
**Omnibus Installation**
```
sudo gitlab-rake gitlab:ldap:check
```
**Source Installation**
```bash
sudo -u git -H bundle exec rake gitlab:ldap:check RAILS_ENV=production
```
------
By default, the task will return a sample of 100 LDAP users. Change this
limit by passing a number to the check task:
```bash
rake gitlab:ldap:check[50]
```
## Rename a provider
If you change the LDAP server ID in `gitlab.yml` or `gitlab.rb` you will need
to update all user identities or users will be unable to sign in. Input the
old and new provider and this task will update all matching identities in the
database.
`old_provider` and `new_provider` are derived from the prefix `ldap` plus the
LDAP server ID from the configuration file. For example, in `gitlab.yml` or
`gitlab.rb` you may see LDAP configuration like this:
```yaml
main:
label: 'LDAP'
host: '_your_ldap_server'
port: 389
uid: 'sAMAccountName'
...
```
`main` is the LDAP server ID. Together, the unique provider is `ldapmain`.
> **Warning**: If you input an incorrect new provider users will be unable
to sign in. If this happens, run the task again with the incorrect provider
as the `old_provider` and the correct provider as the `new_provider`.
**Omnibus Installation**
```bash
sudo gitlab-rake gitlab:ldap:rename_provider[old_provider,new_provider]
```
**Source Installation**
```bash
bundle exec rake gitlab:ldap:rename_provider[old_provider,new_provider] RAILS_ENV=production
```
### Example
Consider beginning with the default server ID `main` (full provider `ldapmain`).
If we change `main` to `mycompany`, the `new_provider` is `ldapmycompany`.
To rename all user identities run the following command:
```bash
sudo gitlab-rake gitlab:ldap:rename_provider[ldapmain,ldapmycompany]
```
Example output:
```
100 users with provider 'ldapmain' will be updated to 'ldapmycompany'.
If the new provider is incorrect, users will be unable to sign in.
Do you want to continue (yes/no)? yes
User identities were successfully updated
```
### Other options
If you do not specify an `old_provider` and `new_provider` you will be prompted
for them:
**Omnibus Installation**
```bash
sudo gitlab-rake gitlab:ldap:rename_provider
```
**Source Installation**
```bash
bundle exec rake gitlab:ldap:rename_provider RAILS_ENV=production
```
**Example output:**
```
What is the old provider? Ex. 'ldapmain': ldapmain
What is the new provider? Ex. 'ldapcustom': ldapmycompany
```
------
This tasks also accepts the `force` environment variable which will skip the
confirmation dialog:
```bash
sudo gitlab-rake gitlab:ldap:rename_provider[old_provider,new_provider] force=yes
```
...@@ -61,6 +61,9 @@ version of Runner required. ...@@ -61,6 +61,9 @@ version of Runner required.
| **CI_RUNNER_DESCRIPTION** | 8.10 | 0.5 | The description of the runner as saved in GitLab | | **CI_RUNNER_DESCRIPTION** | 8.10 | 0.5 | The description of the runner as saved in GitLab |
| **CI_RUNNER_TAGS** | 8.10 | 0.5 | The defined runner tags | | **CI_RUNNER_TAGS** | 8.10 | 0.5 | The defined runner tags |
| **CI_DEBUG_TRACE** | all | 1.7 | Whether [debug tracing](#debug-tracing) is enabled | | **CI_DEBUG_TRACE** | all | 1.7 | Whether [debug tracing](#debug-tracing) is enabled |
| **GET_SOURCES_ATTEMPTS** | 8.15 | 1.9 | Number of attempts to fetch sources running a build |
| **ARTIFACT_DOWNLOAD_ATTEMPTS** | 8.15 | 1.9 | Number of attempts to download artifacts running a build |
| **RESTORE_CACHE_ATTEMPTS** | 8.15 | 1.9 | Number of attempts to restore the cache running a build |
| **GITLAB_USER_ID** | 8.12 | all | The id of the user who started the build | | **GITLAB_USER_ID** | 8.12 | all | The id of the user who started the build |
| **GITLAB_USER_EMAIL** | 8.12 | all | The email of the user who started the build | | **GITLAB_USER_EMAIL** | 8.12 | all | The email of the user who started the build |
......
...@@ -1034,6 +1034,31 @@ variables: ...@@ -1034,6 +1034,31 @@ variables:
GIT_STRATEGY: none GIT_STRATEGY: none
``` ```
## Build stages attempts
> Introduced in GitLab, it requires GitLab Runner v1.9+.
You can set the number for attempts the running build will try to execute each
of the following stages:
| Variable | Description |
|-------------------------|-------------|
| **GET_SOURCES_ATTEMPTS** | Number of attempts to fetch sources running a build |
| **ARTIFACT_DOWNLOAD_ATTEMPTS** | Number of attempts to download artifacts running a build |
| **RESTORE_CACHE_ATTEMPTS** | Number of attempts to restore the cache running a build |
The default is one single attempt.
Example:
```
variables:
GET_SOURCES_ATTEMPTS: "3"
```
You can set them in the global [`variables`](#variables) section or the [`variables`](#job-variables)
section for individual jobs.
## Shallow cloning ## Shallow cloning
> Introduced in GitLab 8.9 as an experimental feature. May change in future > Introduced in GitLab 8.9 as an experimental feature. May change in future
......
...@@ -37,7 +37,7 @@ graphs/dashboards. ...@@ -37,7 +37,7 @@ graphs/dashboards.
GitLab provides built-in tools to aid the process of improving performance: GitLab provides built-in tools to aid the process of improving performance:
* [Sherlock](profiling.md#sherlock) * [Sherlock](profiling.md#sherlock)
* [GitLab Performance Monitoring](../administration/monitoring/performance/monitoring.md) * [GitLab Performance Monitoring](../administration/monitoring/performance/introduction.md)
* [Request Profiling](../administration/monitoring/performance/request_profiling.md) * [Request Profiling](../administration/monitoring/performance/request_profiling.md)
GitLab employees can use GitLab.com's performance monitoring systems located at GitLab employees can use GitLab.com's performance monitoring systems located at
......
...@@ -5,7 +5,7 @@ Bitbucket.org account. ...@@ -5,7 +5,7 @@ Bitbucket.org account.
## Overview ## Overview
You can set up Bitbucket.org as an OAuth provider so that you can use your You can set up Bitbucket.org as an OAuth2 provider so that you can use your
credentials to authenticate into GitLab or import your projects from credentials to authenticate into GitLab or import your projects from
Bitbucket.org. Bitbucket.org.
...@@ -50,6 +50,7 @@ you to use. ...@@ -50,6 +50,7 @@ you to use.
Repositories: Read Repositories: Read
Pull Requests: Read Pull Requests: Read
Issues: Read Issues: Read
Wiki: Read and Write
``` ```
![Bitbucket OAuth settings page](img/bitbucket_oauth_settings_page.png) ![Bitbucket OAuth settings page](img/bitbucket_oauth_settings_page.png)
......
...@@ -4,7 +4,8 @@ ...@@ -4,7 +4,8 @@
- [Check](check.md) - [Check](check.md)
- [Cleanup](cleanup.md) - [Cleanup](cleanup.md)
- [Features](features.md) - [Features](features.md)
- [Maintenance](maintenance.md) and self-checks - [LDAP Maintenance](../administration/raketasks/ldap.md)
- [General Maintenance](maintenance.md) and self-checks
- [User management](user_management.md) - [User management](user_management.md)
- [Webhooks](web_hooks.md) - [Webhooks](web_hooks.md)
- [Import](import.md) of git repositories in bulk - [Import](import.md) of git repositories in bulk
......
...@@ -72,7 +72,7 @@ sudo -u git -H git checkout 8-15-stable-ee ...@@ -72,7 +72,7 @@ sudo -u git -H git checkout 8-15-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.1.0 sudo -u git -H git checkout v4.1.1
``` ```
### 6. Update gitlab-workhorse ### 6. Update gitlab-workhorse
......
...@@ -17,6 +17,7 @@ to enable this if not already. ...@@ -17,6 +17,7 @@ to enable this if not already.
- the pull requests (GitLab 8.4+) - the pull requests (GitLab 8.4+)
- the pull request comments (GitLab 8.15+) - the pull request comments (GitLab 8.15+)
- the milestones (GitLab 8.15+) - the milestones (GitLab 8.15+)
- the wiki (GitLab 8.15+)
- References to pull requests and issues are preserved (GitLab 8.7+) - References to pull requests and issues are preserved (GitLab 8.7+)
- Repository public access is retained. If a repository is private in Bitbucket - Repository public access is retained. If a repository is private in Bitbucket
it will be created as private in GitLab as well. it will be created as private in GitLab as well.
......
Feature: Admin Appearance
Scenario: Create new appearance
Given I sign in as an admin
And I visit admin appearance page
When submit form with new appearance
Then I should be redirected to admin appearance page
And I should see newly created appearance
Scenario: Preview appearance
Given application has custom appearance
And I sign in as an admin
When I visit admin appearance page
And I click preview button
Then I should see a customized appearance
Scenario: Custom sign-in page
Given application has custom appearance
When I visit login page
Then I should see a customized appearance
Scenario: Appearance logo
Given application has custom appearance
And I sign in as an admin
And I visit admin appearance page
When I attach a logo
Then I should see a logo
And I remove the logo
Then I should see logo removed
Scenario: Header logos
Given application has custom appearance
And I sign in as an admin
And I visit admin appearance page
When I attach header logos
Then I should see header logos
And I remove the header logos
Then I should see header logos removed
@admin
Feature: Admin Applications
Background:
Given I sign in as an admin
And I visit applications page
Scenario: I can manage application
Then I click on new application button
And I should see application form
Then I fill application form out and submit
And I see application
Then I click edit
And I see edit application form
Then I change name of application and submit
And I see that application was changed
Then I visit applications page
And I click to remove application
Then I see that application is removed
\ No newline at end of file
@admin
Feature: Admin Broadcast Messages
Background:
Given I sign in as an admin
And application already has a broadcast message
And I visit admin messages page
Scenario: See broadcast messages list
Then I should see all broadcast messages
Scenario: Create a customized broadcast message
When submit form with new customized broadcast message
Then I should be redirected to admin messages page
And I should see newly created broadcast message
Then I visit dashboard page
And I should see a customized broadcast message
Scenario: Edit an existing broadcast message
When I edit an existing broadcast message
And I change the broadcast message text
Then I should be redirected to admin messages page
And I should see the updated broadcast message
Scenario: Remove an existing broadcast message
When I remove an existing broadcast message
Then I should be redirected to admin messages page
And I should not see the removed broadcast message
@javascript
Scenario: Live preview a customized broadcast message
When I visit admin messages page
And I enter a broadcast message with Markdown
Then I should see a live preview of the rendered broadcast message
@admin
Feature: Admin Deploy Keys
Background:
Given I sign in as an admin
And there are public deploy keys in system
Scenario: Deploy Keys list
When I visit admin deploy keys page
Then I should see all public deploy keys
Scenario: Deploy Keys new
When I visit admin deploy keys page
And I click 'New Deploy Key'
And I submit new deploy key
Then I should be on admin deploy keys page
And I should see newly created deploy key
Feature: Admin Issues Labels
Background:
Given I sign in as an admin
And I have labels: "bug", "feature", "enhancement"
Given I visit admin labels page
Scenario: I should see labels list
Then I should see label 'bug'
And I should see label 'feature'
Scenario: I create new label
Given I submit new label 'support'
Then I should see label 'support'
Scenario: I edit label
Given I visit 'bug' label edit page
When I change label 'bug' to 'fix'
Then I should not see label 'bug'
Then I should see label 'fix'
Scenario: I remove label
When I remove label 'bug'
Then I should not see label 'bug'
@javascript
Scenario: I delete all labels
When I delete all labels
Then I should see labels help message
Scenario: I create a label with invalid color
Given I visit admin new label page
When I submit new label with invalid color
Then I should see label color error message
Scenario: I create a label that already exists
Given I visit admin new label page
When I submit new label 'bug'
Then I should see label exist error message
class Spinach::Features::AdminApplications < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
include SharedAdmin
step 'I click on new application button' do
click_on 'New Application'
end
step 'I should see application form' do
expect(page).to have_content "New application"
end
step 'I fill application form out and submit' do
fill_in :doorkeeper_application_name, with: 'test'
fill_in :doorkeeper_application_redirect_uri, with: 'https://test.com'
click_on "Submit"
end
step 'I see application' do
expect(page).to have_content "Application: test"
expect(page).to have_content "Application Id"
expect(page).to have_content "Secret"
end
step 'I click edit' do
click_on "Edit"
end
step 'I see edit application form' do
expect(page).to have_content "Edit application"
end
step 'I change name of application and submit' do
expect(page).to have_content "Edit application"
fill_in :doorkeeper_application_name, with: 'test_changed'
click_on "Submit"
end
step 'I see that application was changed' do
expect(page).to have_content "test_changed"
expect(page).to have_content "Application Id"
expect(page).to have_content "Secret"
end
step 'I click to remove application' do
page.within '.oauth-applications' do
click_on "Destroy"
end
end
step "I see that application is removed" do
expect(page.find(".oauth-applications")).not_to have_content "test_changed"
end
end
class Spinach::Features::AdminIssuesLabels < Spinach::FeatureSteps
include SharedAuthentication
include SharedProject
include SharedPaths
step 'I visit \'bug\' label edit page' do
visit edit_admin_label_path(bug_label)
end
step 'I visit admin new label page' do
visit new_admin_label_path
end
step 'I visit admin labels page' do
visit admin_labels_path
end
step 'I remove label \'bug\'' do
page.within "#label_#{bug_label.id}" do
click_link 'Delete'
end
end
step 'I have labels: "bug", "feature", "enhancement"' do
["bug", "feature", "enhancement"].each do |title|
Label.create(title: title, template: true)
end
end
step 'I delete all labels' do
page.within '.labels' do
page.all('.btn-remove').each do |remove|
remove.click
sleep 0.05
end
end
end
step 'I should see labels help message' do
page.within '.labels' do
expect(page).to have_content 'There are no labels yet'
end
end
step 'I submit new label \'support\'' do
visit new_admin_label_path
fill_in 'Title', with: 'support'
fill_in 'Background color', with: '#F95610'
click_button 'Save'
end
step 'I submit new label \'bug\'' do
visit new_admin_label_path
fill_in 'Title', with: 'bug'
fill_in 'Background color', with: '#F95610'
click_button 'Save'
end
step 'I submit new label with invalid color' do
visit new_admin_label_path
fill_in 'Title', with: 'support'
fill_in 'Background color', with: '#12'
click_button 'Save'
end
step 'I should see label exist error message' do
page.within '.label-form' do
expect(page).to have_content 'Title has already been taken'
end
end
step 'I should see label color error message' do
page.within '.label-form' do
expect(page).to have_content 'Color must be a valid color code'
end
end
step 'I should see label \'feature\'' do
page.within '.manage-labels-list' do
expect(page).to have_content 'feature'
end
end
step 'I should see label \'bug\'' do
page.within '.manage-labels-list' do
expect(page).to have_content 'bug'
end
end
step 'I should not see label \'bug\'' do
page.within '.manage-labels-list' do
expect(page).not_to have_content 'bug'
end
end
step 'I should see label \'support\'' do
page.within '.manage-labels-list' do
expect(page).to have_content 'support'
end
end
step 'I change label \'bug\' to \'fix\'' do
fill_in 'Title', with: 'fix'
fill_in 'Background color', with: '#F15610'
click_button 'Save'
end
step 'I should see label \'fix\'' do
page.within '.manage-labels-list' do
expect(page).to have_content 'fix'
end
end
def bug_label
Label.templates.find_or_create_by(title: 'bug')
end
end
...@@ -199,10 +199,6 @@ module SharedPaths ...@@ -199,10 +199,6 @@ module SharedPaths
visit admin_groups_path visit admin_groups_path
end end
step 'I visit admin appearance page' do
visit admin_appearances_path
end
step 'I visit admin teams page' do step 'I visit admin teams page' do
visit admin_teams_path visit admin_teams_path
end end
...@@ -219,10 +215,6 @@ module SharedPaths ...@@ -219,10 +215,6 @@ module SharedPaths
visit admin_spam_logs_path visit admin_spam_logs_path
end end
step 'I visit applications page' do
visit admin_applications_path
end
step 'I visit push rules page' do step 'I visit push rules page' do
visit admin_push_rule_path visit admin_push_rule_path
end end
......
...@@ -8,6 +8,10 @@ module API ...@@ -8,6 +8,10 @@ module API
gitlab_ci_ymls: { gitlab_ci_ymls: {
klass: Gitlab::Template::GitlabCiYmlTemplate, klass: Gitlab::Template::GitlabCiYmlTemplate,
gitlab_version: 8.9 gitlab_version: 8.9
},
dockerfiles: {
klass: Gitlab::Template::DockerfileTemplate,
gitlab_version: 8.15
} }
}.freeze }.freeze
PROJECT_TEMPLATE_REGEX = PROJECT_TEMPLATE_REGEX =
...@@ -51,7 +55,7 @@ module API ...@@ -51,7 +55,7 @@ module API
end end
params do params do
optional :popular, type: Boolean, desc: 'If passed, returns only popular licenses' optional :popular, type: Boolean, desc: 'If passed, returns only popular licenses'
end end
get route do get route do
options = { options = {
featured: declared(params).popular.present? ? true : nil featured: declared(params).popular.present? ? true : nil
...@@ -69,7 +73,7 @@ module API ...@@ -69,7 +73,7 @@ module API
end end
params do params do
requires :name, type: String, desc: 'The name of the template' requires :name, type: String, desc: 'The name of the template'
end end
get route, requirements: { name: /[\w\.-]+/ } do get route, requirements: { name: /[\w\.-]+/ } do
not_found!('License') unless Licensee::License.find(declared(params).name) not_found!('License') unless Licensee::License.find(declared(params).name)
...@@ -78,7 +82,7 @@ module API ...@@ -78,7 +82,7 @@ module API
present template, with: Entities::RepoLicense present template, with: Entities::RepoLicense
end end
end end
GLOBAL_TEMPLATE_TYPES.each do |template_type, properties| GLOBAL_TEMPLATE_TYPES.each do |template_type, properties|
klass = properties[:klass] klass = properties[:klass]
gitlab_version = properties[:gitlab_version] gitlab_version = properties[:gitlab_version]
...@@ -104,7 +108,7 @@ module API ...@@ -104,7 +108,7 @@ module API
end end
params do params do
requires :name, type: String, desc: 'The name of the template' requires :name, type: String, desc: 'The name of the template'
end end
get route do get route do
new_template = klass.find(declared(params).name) new_template = klass.find(declared(params).name)
......
...@@ -51,6 +51,10 @@ module Bitbucket ...@@ -51,6 +51,10 @@ module Bitbucket
raw['scm'] == 'git' raw['scm'] == 'git'
end end
def has_wiki?
raw['has_wiki']
end
def visibility_level def visibility_level
if raw['is_private'] if raw['is_private']
Gitlab::VisibilityLevel::PRIVATE Gitlab::VisibilityLevel::PRIVATE
......
...@@ -41,7 +41,7 @@ module Ci ...@@ -41,7 +41,7 @@ module Ci
put ":id" do put ":id" do
authenticate_runner! authenticate_runner!
build = Ci::Build.where(runner_id: current_runner.id).running.find(params[:id]) build = Ci::Build.where(runner_id: current_runner.id).running.find(params[:id])
forbidden!('Build has been erased!') if build.erased? validate_build!(build)
update_runner_info update_runner_info
...@@ -71,9 +71,7 @@ module Ci ...@@ -71,9 +71,7 @@ module Ci
# PATCH /builds/:id/trace.txt # PATCH /builds/:id/trace.txt
patch ":id/trace.txt" do patch ":id/trace.txt" do
build = Ci::Build.find_by_id(params[:id]) build = Ci::Build.find_by_id(params[:id])
not_found! unless build authenticate_build!(build)
authenticate_build_token!(build)
forbidden!('Build has been erased!') if build.erased?
error!('400 Missing header Content-Range', 400) unless request.headers.has_key?('Content-Range') error!('400 Missing header Content-Range', 400) unless request.headers.has_key?('Content-Range')
content_range = request.headers['Content-Range'] content_range = request.headers['Content-Range']
...@@ -104,8 +102,7 @@ module Ci ...@@ -104,8 +102,7 @@ module Ci
Gitlab::Workhorse.verify_api_request!(headers) Gitlab::Workhorse.verify_api_request!(headers)
not_allowed! unless Gitlab.config.artifacts.enabled not_allowed! unless Gitlab.config.artifacts.enabled
build = Ci::Build.find_by_id(params[:id]) build = Ci::Build.find_by_id(params[:id])
not_found! unless build authenticate_build!(build)
authenticate_build_token!(build)
forbidden!('build is not running') unless build.running? forbidden!('build is not running') unless build.running?
if params[:filesize] if params[:filesize]
...@@ -142,10 +139,8 @@ module Ci ...@@ -142,10 +139,8 @@ module Ci
require_gitlab_workhorse! require_gitlab_workhorse!
not_allowed! unless Gitlab.config.artifacts.enabled not_allowed! unless Gitlab.config.artifacts.enabled
build = Ci::Build.find_by_id(params[:id]) build = Ci::Build.find_by_id(params[:id])
not_found! unless build authenticate_build!(build)
authenticate_build_token!(build)
forbidden!('Build is not running!') unless build.running? forbidden!('Build is not running!') unless build.running?
forbidden!('Build has been erased!') if build.erased?
artifacts_upload_path = ArtifactUploader.artifacts_upload_path artifacts_upload_path = ArtifactUploader.artifacts_upload_path
artifacts = uploaded_file(:file, artifacts_upload_path) artifacts = uploaded_file(:file, artifacts_upload_path)
...@@ -176,8 +171,7 @@ module Ci ...@@ -176,8 +171,7 @@ module Ci
# GET /builds/:id/artifacts # GET /builds/:id/artifacts
get ":id/artifacts" do get ":id/artifacts" do
build = Ci::Build.find_by_id(params[:id]) build = Ci::Build.find_by_id(params[:id])
not_found! unless build authenticate_build!(build)
authenticate_build_token!(build)
artifacts_file = build.artifacts_file artifacts_file = build.artifacts_file
unless artifacts_file.file_storage? unless artifacts_file.file_storage?
...@@ -202,8 +196,7 @@ module Ci ...@@ -202,8 +196,7 @@ module Ci
# DELETE /builds/:id/artifacts # DELETE /builds/:id/artifacts
delete ":id/artifacts" do delete ":id/artifacts" do
build = Ci::Build.find_by_id(params[:id]) build = Ci::Build.find_by_id(params[:id])
not_found! unless build authenticate_build!(build)
authenticate_build_token!(build)
build.erase_artifacts! build.erase_artifacts!
end end
......
...@@ -13,8 +13,19 @@ module Ci ...@@ -13,8 +13,19 @@ module Ci
forbidden! unless current_runner forbidden! unless current_runner
end end
def authenticate_build_token!(build) def authenticate_build!(build)
forbidden! unless build_token_valid?(build) validate_build!(build) do
forbidden! unless build_token_valid?(build)
end
end
def validate_build!(build)
not_found! unless build
yield if block_given?
forbidden!('Project has been deleted!') unless build.project
forbidden!('Build has been erased!') if build.erased?
end end
def runner_registration_token_valid? def runner_registration_token_valid?
......
...@@ -118,7 +118,7 @@ module Ci ...@@ -118,7 +118,7 @@ module Ci
.merge(job_variables(name)) .merge(job_variables(name))
variables.map do |key, value| variables.map do |key, value|
{ key: key, value: value, public: true } { key: key.to_s, value: value, public: true }
end end
end end
......
module Gitlab module Gitlab
module BitbucketImport module BitbucketImport
class Importer class Importer
include Gitlab::ShellAdapter
LABELS = [{ title: 'bug', color: '#FF0000' }, LABELS = [{ title: 'bug', color: '#FF0000' },
{ title: 'enhancement', color: '#428BCA' }, { title: 'enhancement', color: '#428BCA' },
{ title: 'proposal', color: '#69D100' }, { title: 'proposal', color: '#69D100' },
...@@ -18,6 +20,7 @@ module Gitlab ...@@ -18,6 +20,7 @@ module Gitlab
end end
def execute def execute
import_wiki
import_issues import_issues
import_pull_requests import_pull_requests
handle_errors handle_errors
...@@ -55,6 +58,16 @@ module Gitlab ...@@ -55,6 +58,16 @@ module Gitlab
@repo ||= client.repo(project.import_source) @repo ||= client.repo(project.import_source)
end end
def import_wiki
return if project.wiki.repository_exists?
path_with_namespace = "#{project.path_with_namespace}.wiki"
import_url = project.import_url.sub(/\.git\z/, ".git/wiki")
gitlab_shell.import_repository(project.repository_storage_path, path_with_namespace, import_url)
rescue StandardError => e
errors << { type: :wiki, errors: e.message }
end
def import_issues def import_issues
return unless repo.issues_enabled? return unless repo.issues_enabled?
......
...@@ -22,9 +22,16 @@ module Gitlab ...@@ -22,9 +22,16 @@ module Gitlab
import_type: 'bitbucket', import_type: 'bitbucket',
import_source: repo.full_name, import_source: repo.full_name,
import_url: repo.clone_url(session_data[:token]), import_url: repo.clone_url(session_data[:token]),
import_data: { credentials: session_data } import_data: { credentials: session_data },
skip_wiki: skip_wiki
).execute ).execute
end end
private
def skip_wiki
repo.has_wiki?
end
end end
end end
end end
...@@ -17,6 +17,10 @@ module Gitlab ...@@ -17,6 +17,10 @@ module Gitlab
'icon_status_manual' 'icon_status_manual'
end end
def group
'manual'
end
def has_action? def has_action?
can?(user, :update_build, subject) can?(user, :update_build, subject)
end end
......
...@@ -17,6 +17,10 @@ module Gitlab ...@@ -17,6 +17,10 @@ module Gitlab
'icon_status_manual' 'icon_status_manual'
end end
def group
'manual'
end
def has_action? def has_action?
can?(user, :update_build, subject) can?(user, :update_build, subject)
end end
......
...@@ -22,15 +22,8 @@ module Gitlab ...@@ -22,15 +22,8 @@ module Gitlab
raise NotImplementedError raise NotImplementedError
end end
# Deprecation warning: this method is here because we need to maintain def group
# backwards compatibility with legacy statuses. We often do something self.class.name.demodulize.underscore
# like "ci-status ci-status-#{status}" to set CSS class.
#
# `to_s` method should be renamed to `group` at some point, after
# phasing legacy satuses out.
#
def to_s
self.class.name.demodulize.downcase.underscore
end end
def has_details? def has_details?
......
...@@ -17,7 +17,7 @@ module Gitlab ...@@ -17,7 +17,7 @@ module Gitlab
'icon_status_warning' 'icon_status_warning'
end end
def to_s def group
'success_with_warnings' 'success_with_warnings'
end end
......
...@@ -120,7 +120,7 @@ module Gitlab ...@@ -120,7 +120,7 @@ module Gitlab
members_mapper: members_mapper, members_mapper: members_mapper,
user: @user, user: @user,
project_id: restored_project.id) project_id: restored_project.id)
end end.compact
relation_hash_list.is_a?(Array) ? relation_array : relation_array.first relation_hash_list.is_a?(Array) ? relation_array : relation_array.first
end end
......
...@@ -14,7 +14,7 @@ module Gitlab ...@@ -14,7 +14,7 @@ module Gitlab
priorities: :label_priorities, priorities: :label_priorities,
label: :project_label }.freeze label: :project_label }.freeze
USER_REFERENCES = %w[author_id assignee_id updated_by_id user_id created_by_id].freeze USER_REFERENCES = %w[author_id assignee_id updated_by_id user_id created_by_id merge_user_id].freeze
PROJECT_REFERENCES = %w[project_id source_project_id gl_project_id target_project_id].freeze PROJECT_REFERENCES = %w[project_id source_project_id gl_project_id target_project_id].freeze
...@@ -40,6 +40,8 @@ module Gitlab ...@@ -40,6 +40,8 @@ module Gitlab
# the relation_hash, updating references with new object IDs, mapping users using # the relation_hash, updating references with new object IDs, mapping users using
# the "members_mapper" object, also updating notes if required. # the "members_mapper" object, also updating notes if required.
def create def create
return nil if unknown_service?
setup_models setup_models
generate_imported_object generate_imported_object
...@@ -99,6 +101,8 @@ module Gitlab ...@@ -99,6 +101,8 @@ module Gitlab
def generate_imported_object def generate_imported_object
if BUILD_MODELS.include?(@relation_name) # call #trace= method after assigning the other attributes if BUILD_MODELS.include?(@relation_name) # call #trace= method after assigning the other attributes
trace = @relation_hash.delete('trace') trace = @relation_hash.delete('trace')
@relation_hash.delete('token')
imported_object do |object| imported_object do |object|
object.trace = trace object.trace = trace
object.commit_id = nil object.commit_id = nil
...@@ -215,6 +219,11 @@ module Gitlab ...@@ -215,6 +219,11 @@ module Gitlab
existing_object existing_object
end end
end end
def unknown_service?
@relation_name == :services && parsed_relation_hash['type'] &&
!Object.const_defined?(parsed_relation_hash['type'])
end
end end
end end
end end
module Gitlab
module Serialize
module Ci
# This serializer could make sure our YAML variables' keys and values
# are always strings. This is more for legacy build data because
# from now on we convert them into strings before saving to database.
module Variables
extend self
def load(string)
return unless string
object = YAML.safe_load(string, [Symbol])
object.map do |variable|
variable[:key] = variable[:key].to_s
variable
end
end
def dump(object)
YAML.dump(object)
end
end
end
end
end
module Gitlab
module Template
class DockerfileTemplate < BaseTemplate
def content
explanation = "# This file is a template, and might need editing before it works on your project."
[explanation, super].join("\n")
end
class << self
def extension
'Dockerfile'
end
def categories
{
"General" => ''
}
end
def base_dir
Rails.root.join('vendor/dockerfile')
end
def finder(project = nil)
Gitlab::Template::Finders::GlobalTemplateFinder.new(self.base_dir, self.extension, self.categories)
end
end
end
end
end
...@@ -20,6 +20,11 @@ upstream gitlab-workhorse { ...@@ -20,6 +20,11 @@ upstream gitlab-workhorse {
server unix:/home/git/gitlab/tmp/sockets/gitlab-workhorse.socket fail_timeout=0; server unix:/home/git/gitlab/tmp/sockets/gitlab-workhorse.socket fail_timeout=0;
} }
map $http_upgrade $connection_upgrade_gitlab {
default upgrade;
'' close;
}
## Normal HTTP host ## Normal HTTP host
server { server {
## Either remove "default_server" from the listen line below, ## Either remove "default_server" from the listen line below,
...@@ -53,6 +58,8 @@ server { ...@@ -53,6 +58,8 @@ server {
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade_gitlab;
proxy_pass http://gitlab-workhorse; proxy_pass http://gitlab-workhorse;
} }
......
...@@ -24,6 +24,11 @@ upstream gitlab-workhorse { ...@@ -24,6 +24,11 @@ upstream gitlab-workhorse {
server unix:/home/git/gitlab/tmp/sockets/gitlab-workhorse.socket fail_timeout=0; server unix:/home/git/gitlab/tmp/sockets/gitlab-workhorse.socket fail_timeout=0;
} }
map $http_upgrade $connection_upgrade_gitlab_ssl {
default upgrade;
'' close;
}
## Redirects all HTTP traffic to the HTTPS host ## Redirects all HTTP traffic to the HTTPS host
server { server {
## Either remove "default_server" from the listen line below, ## Either remove "default_server" from the listen line below,
...@@ -98,6 +103,9 @@ server { ...@@ -98,6 +103,9 @@ server {
proxy_set_header X-Forwarded-Ssl on; proxy_set_header X-Forwarded-Ssl on;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade_gitlab_ssl;
proxy_pass http://gitlab-workhorse; proxy_pass http://gitlab-workhorse;
} }
......
namespace :gitlab do
namespace :ldap do
desc 'GitLab | LDAP | Rename provider'
task :rename_provider, [:old_provider, :new_provider] => :environment do |_, args|
old_provider = args[:old_provider] ||
prompt('What is the old provider? Ex. \'ldapmain\': '.color(:blue))
new_provider = args[:new_provider] ||
prompt('What is the new provider ID? Ex. \'ldapcustom\': '.color(:blue))
puts '' # Add some separation in the output
identities = Identity.where(provider: old_provider)
identity_count = identities.count
if identities.empty?
puts "Found no user identities with '#{old_provider}' provider."
puts 'Please check the provider name and try again.'
exit 1
end
plural_id_count = ActionController::Base.helpers.pluralize(identity_count, 'user')
unless ENV['force'] == 'yes'
puts "#{plural_id_count} with provider '#{old_provider}' will be updated to '#{new_provider}'"
puts 'If the new provider is incorrect, users will be unable to sign in'
ask_to_continue
puts ''
end
updated_count = identities.update_all(provider: new_provider)
if updated_count == identity_count
puts 'User identities were successfully updated'.color(:green)
else
plural_updated_count = ActionController::Base.helpers.pluralize(updated_count, 'user')
puts 'Some user identities could not be updated'.color(:red)
puts "Successfully updated #{plural_updated_count} out of #{plural_id_count} total"
end
end
end
end
...@@ -25,5 +25,10 @@ describe Projects::BlameController do ...@@ -25,5 +25,10 @@ describe Projects::BlameController do
let(:id) { 'master/files/ruby/popen.rb' } let(:id) { 'master/files/ruby/popen.rb' }
it { is_expected.to respond_with(:success) } it { is_expected.to respond_with(:success) }
end end
context "invalid file" do
let(:id) { 'master/files/ruby/missing_file.rb'}
it { expect(response).to have_http_status(404) }
end
end end
end end
...@@ -22,7 +22,7 @@ FactoryGirl.define do ...@@ -22,7 +22,7 @@ FactoryGirl.define do
yaml_variables do yaml_variables do
[ [
{ key: :DB_NAME, value: 'postgres', public: true } { key: 'DB_NAME', value: 'postgres', public: true }
] ]
end end
......
class Spinach::Features::AdminAppearance < Spinach::FeatureSteps require 'spec_helper'
include SharedAuthentication
include SharedPaths feature 'Admin Appearance', feature: true do
let!(:appearance) { create(:appearance) }
scenario 'Create new appearance' do
login_as :admin
visit admin_appearances_path
step 'submit form with new appearance' do
fill_in 'appearance_title', with: 'MyCompany' fill_in 'appearance_title', with: 'MyCompany'
fill_in 'appearance_description', with: 'dev server' fill_in 'appearance_description', with: 'dev server'
click_button 'Save' click_button 'Save'
end
step 'I should be redirected to admin appearance page' do
expect(current_path).to eq admin_appearances_path expect(current_path).to eq admin_appearances_path
expect(page).to have_content 'Appearance settings' expect(page).to have_content 'Appearance settings'
end
step 'I should see newly created appearance' do
expect(page).to have_field('appearance_title', with: 'MyCompany') expect(page).to have_field('appearance_title', with: 'MyCompany')
expect(page).to have_field('appearance_description', with: 'dev server') expect(page).to have_field('appearance_description', with: 'dev server')
expect(page).to have_content 'Last edit' expect(page).to have_content 'Last edit'
end end
step 'I click preview button' do scenario 'Preview appearance' do
login_as :admin
visit admin_appearances_path
click_link "Preview" click_link "Preview"
end
step 'application has custom appearance' do expect_page_has_custom_appearance(appearance)
create(:appearance)
end end
step 'I should see a customized appearance' do scenario 'Custom sign-in page' do
expect(page).to have_content appearance.title visit new_user_session_path
expect(page).to have_content appearance.description expect_page_has_custom_appearance(appearance)
end end
step 'I attach a logo' do scenario 'Appearance logo' do
attach_file(:appearance_logo, Rails.root.join('spec', 'fixtures', 'dk.png')) login_as :admin
click_button 'Save' visit admin_appearances_path
end
step 'I attach header logos' do attach_file(:appearance_logo, logo_fixture)
attach_file(:appearance_header_logo, Rails.root.join('spec', 'fixtures', 'dk.png'))
click_button 'Save' click_button 'Save'
end expect(page).to have_css(logo_selector)
step 'I should see a logo' do click_link 'Remove logo'
expect(page).to have_xpath('//img[@src="/uploads/appearance/logo/1/dk.png"]') expect(page).not_to have_css(logo_selector)
end end
step 'I should see header logos' do scenario 'Header logos' do
expect(page).to have_xpath('//img[@src="/uploads/appearance/header_logo/1/dk.png"]') login_as :admin
end visit admin_appearances_path
step 'I remove the logo' do attach_file(:appearance_header_logo, logo_fixture)
click_link 'Remove logo' click_button 'Save'
end expect(page).to have_css(header_logo_selector)
step 'I remove the header logos' do
click_link 'Remove header logo' click_link 'Remove header logo'
expect(page).not_to have_css(header_logo_selector)
end
def expect_page_has_custom_appearance(appearance)
expect(page).to have_content appearance.title
expect(page).to have_content appearance.description
end end
step 'I should see logo removed' do def logo_selector
expect(page).not_to have_xpath('//img[@src="/uploads/appearance/logo/1/gitlab_logo.png"]') '//img[@src^="/uploads/appearance/logo"]'
end end
step 'I should see header logos removed' do def header_logo_selector
expect(page).not_to have_xpath('//img[@src="/uploads/appearance/header_logo/1/header_logo_light.png"]') '//img[@src^="/uploads/appearance/header_logo"]'
end end
def appearance def logo_fixture
Appearance.last Rails.root.join('spec', 'fixtures', 'dk.png')
end end
end end
class Spinach::Features::AdminBroadcastMessages < Spinach::FeatureSteps require 'spec_helper'
include SharedAuthentication
include SharedPaths
step 'application already has a broadcast message' do feature 'Admin Broadcast Messages', feature: true do
FactoryGirl.create(:broadcast_message, :expired, message: "Migration to new server") before do
login_as :admin
create(:broadcast_message, :expired, message: 'Migration to new server')
visit admin_broadcast_messages_path
end end
step 'I should see all broadcast messages' do scenario 'See broadcast messages list' do
expect(page).to have_content "Migration to new server" expect(page).to have_content 'Migration to new server'
end end
step 'I should be redirected to admin messages page' do scenario 'Create a customized broadcast message' do
expect(current_path).to eq admin_broadcast_messages_path
end
step 'I should see newly created broadcast message' do
expect(page).to have_content 'Application update from 4:00 CST to 5:00 CST'
end
step 'submit form with new customized broadcast message' do
fill_in 'broadcast_message_message', with: 'Application update from **4:00 CST to 5:00 CST**' fill_in 'broadcast_message_message', with: 'Application update from **4:00 CST to 5:00 CST**'
fill_in 'broadcast_message_color', with: '#f2dede' fill_in 'broadcast_message_color', with: '#f2dede'
fill_in 'broadcast_message_font', with: '#b94a48' fill_in 'broadcast_message_font', with: '#b94a48'
select Date.today.next_year.year, from: "broadcast_message_ends_at_1i" select Date.today.next_year.year, from: 'broadcast_message_ends_at_1i'
click_button "Add broadcast message" click_button 'Add broadcast message'
end
step 'I should see a customized broadcast message' do expect(current_path).to eq admin_broadcast_messages_path
expect(page).to have_content 'Application update from 4:00 CST to 5:00 CST' expect(page).to have_content 'Application update from 4:00 CST to 5:00 CST'
expect(page).to have_selector 'strong', text: '4:00 CST to 5:00 CST' expect(page).to have_selector 'strong', text: '4:00 CST to 5:00 CST'
expect(page).to have_selector %(div[style="background-color: #f2dede; color: #b94a48"]) expect(page).to have_selector %(div[style="background-color: #f2dede; color: #b94a48"])
end end
step 'I edit an existing broadcast message' do scenario 'Edit an existing broadcast message' do
click_link 'Edit' click_link 'Edit'
end
step 'I change the broadcast message text' do
fill_in 'broadcast_message_message', with: 'Application update RIGHT NOW' fill_in 'broadcast_message_message', with: 'Application update RIGHT NOW'
click_button 'Update broadcast message' click_button 'Update broadcast message'
end
step 'I should see the updated broadcast message' do expect(current_path).to eq admin_broadcast_messages_path
expect(page).to have_content "Application update RIGHT NOW" expect(page).to have_content 'Application update RIGHT NOW'
end end
step 'I remove an existing broadcast message' do scenario 'Remove an existing broadcast message' do
click_link 'Remove' click_link 'Remove'
end
step 'I should not see the removed broadcast message' do expect(current_path).to eq admin_broadcast_messages_path
expect(page).not_to have_content 'Migration to new server' expect(page).not_to have_content 'Migration to new server'
end end
step 'I enter a broadcast message with Markdown' do scenario 'Live preview a customized broadcast message', js: true do
fill_in 'broadcast_message_message', with: "Live **Markdown** previews. :tada:" fill_in 'broadcast_message_message', with: "Live **Markdown** previews. :tada:"
end
step 'I should see a live preview of the rendered broadcast message' do
page.within('.broadcast-message-preview') do page.within('.broadcast-message-preview') do
expect(page).to have_selector('strong', text: 'Markdown') expect(page).to have_selector('strong', text: 'Markdown')
expect(page).to have_selector('img.emoji') expect(page).to have_selector('img.emoji')
......
class Spinach::Features::AdminDeployKeys < Spinach::FeatureSteps require 'spec_helper'
include SharedAuthentication
include SharedPaths
include SharedAdmin
step 'there are public deploy keys in system' do RSpec.describe 'admin deploy keys', type: :feature do
create(:deploy_key, public: true) let!(:deploy_key) { create(:deploy_key, public: true) }
create(:another_deploy_key, public: true) let!(:another_deploy_key) { create(:another_deploy_key, public: true) }
end
step 'I should see all public deploy keys' do before do
DeployKey.are_public.each do |p| login_as(:admin)
expect(page).to have_content p.title
end
end end
step 'I visit admin deploy key page' do it 'show all public deploy keys' do
visit admin_deploy_key_path(deploy_key) visit admin_deploy_keys_path
expect(page).to have_content(deploy_key.title)
expect(page).to have_content(another_deploy_key.title)
end end
step 'I visit admin deploy keys page' do it 'creates new deploy key' do
visit admin_deploy_keys_path visit admin_deploy_keys_path
end
step 'I click \'New Deploy Key\'' do
click_link 'New Deploy Key' click_link 'New Deploy Key'
end fill_in 'deploy_key_title', with: 'laptop'
fill_in 'deploy_key_key', with: 'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAzrEJUIR6Y03TCE9rIJ+GqTBvgb8t1jI9h5UBzCLuK4VawOmkLornPqLDrGbm6tcwM/wBrrLvVOqi2HwmkKEIecVO0a64A4rIYScVsXIniHRS6w5twyn1MD3sIbN+socBDcaldECQa2u1dI3tnNVcs8wi77fiRe7RSxePsJceGoheRQgC8AZ510UdIlO+9rjIHUdVN7LLyz512auAfYsgx1OfablkQ/XJcdEwDNgi9imI6nAXhmoKUm1IPLT2yKajTIC64AjLOnE0YyCh6+7RFMpiMyu1qiOCpdjYwTgBRiciNRZCH8xIedyCoAmiUgkUT40XYHwLuwiPJICpkAzp7Q== user@laptop'
click_button 'Create'
step 'I submit new deploy key' do
fill_in "deploy_key_title", with: "laptop"
fill_in "deploy_key_key", with: "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAzrEJUIR6Y03TCE9rIJ+GqTBvgb8t1jI9h5UBzCLuK4VawOmkLornPqLDrGbm6tcwM/wBrrLvVOqi2HwmkKEIecVO0a64A4rIYScVsXIniHRS6w5twyn1MD3sIbN+socBDcaldECQa2u1dI3tnNVcs8wi77fiRe7RSxePsJceGoheRQgC8AZ510UdIlO+9rjIHUdVN7LLyz512auAfYsgx1OfablkQ/XJcdEwDNgi9imI6nAXhmoKUm1IPLT2yKajTIC64AjLOnE0YyCh6+7RFMpiMyu1qiOCpdjYwTgBRiciNRZCH8xIedyCoAmiUgkUT40XYHwLuwiPJICpkAzp7Q== user@laptop"
click_button "Create"
end
step 'I should be on admin deploy keys page' do
expect(current_path).to eq admin_deploy_keys_path expect(current_path).to eq admin_deploy_keys_path
end expect(page).to have_content('laptop')
step 'I should see newly created deploy key' do
expect(page).to have_content(deploy_key.title)
end
def deploy_key
@deploy_key ||= DeployKey.are_public.first
end end
end end
require 'spec_helper'
RSpec.describe 'admin issues labels' do
include WaitForAjax
let!(:bug_label) { Label.create(title: 'bug', template: true) }
let!(:feature_label) { Label.create(title: 'feature', template: true) }
before do
login_as :admin
end
describe 'list' do
before do
visit admin_labels_path
end
it 'renders labels list' do
page.within '.manage-labels-list' do
expect(page).to have_content('bug')
expect(page).to have_content('feature')
end
end
it 'deletes label' do
page.within "#label_#{bug_label.id}" do
click_link 'Delete'
end
page.within '.manage-labels-list' do
expect(page).not_to have_content('bug')
end
end
it 'deletes all labels', js: true do
page.within '.labels' do
page.all('.btn-remove').each do |remove|
wait_for_ajax
remove.click
end
end
page.within '.manage-labels-list' do
expect(page).not_to have_content('bug')
expect(page).not_to have_content('feature_label')
end
end
end
describe 'create' do
before do
visit new_admin_label_path
end
it 'creates new label' do
fill_in 'Title', with: 'support'
fill_in 'Background color', with: '#F95610'
click_button 'Save'
page.within '.manage-labels-list' do
expect(page).to have_content('support')
end
end
it 'does not creates label with invalid color' do
fill_in 'Title', with: 'support'
fill_in 'Background color', with: '#12'
click_button 'Save'
page.within '.label-form' do
expect(page).to have_content('Color must be a valid color code')
end
end
it 'does not creates label if label already exists' do
fill_in 'Title', with: 'bug'
fill_in 'Background color', with: '#F95610'
click_button 'Save'
page.within '.label-form' do
expect(page).to have_content 'Title has already been taken'
end
end
end
describe 'edit' do
it 'changes bug label' do
visit edit_admin_label_path(bug_label)
fill_in 'Title', with: 'fix'
fill_in 'Background color', with: '#F15610'
click_button 'Save'
page.within '.manage-labels-list' do
expect(page).to have_content('fix')
end
end
end
end
require 'spec_helper'
RSpec.describe 'admin manage applications', feature: true do
before do
login_as :admin
end
it do
visit admin_applications_path
click_on 'New Application'
expect(page).to have_content('New application')
fill_in :doorkeeper_application_name, with: 'test'
fill_in :doorkeeper_application_redirect_uri, with: 'https://test.com'
click_on 'Submit'
expect(page).to have_content('Application: test')
expect(page).to have_content('Application Id')
expect(page).to have_content('Secret')
click_on 'Edit'
expect(page).to have_content('Edit application')
fill_in :doorkeeper_application_name, with: 'test_changed'
click_on 'Submit'
expect(page).to have_content('test_changed')
expect(page).to have_content('Application Id')
expect(page).to have_content('Secret')
visit admin_applications_path
page.within '.oauth-applications' do
click_on 'Destroy'
end
expect(page.find('.oauth-applications')).not_to have_content('test_changed')
end
end
require 'spec_helper'
feature 'User wants to add a Dockerfile file', feature: true do
include WaitForAjax
before do
user = create(:user)
project = create(:project)
project.team << [user, :master]
login_as user
visit namespace_project_new_blob_path(project.namespace, project, 'master', file_name: 'Dockerfile')
end
scenario 'user can see Dockerfile dropdown' do
expect(page).to have_css('.dockerfile-selector')
end
scenario 'user can pick a Dockerfile file from the dropdown', js: true do
find('.js-dockerfile-selector').click
wait_for_ajax
within '.dockerfile-selector' do
find('.dropdown-input-field').set('HTTPd')
find('.dropdown-content li', text: 'HTTPd').click
end
wait_for_ajax
expect(page).to have_css('.dockerfile-selector .dropdown-toggle-text', text: 'HTTPd')
expect(page).to have_content('COPY ./ /usr/local/apache2/htdocs/')
end
end
...@@ -19,7 +19,7 @@ describe "Pipelines", feature: true, js: true do ...@@ -19,7 +19,7 @@ describe "Pipelines", feature: true, js: true do
@success = create(:ci_build, :success, pipeline: pipeline, stage: 'build', name: 'build') @success = create(:ci_build, :success, pipeline: pipeline, stage: 'build', name: 'build')
@failed = create(:ci_build, :failed, pipeline: pipeline, stage: 'test', name: 'test', commands: 'test') @failed = create(:ci_build, :failed, pipeline: pipeline, stage: 'test', name: 'test', commands: 'test')
@running = create(:ci_build, :running, pipeline: pipeline, stage: 'deploy', name: 'deploy') @running = create(:ci_build, :running, pipeline: pipeline, stage: 'deploy', name: 'deploy')
@manual = create(:ci_build, :manual, pipeline: pipeline, stage: 'deploy', name: 'manual build') @manual = create(:ci_build, :manual, pipeline: pipeline, stage: 'deploy', name: 'manual-build')
@external = create(:generic_commit_status, status: 'success', pipeline: pipeline, name: 'jenkins', stage: 'external') @external = create(:generic_commit_status, status: 'success', pipeline: pipeline, name: 'jenkins', stage: 'external')
end end
...@@ -41,37 +41,34 @@ describe "Pipelines", feature: true, js: true do ...@@ -41,37 +41,34 @@ describe "Pipelines", feature: true, js: true do
describe 'pipeline graph' do describe 'pipeline graph' do
context 'when pipeline has running builds' do context 'when pipeline has running builds' do
it 'shows a running icon and a cancel action for the running build' do it 'shows a running icon and a cancel action for the running build' do
page.within('a[data-title="deploy - running"]') do page.within('#ci-badge-deploy') do
expect(page).to have_selector('.ci-status-icon-running') expect(page).to have_selector('.ci-status-icon-running')
expect(page).to have_content('deploy')
end
page.within('a[data-title="deploy - running"] + .ci-action-icon-container') do
expect(page).to have_selector('.ci-action-icon-container .fa-ban') expect(page).to have_selector('.ci-action-icon-container .fa-ban')
expect(page).to have_content('deploy')
end end
end end
it 'should be possible to cancel the running build' do it 'should be possible to cancel the running build' do
find('a[data-title="deploy - running"] + .ci-action-icon-container').trigger('click') find('#ci-badge-deploy .ci-action-icon-container').trigger('click')
expect(page).not_to have_content('Cancel running') expect(page).not_to have_content('Cancel running')
end end
end end
context 'when pipeline has successful builds' do context 'when pipeline has successful builds' do
it 'shows the success icon and a retry action for the successfull build' do it 'shows the success icon and a retry action for the successful build' do
page.within('a[data-title="build - passed"]') do page.within('#ci-badge-build') do
expect(page).to have_selector('.ci-status-icon-success') expect(page).to have_selector('.ci-status-icon-success')
expect(page).to have_content('build') expect(page).to have_content('build')
end end
page.within('a[data-title="build - passed"] + .ci-action-icon-container') do page.within('#ci-badge-build .ci-action-icon-container') do
expect(page).to have_selector('.ci-action-icon-container .fa-refresh') expect(page).to have_selector('.ci-action-icon-container .fa-refresh')
end end
end end
it 'should be possible to retry the success build' do it 'should be possible to retry the success build' do
find('a[data-title="build - passed"] + .ci-action-icon-container').trigger('click') find('#ci-badge-build .ci-action-icon-container').trigger('click')
expect(page).not_to have_content('Retry build') expect(page).not_to have_content('Retry build')
end end
...@@ -79,18 +76,18 @@ describe "Pipelines", feature: true, js: true do ...@@ -79,18 +76,18 @@ describe "Pipelines", feature: true, js: true do
context 'when pipeline has failed builds' do context 'when pipeline has failed builds' do
it 'shows the failed icon and a retry action for the failed build' do it 'shows the failed icon and a retry action for the failed build' do
page.within('a[data-title="test - failed"]') do page.within('#ci-badge-test') do
expect(page).to have_selector('.ci-status-icon-failed') expect(page).to have_selector('.ci-status-icon-failed')
expect(page).to have_content('test') expect(page).to have_content('test')
end end
page.within('a[data-title="test - failed"] + .ci-action-icon-container') do page.within('#ci-badge-test .ci-action-icon-container') do
expect(page).to have_selector('.ci-action-icon-container .fa-refresh') expect(page).to have_selector('.ci-action-icon-container .fa-refresh')
end end
end end
it 'should be possible to retry the failed build' do it 'should be possible to retry the failed build' do
find('a[data-title="test - failed"] + .ci-action-icon-container').trigger('click') find('#ci-badge-test .ci-action-icon-container').trigger('click')
expect(page).not_to have_content('Retry build') expect(page).not_to have_content('Retry build')
end end
...@@ -98,18 +95,18 @@ describe "Pipelines", feature: true, js: true do ...@@ -98,18 +95,18 @@ describe "Pipelines", feature: true, js: true do
context 'when pipeline has manual builds' do context 'when pipeline has manual builds' do
it 'shows the skipped icon and a play action for the manual build' do it 'shows the skipped icon and a play action for the manual build' do
page.within('a[data-title="manual build - manual play action"]') do page.within('#ci-badge-manual-build') do
expect(page).to have_selector('.ci-status-icon-skipped') expect(page).to have_selector('.ci-status-icon-manual')
expect(page).to have_content('manual') expect(page).to have_content('manual')
end end
page.within('a[data-title="manual build - manual play action"] + .ci-action-icon-container') do page.within('#ci-badge-manual-build .ci-action-icon-container') do
expect(page).to have_selector('.ci-action-icon-container .fa-play') expect(page).to have_selector('.ci-action-icon-container .fa-play')
end end
end end
it 'should be possible to play the manual build' do it 'should be possible to play the manual build' do
find('a[data-title="manual build - manual play action"] + .ci-action-icon-container').trigger('click') find('#ci-badge-manual-build .ci-action-icon-container').trigger('click')
expect(page).not_to have_content('Play build') expect(page).not_to have_content('Play build')
end end
...@@ -167,7 +164,7 @@ describe "Pipelines", feature: true, js: true do ...@@ -167,7 +164,7 @@ describe "Pipelines", feature: true, js: true do
@success = create(:ci_build, :success, pipeline: pipeline, stage: 'build', name: 'build') @success = create(:ci_build, :success, pipeline: pipeline, stage: 'build', name: 'build')
@failed = create(:ci_build, :failed, pipeline: pipeline, stage: 'test', name: 'test', commands: 'test') @failed = create(:ci_build, :failed, pipeline: pipeline, stage: 'test', name: 'test', commands: 'test')
@running = create(:ci_build, :running, pipeline: pipeline, stage: 'deploy', name: 'deploy') @running = create(:ci_build, :running, pipeline: pipeline, stage: 'deploy', name: 'deploy')
@manual = create(:ci_build, :manual, pipeline: pipeline, stage: 'deploy', name: 'manual build') @manual = create(:ci_build, :manual, pipeline: pipeline, stage: 'deploy', name: 'manual-build')
@external = create(:generic_commit_status, status: 'success', pipeline: pipeline, name: 'jenkins', stage: 'external') @external = create(:generic_commit_status, status: 'success', pipeline: pipeline, name: 'jenkins', stage: 'external')
end end
......
...@@ -8,8 +8,7 @@ ...@@ -8,8 +8,7 @@
%ul %ul
%li.build %li.build
.curve .curve
.build-content %a
%a %svg
%svg .ci-status-text
.ci-status-text stop_review
stop_review
require 'spec_helper'
describe Bitbucket::Representation::Repo do
describe '#has_wiki?' do
it { expect(described_class.new({ 'has_wiki' => false }).has_wiki?).to be_falsey }
it { expect(described_class.new({ 'has_wiki' => true }).has_wiki?).to be_truthy }
end
describe '#name' do
it { expect(described_class.new({ 'name' => 'test' }).name).to eq('test') }
end
describe '#valid?' do
it { expect(described_class.new({ 'scm' => 'hg' }).valid?).to be_falsey }
it { expect(described_class.new({ 'scm' => 'git' }).valid?).to be_truthy }
end
describe '#full_name' do
it { expect(described_class.new({ 'full_name' => 'test_full' }).full_name).to eq('test_full') }
end
describe '#description' do
it { expect(described_class.new({ 'description' => 'desc' }).description).to eq('desc') }
end
describe '#issues_enabled?' do
it { expect(described_class.new({ 'has_issues' => false }).issues_enabled?).to be_falsey }
it { expect(described_class.new({ 'has_issues' => true }).issues_enabled?).to be_truthy }
end
describe '#owner_and_slug' do
it { expect(described_class.new({ 'full_name' => 'ben/test' }).owner_and_slug).to eq(['ben', 'test']) }
end
describe '#owner' do
it { expect(described_class.new({ 'full_name' => 'ben/test' }).owner).to eq('ben') }
end
describe '#slug' do
it { expect(described_class.new({ 'full_name' => 'ben/test' }).slug).to eq('test') }
end
describe '#clone_url' do
it 'builds url' do
data = { 'links' => { 'clone' => [ { 'name' => 'https', 'href' => 'https://bibucket.org/test/test.git' }] } }
expect(described_class.new(data).clone_url('abc')).to eq('https://x-token-auth:abc@bibucket.org/test/test.git')
end
end
end
...@@ -483,7 +483,7 @@ module Ci ...@@ -483,7 +483,7 @@ module Ci
context 'when global variables are defined' do context 'when global variables are defined' do
let(:variables) do let(:variables) do
{ VAR1: 'value1', VAR2: 'value2' } { 'VAR1' => 'value1', 'VAR2' => 'value2' }
end end
let(:config) do let(:config) do
{ {
...@@ -495,18 +495,18 @@ module Ci ...@@ -495,18 +495,18 @@ module Ci
it 'returns global variables' do it 'returns global variables' do
expect(subject).to contain_exactly( expect(subject).to contain_exactly(
{ key: :VAR1, value: 'value1', public: true }, { key: 'VAR1', value: 'value1', public: true },
{ key: :VAR2, value: 'value2', public: true } { key: 'VAR2', value: 'value2', public: true }
) )
end end
end end
context 'when job and global variables are defined' do context 'when job and global variables are defined' do
let(:global_variables) do let(:global_variables) do
{ VAR1: 'global1', VAR3: 'global3' } { 'VAR1' => 'global1', 'VAR3' => 'global3' }
end end
let(:job_variables) do let(:job_variables) do
{ VAR1: 'value1', VAR2: 'value2' } { 'VAR1' => 'value1', 'VAR2' => 'value2' }
end end
let(:config) do let(:config) do
{ {
...@@ -518,9 +518,9 @@ module Ci ...@@ -518,9 +518,9 @@ module Ci
it 'returns all unique variables' do it 'returns all unique variables' do
expect(subject).to contain_exactly( expect(subject).to contain_exactly(
{ key: :VAR3, value: 'global3', public: true }, { key: 'VAR3', value: 'global3', public: true },
{ key: :VAR1, value: 'value1', public: true }, { key: 'VAR1', value: 'value1', public: true },
{ key: :VAR2, value: 'value2', public: true } { key: 'VAR2', value: 'value2', public: true }
) )
end end
end end
...@@ -535,13 +535,13 @@ module Ci ...@@ -535,13 +535,13 @@ module Ci
context 'when syntax is correct' do context 'when syntax is correct' do
let(:variables) do let(:variables) do
{ VAR1: 'value1', VAR2: 'value2' } { 'VAR1' => 'value1', 'VAR2' => 'value2' }
end end
it 'returns job variables' do it 'returns job variables' do
expect(subject).to contain_exactly( expect(subject).to contain_exactly(
{ key: :VAR1, value: 'value1', public: true }, { key: 'VAR1', value: 'value1', public: true },
{ key: :VAR2, value: 'value2', public: true } { key: 'VAR2', value: 'value2', public: true }
) )
end end
end end
...@@ -549,7 +549,7 @@ module Ci ...@@ -549,7 +549,7 @@ module Ci
context 'when syntax is incorrect' do context 'when syntax is incorrect' do
context 'when variables defined but invalid' do context 'when variables defined but invalid' do
let(:variables) do let(:variables) do
[ :VAR1, 'value1', :VAR2, 'value2' ] [ 'VAR1', 'value1', 'VAR2', 'value2' ]
end end
it 'raises error' do it 'raises error' do
......
...@@ -69,6 +69,9 @@ describe Gitlab::BitbucketImport::Importer, lib: true do ...@@ -69,6 +69,9 @@ describe Gitlab::BitbucketImport::Importer, lib: true do
context 'issues statuses' do context 'issues statuses' do
before do before do
# HACK: Bitbucket::Representation.const_get('Issue') seems to return ::Issue without this
Bitbucket::Representation::Issue.new({})
stub_request( stub_request(
:get, :get,
"https://api.bitbucket.org/2.0/repositories/#{project_identifier}" "https://api.bitbucket.org/2.0/repositories/#{project_identifier}"
...@@ -108,13 +111,16 @@ describe Gitlab::BitbucketImport::Importer, lib: true do ...@@ -108,13 +111,16 @@ describe Gitlab::BitbucketImport::Importer, lib: true do
body: {}.to_json) body: {}.to_json)
end end
it 'map statuses to open or closed' do it 'maps statuses to open or closed' do
# HACK: Bitbucket::Representation.const_get('Issue') seems to return ::Issue without this
Bitbucket::Representation::Issue.new({})
importer.execute importer.execute
expect(project.issues.where(state: "closed").size).to eq(5) expect(project.issues.where(state: "closed").size).to eq(5)
expect(project.issues.where(state: "opened").size).to eq(2) expect(project.issues.where(state: "opened").size).to eq(2)
end end
it 'calls import_wiki' do
expect(importer).to receive(:import_wiki)
importer.execute
end
end end
end end
...@@ -11,7 +11,8 @@ describe Gitlab::BitbucketImport::ProjectCreator, lib: true do ...@@ -11,7 +11,8 @@ describe Gitlab::BitbucketImport::ProjectCreator, lib: true do
owner: "asd", owner: "asd",
full_name: 'Vim repo', full_name: 'Vim repo',
visibility_level: Gitlab::VisibilityLevel::PRIVATE, visibility_level: Gitlab::VisibilityLevel::PRIVATE,
clone_url: 'ssh://git@bitbucket.org/asd/vim.git') clone_url: 'ssh://git@bitbucket.org/asd/vim.git',
has_wiki?: false)
end end
let(:namespace){ create(:group, owner: user) } let(:namespace){ create(:group, owner: user) }
......
...@@ -32,6 +32,14 @@ describe Gitlab::Ci::Status::Build::Cancelable do ...@@ -32,6 +32,14 @@ describe Gitlab::Ci::Status::Build::Cancelable do
end end
end end
describe '#group' do
it 'does not override status group' do
expect(status).to receive(:group)
subject.group
end
end
describe 'action details' do describe 'action details' do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:build) { create(:ci_build) } let(:build) { create(:ci_build) }
......
...@@ -18,6 +18,10 @@ describe Gitlab::Ci::Status::Build::Play do ...@@ -18,6 +18,10 @@ describe Gitlab::Ci::Status::Build::Play do
it { expect(subject.icon).to eq 'icon_status_manual' } it { expect(subject.icon).to eq 'icon_status_manual' }
end end
describe '#group' do
it { expect(subject.group).to eq 'manual' }
end
describe 'action details' do describe 'action details' do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:build) { create(:ci_build) } let(:build) { create(:ci_build) }
......
...@@ -32,6 +32,14 @@ describe Gitlab::Ci::Status::Build::Retryable do ...@@ -32,6 +32,14 @@ describe Gitlab::Ci::Status::Build::Retryable do
end end
end end
describe '#group' do
it 'does not override status group' do
expect(status).to receive(:group)
subject.group
end
end
describe 'action details' do describe 'action details' do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:build) { create(:ci_build) } let(:build) { create(:ci_build) }
......
...@@ -20,6 +20,10 @@ describe Gitlab::Ci::Status::Build::Stop do ...@@ -20,6 +20,10 @@ describe Gitlab::Ci::Status::Build::Stop do
it { expect(subject.icon).to eq 'icon_status_manual' } it { expect(subject.icon).to eq 'icon_status_manual' }
end end
describe '#group' do
it { expect(subject.group).to eq 'manual' }
end
describe 'action details' do describe 'action details' do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:build) { create(:ci_build) } let(:build) { create(:ci_build) }
......
...@@ -16,4 +16,8 @@ describe Gitlab::Ci::Status::Canceled do ...@@ -16,4 +16,8 @@ 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 '#group' do
it { expect(subject.group).to eq 'canceled' }
end
end end
...@@ -16,4 +16,8 @@ describe Gitlab::Ci::Status::Created do ...@@ -16,4 +16,8 @@ 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 '#group' do
it { expect(subject.group).to eq 'created' }
end
end end
...@@ -16,4 +16,8 @@ describe Gitlab::Ci::Status::Failed do ...@@ -16,4 +16,8 @@ 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 '#group' do
it { expect(subject.group).to eq 'failed' }
end
end end
...@@ -16,4 +16,8 @@ describe Gitlab::Ci::Status::Pending do ...@@ -16,4 +16,8 @@ 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 '#group' do
it { expect(subject.group).to eq 'pending' }
end
end end
...@@ -17,6 +17,10 @@ describe Gitlab::Ci::Status::Pipeline::SuccessWithWarnings do ...@@ -17,6 +17,10 @@ describe Gitlab::Ci::Status::Pipeline::SuccessWithWarnings do
it { expect(subject.icon).to eq 'icon_status_warning' } it { expect(subject.icon).to eq 'icon_status_warning' }
end end
describe '#group' do
it { expect(subject.group).to eq 'success_with_warnings' }
end
describe '.matches?' do describe '.matches?' do
context 'when pipeline is successful' do context 'when pipeline is successful' do
let(:pipeline) do let(:pipeline) do
......
...@@ -16,4 +16,8 @@ describe Gitlab::Ci::Status::Running do ...@@ -16,4 +16,8 @@ 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 '#group' do
it { expect(subject.group).to eq 'running' }
end
end end
...@@ -16,4 +16,8 @@ describe Gitlab::Ci::Status::Skipped do ...@@ -16,4 +16,8 @@ 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 '#group' do
it { expect(subject.group).to eq 'skipped' }
end
end end
...@@ -16,4 +16,8 @@ describe Gitlab::Ci::Status::Success do ...@@ -16,4 +16,8 @@ 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 '#group' do
it { expect(subject.group).to eq 'success' }
end
end end
...@@ -2517,7 +2517,7 @@ ...@@ -2517,7 +2517,7 @@
"merge_params": { "merge_params": {
"force_remove_source_branch": null "force_remove_source_branch": null
}, },
"merge_when_build_succeeds": false, "merge_when_build_succeeds": true,
"merge_user_id": null, "merge_user_id": null,
"merge_commit_sha": null, "merge_commit_sha": null,
"deleted_at": null, "deleted_at": null,
...@@ -6548,7 +6548,9 @@ ...@@ -6548,7 +6548,9 @@
"url": null "url": null
}, },
"erased_by_id": null, "erased_by_id": null,
"erased_at": null "erased_at": null,
"type": "Ci::Build",
"token": "abcd"
}, },
{ {
"id": 72, "id": 72,
...@@ -7409,6 +7411,28 @@ ...@@ -7409,6 +7411,28 @@
"category": "common", "category": "common",
"default": false, "default": false,
"wiki_page_events": true "wiki_page_events": true
},
{
"id": 101,
"title": "JenkinsDeprecated",
"project_id": 5,
"created_at": "2016-06-14T15:01:51.031Z",
"updated_at": "2016-06-14T15:01:51.031Z",
"active": false,
"properties": {
},
"template": false,
"push_events": true,
"issues_events": true,
"merge_requests_events": true,
"tag_push_events": true,
"note_events": true,
"build_events": true,
"category": "common",
"default": false,
"wiki_page_events": true,
"type": "JenkinsDeprecatedService"
} }
], ],
"hooks": [ "hooks": [
......
...@@ -189,6 +189,14 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do ...@@ -189,6 +189,14 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do
end end
end end
end end
context 'when there is an existing build with build token' do
it 'restores project json correctly' do
create(:ci_build, token: 'abcd')
expect(restored_project_json).to be true
end
end
end end
end end
end end
require 'spec_helper'
describe Gitlab::Serialize::Ci::Variables do
subject do
described_class.load(described_class.dump(object))
end
let(:object) do
[{ key: :key, value: 'value', public: true },
{ key: 'wee', value: 1, public: false }]
end
it 'converts keys into strings' do
is_expected.to eq([
{ key: 'key', value: 'value', public: true },
{ key: 'wee', value: 1, public: false }])
end
end
...@@ -458,7 +458,7 @@ describe Ci::Build, models: true do ...@@ -458,7 +458,7 @@ describe Ci::Build, models: true do
}) })
end end
let(:variables) do let(:variables) do
[{ key: :KEY, value: 'value', public: true }] [{ key: 'KEY', value: 'value', public: true }]
end end
it { is_expected.to eq(predefined_variables + variables) } it { is_expected.to eq(predefined_variables + variables) }
...@@ -1306,11 +1306,25 @@ describe Ci::Build, models: true do ...@@ -1306,11 +1306,25 @@ describe Ci::Build, models: true do
describe '#expanded_environment_name' do describe '#expanded_environment_name' do
subject { build.expanded_environment_name } subject { build.expanded_environment_name }
context 'when environment uses variables' do context 'when environment uses $CI_BUILD_REF_NAME' do
let(:build) { create(:ci_build, ref: 'master', environment: 'review/$CI_BUILD_REF_NAME') } let(:build) do
create(:ci_build,
ref: 'master',
environment: 'review/$CI_BUILD_REF_NAME')
end
it { is_expected.to eq('review/master') } it { is_expected.to eq('review/master') }
end end
context 'when environment uses yaml_variables containing symbol keys' do
let(:build) do
create(:ci_build,
yaml_variables: [{ key: :APP_HOST, value: 'host' }],
environment: 'review/$APP_HOST')
end
it { is_expected.to eq('review/host') }
end
end end
describe '#detailed_status' do describe '#detailed_status' do
......
require 'spec_helper' require 'spec_helper'
describe Route, models: true do describe Route, models: true do
let!(:group) { create(:group) } let!(:group) { create(:group, path: 'gitlab') }
let!(:route) { group.route } let!(:route) { group.route }
describe 'relationships' do describe 'relationships' do
...@@ -17,13 +17,15 @@ describe Route, models: true do ...@@ -17,13 +17,15 @@ describe Route, models: true do
describe '#rename_children' do describe '#rename_children' do
let!(:nested_group) { create(:group, path: "test", parent: group) } let!(:nested_group) { create(:group, path: "test", parent: group) }
let!(:deep_nested_group) { create(:group, path: "foo", parent: nested_group) } let!(:deep_nested_group) { create(:group, path: "foo", parent: nested_group) }
let!(:similar_group) { create(:group, path: 'gitlab-org') }
it "updates children routes with new path" do before { route.update_attributes(path: 'bar') }
route.update_attributes(path: 'bar')
it "updates children routes with new path" do
expect(described_class.exists?(path: 'bar')).to be_truthy expect(described_class.exists?(path: 'bar')).to be_truthy
expect(described_class.exists?(path: 'bar/test')).to be_truthy expect(described_class.exists?(path: 'bar/test')).to be_truthy
expect(described_class.exists?(path: 'bar/test/foo')).to be_truthy expect(described_class.exists?(path: 'bar/test/foo')).to be_truthy
expect(described_class.exists?(path: 'gitlab-org')).to be_truthy
end end
end end
end end
...@@ -249,7 +249,11 @@ describe Ci::API::Builds do ...@@ -249,7 +249,11 @@ describe Ci::API::Builds do
end end
describe 'PATCH /builds/:id/trace.txt' do describe 'PATCH /builds/:id/trace.txt' do
let(:build) { create(:ci_build, :pending, :trace, runner_id: runner.id) } let(:build) do
attributes = { runner_id: runner.id, pipeline: pipeline }
create(:ci_build, :running, :trace, attributes)
end
let(:headers) { { Ci::API::Helpers::BUILD_TOKEN_HEADER => build.token, 'Content-Type' => 'text/plain' } } let(:headers) { { Ci::API::Helpers::BUILD_TOKEN_HEADER => build.token, 'Content-Type' => 'text/plain' } }
let(:headers_with_range) { headers.merge({ 'Content-Range' => '11-20' }) } let(:headers_with_range) { headers.merge({ 'Content-Range' => '11-20' }) }
let(:update_interval) { 10.seconds.to_i } let(:update_interval) { 10.seconds.to_i }
...@@ -276,7 +280,6 @@ describe Ci::API::Builds do ...@@ -276,7 +280,6 @@ describe Ci::API::Builds do
end end
before do before do
build.run!
initial_patch_the_trace initial_patch_the_trace
end end
...@@ -329,6 +332,19 @@ describe Ci::API::Builds do ...@@ -329,6 +332,19 @@ describe Ci::API::Builds do
end end
end end
end end
context 'when project for the build has been deleted' do
let(:build) do
attributes = { runner_id: runner.id, pipeline: pipeline }
create(:ci_build, :running, :trace, attributes) do |build|
build.project.update(pending_delete: true)
end
end
it 'responds with forbidden' do
expect(response.status).to eq(403)
end
end
end end
context 'when Runner makes a force-patch' do context 'when Runner makes a force-patch' do
......
require 'rake_helper'
describe 'gitlab:ldap:rename_provider rake task' do
it 'completes without error' do
Rake.application.rake_require 'tasks/gitlab/ldap'
stub_warn_user_is_not_gitlab
ENV['force'] = 'yes'
create(:identity) # Necessary to prevent `exit 1` from the task.
run_rake_task('gitlab:ldap:rename_provider', 'ldapmain', 'ldapfoo')
end
end
FROM httpd:alpine
COPY ./ /usr/local/apache2/htdocs/
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