Commit 0d224376 authored by Kamil Trzcinski's avatar Kamil Trzcinski

Merge remote-tracking branch 'origin/master' into zj-mattermost-slash-config

parents f7b7e918 deb74f73
......@@ -2,6 +2,21 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
## 8.14.5 (2016-12-14)
- Moved Leave Project and Leave Group buttons to access_request_buttons from the settings dropdown. !7600
- fix display hook error message. !7775 (basyura)
- Remove wrong '.builds-feature' class from the MR settings fieldset. !7930
- Avoid escaping relative links in Markdown twice. !7940 (winniehell)
- API: Memoize the current_user so that sudo can work properly. !8017
- Displays milestone remaining days only when it's present.
- Allow branch names with dots on API endpoint.
- Issue#visible_to_user moved to IssuesFinder to prevent accidental use.
- Shows group members in project members list.
- Encode input when migrating ProcessCommitWorker jobs to prevent migration errors.
- Fixed timeago re-rendering every timeago.
- Fix missing Note access checks by moving Note#search to updated NoteFinder.
## 8.14.4 (2016-12-08)
- Fix diff view permalink highlighting. !7090
......@@ -264,6 +279,13 @@ entry.
- Fix "Without projects" filter. !6611 (Ben Bodenmiller)
- Fix 404 when visit /projects page
## 8.13.10 (2016-12-14)
- API: Memoize the current_user so that sudo can work properly. !8017
- Filter `authentication_token`, `incoming_email_token` and `runners_token` parameters.
- Issue#visible_to_user moved to IssuesFinder to prevent accidental use.
- Fix missing Note access checks by moving Note#search to updated NoteFinder.
## 8.13.9 (2016-12-08)
- Reenables /user API request to return private-token if user is admin and request is made with sudo. !7615
......
......@@ -169,7 +169,7 @@ gem 'gitlab-flowdock-git-hook', '~> 1.0.1'
gem 'gemnasium-gitlab-service', '~> 0.2'
# Slack integration
gem 'slack-notifier', '~> 1.2.0'
gem 'slack-notifier', '~> 1.5.1'
# Asana integration
gem 'asana', '~> 0.4.0'
......
......@@ -683,7 +683,7 @@ GEM
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.0)
slack-notifier (1.2.1)
slack-notifier (1.5.1)
slop (3.6.0)
spinach (0.8.10)
colorize
......@@ -952,7 +952,7 @@ DEPENDENCIES
sidekiq-cron (~> 0.4.4)
sidekiq-limit_fetch (~> 3.4)
simplecov (= 0.12.0)
slack-notifier (~> 1.2.0)
slack-notifier (~> 1.5.1)
spinach-rails (~> 0.2.1)
spinach-rerun-reporter (~> 0.0.2)
spring (~> 1.7.0)
......
......@@ -343,16 +343,18 @@
selector = ".dropdown-page-one .dropdown-content a";
}
this.dropdown.on("click", selector, function(e) {
var $el, selected;
var $el, selected, selectedObj, isMarking;
$el = $(this);
selected = self.rowClicked($el);
selectedObj = selected ? selected[0] : null;
isMarking = selected ? selected[1] : null;
if (self.options.clicked) {
self.options.clicked(selected[0], $el, e, selected[1]);
self.options.clicked(selectedObj, $el, e, isMarking);
}
// Update label right after all modifications in dropdown has been done
if (self.options.toggleLabel) {
self.updateLabel(selected[0], $el, self);
self.updateLabel(selectedObj, $el, self);
}
$el.trigger('blur');
......
......@@ -19,7 +19,7 @@
});
$(document).off('ajax:success', '.notification-form').on('ajax:success', '.notification-form', function(e, data) {
if (data.saved) {
return $(e.currentTarget).closest('.notification-dropdown').replaceWith(data.html);
return $(e.currentTarget).closest('.js-notification-dropdown').replaceWith(data.html);
} else {
return new Flash('Failed to save new settings', 'alert');
}
......
......@@ -96,6 +96,10 @@ label {
code {
line-height: 1.8;
}
img {
margin-right: $gl-padding;
}
}
@media(max-width: $screen-xs-max) {
......
......@@ -49,3 +49,11 @@
fill: $gray-darkest;
}
}
.ci-status-icon-manual {
color: $gl-text-color;
svg {
fill: $gl-text-color;
}
}
......@@ -54,7 +54,7 @@
}
// Display Star and Fork buttons without counters on mobile.
.project-action-buttons {
.project-repo-buttons {
display: block;
.count-buttons .btn {
......
......@@ -57,7 +57,6 @@
}
.ci-status-link {
svg {
position: relative;
top: 2px;
......
......@@ -18,6 +18,20 @@
margin-top: -2px;
margin-left: 5px;
}
&.split {
display: flex;
align-items: center;
}
.left {
flex: 1 1 auto;
}
.right {
flex: 0 0 auto;
text-align: right;
}
}
.panel-body {
......
......@@ -24,6 +24,7 @@ $gray-lightest: #fdfdfd;
$gray-light: #fafafa;
$gray-lighter: #f9f9f9;
$gray-normal: #f5f5f5;
$gray-dark: darken($gray-light, $darken-dark-factor);
$gray-darker: #eee;
$gray-darkest: #c4c4c4;
......
......@@ -2,7 +2,6 @@
padding: $gl-padding-top 0;
border-bottom: 1px solid $border-color;
color: $gl-text-color-dark;
font-size: 16px;
line-height: 34px;
.author {
......
......@@ -27,12 +27,6 @@
}
}
.group-buttons {
.notification-dropdown {
display: inline-block;
}
}
.groups-header {
@media (min-width: $screen-sm-min) {
.nav-links {
......
......@@ -428,7 +428,7 @@
width: 21px;
height: 25px;
position: absolute;
top: -32px;
top: -31px;
border-top: 2px solid $border-color;
}
......@@ -456,32 +456,31 @@
}
.build {
border: 1px solid $border-color;
border-radius: 30px;
background-color: $white-light;
position: relative;
padding: 8px 4px 9px 10px;
width: 186px;
margin-bottom: 10px;
white-space: normal;
color: $gl-text-color-light;
&:hover {
background-color: $stage-hover-bg;
border: 1px solid $stage-hover-border;
> .build-content {
display: inline-block;
padding: 8px 10px 9px;
width: 100%;
border: 1px solid $border-color;
border-radius: 30px;
background-color: $white-light;
a,
.dropdown-counter-badge,
.dropdown-menu-toggle {
&:hover {
background-color: $stage-hover-bg;
border: 1px solid $stage-hover-border;
color: $gl-text-color;
}
}
.grouped-pipeline-dropdown a {
color: $gl-text-color-light;
&:hover {
color: $gl-text-color;
}
}
> .ci-action-icon-container {
position: absolute;
right: 4px;
top: 5px;
}
.ci-status-icon {
......@@ -621,8 +620,8 @@
padding: 0;
width: 191px;
left: auto;
right: -206px;
top: -11px;
right: -195px;
top: -4px;
box-shadow: 0 1px 5px $black-transparent;
a {
......@@ -650,30 +649,20 @@
.dropdown-build {
color: $gl-text-color-light;
a.ci-action-icon-container {
padding: 0;
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;
.build-content {
width: 100%;
}
.ci-action-icon-container {
font-size: 11px;
position: absolute;
right: 4px;
i {
width: 25px;
height: 25px;
font-size: 11px;
margin-top: 0;
&::before {
top: 1px;
......@@ -682,6 +671,12 @@
}
}
&:hover {
background-color: $stage-hover-bg;
border-radius: 3px;
color: $gl-text-color;
}
.stage {
max-width: 100px;
width: 100px;
......@@ -704,9 +699,6 @@
// Action Icons
.ci-action-icon-container .ci-action-icon-wrapper {
float: right;
margin-top: -4px;
i {
color: $border-color;
border-radius: 100%;
......
......@@ -145,8 +145,6 @@
.project-repo-buttons,
.group-buttons {
margin-top: 15px;
.btn {
@include btn-gray;
padding: 3px 10px;
......@@ -175,11 +173,9 @@
}
}
.download-button,
.dropdown-toggle,
.notification-dropdown,
.project-dropdown {
margin-left: 10px;
.project-action-button {
margin: 15px 5px 0;
vertical-align: top;
}
.notification-dropdown .dropdown-menu {
......@@ -195,13 +191,15 @@
.count-buttons {
display: inline-block;
vertical-align: top;
margin-top: 15px;
}
.project-clone-holder {
display: inline-block;
margin: 15px 5px 0 0;
input {
height: 29px;
height: 28px;
}
}
......@@ -255,7 +253,7 @@
line-height: 13px;
padding: $gl-vert-padding $gl-padding;
letter-spacing: .4px;
padding: 7px 14px;
padding: 6px 14px;
text-align: center;
vertical-align: middle;
touch-action: manipulation;
......@@ -492,6 +490,7 @@ a.deploy-project-label {
.project-stats {
font-size: 0;
text-align: center;
border-bottom: 1px solid $border-color;
.nav {
......
......@@ -15,8 +15,7 @@
height: 13px;
width: 13px;
position: relative;
top: 1px;
margin-right: 3px;
top: 2px;
overflow: visible;
}
......@@ -25,7 +24,7 @@
border-color: $gl-danger;
&:not(span):hover {
background-color: rgba( $gl-danger, .07);
background-color: rgba($gl-danger, .07);
}
svg {
......@@ -39,7 +38,7 @@
border-color: $gl-success;
&:not(span):hover {
background-color: rgba( $gl-success, .07);
background-color: rgba($gl-success, .07);
}
svg {
......@@ -52,7 +51,7 @@
border-color: $gl-info;
&:not(span):hover {
background-color: rgba( $gl-info, .07);
background-color: rgba($gl-info, .07);
}
svg {
......@@ -66,7 +65,7 @@
border-color: $gl-gray;
&:not(span):hover {
background-color: rgba( $gl-gray, .07);
background-color: rgba($gl-gray, .07);
}
svg {
......@@ -79,7 +78,7 @@
border-color: $gl-warning;
&:not(span):hover {
background-color: rgba( $gl-warning, .07);
background-color: rgba($gl-warning, .07);
}
svg {
......@@ -92,7 +91,7 @@
border-color: $blue-normal;
&:not(span):hover {
background-color: rgba( $blue-normal, .07);
background-color: rgba($blue-normal, .07);
}
svg {
......@@ -106,13 +105,26 @@
border-color: $gl-gray-light;
&:not(span):hover {
background-color: rgba( $gl-gray-light, .07);
background-color: rgba($gl-gray-light, .07);
}
svg {
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 @@
.add-to-tree {
vertical-align: top;
padding: 6px 10px;
}
.tree-table {
......@@ -172,7 +173,7 @@
position: relative;
z-index: 2;
.download-button {
.project-action-button {
margin-left: $btn-side-margin;
}
}
......@@ -8,6 +8,9 @@ class Projects::BlameController < Projects::ApplicationController
def show
@blob = @repository.blob_at(@commit.id, @path)
return render_404 unless @blob
@blame_groups = Gitlab::Blame.new(@blob, @commit).groups
end
end
......@@ -18,7 +18,7 @@ module Ci
end
serialize :options
serialize :yaml_variables
serialize :yaml_variables, Gitlab::Serialize::Ci::Variables
validates :coverage, numericality: true, allow_blank: true
validates_presence_of :ref
......
......@@ -97,7 +97,7 @@ class MergeRequest < ActiveRecord::Base
validates :source_branch, presence: true
validates :target_project, 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_fork, unless: :closed_without_fork?
......
......@@ -79,7 +79,6 @@ class Project < ActiveRecord::Base
has_one :last_event, -> {order 'events.created_at DESC'}, class_name: 'Event'
has_many :boards, before_add: :validate_board_limit, dependent: :destroy
has_many :chat_services
# Project services
has_one :campfire_service, dependent: :destroy
......@@ -96,6 +95,7 @@ class Project < ActiveRecord::Base
has_one :gemnasium_service, dependent: :destroy
has_one :mattermost_slash_commands_service, dependent: :destroy
has_one :mattermost_notification_service, dependent: :destroy
has_one :slack_slash_commands_service, dependent: :destroy
has_one :slack_notification_service, dependent: :destroy
has_one :buildkite_service, dependent: :destroy
has_one :bamboo_service, dependent: :destroy
......
# Base class for Chat services
# This class is not meant to be used directly, but only to inherit from.
class ChatService < Service
# This class is not meant to be used directly, but only to inherrit from.
class ChatSlashCommandsService < Service
default_value_for :category, 'chat'
has_many :chat_names, foreign_key: :service_id
prop_accessor :token
has_many :chat_names, foreign_key: :service_id, dependent: :destroy
def valid_token?(token)
self.respond_to?(:token) &&
......@@ -15,7 +17,40 @@ class ChatService < Service
[]
end
def can_test?
false
end
def fields
[
{ type: 'text', name: 'token', placeholder: '' }
]
end
def trigger(params)
raise NotImplementedError
return unless valid_token?(params[:token])
user = find_chat_user(params)
unless user
url = authorize_chat_name_url(params)
return presenter.authorize_chat_name(url)
end
Gitlab::ChatCommands::Command.new(project, user,
params).execute
end
private
def find_chat_user(params)
ChatNames::FindUserService.new(self, params).execute
end
def authorize_chat_name_url(params)
ChatNames::AuthorizeUserService.new(self, params).execute
end
def presenter
Gitlab::ChatCommands::Presenter.new
end
end
class MattermostSlashCommandsService < ChatService
class MattermostSlashCommandsService < ChatSlashCommandsService
include TriggersHelper
prop_accessor :token
......@@ -19,12 +19,6 @@ class MattermostSlashCommandsService < ChatService
'mattermost_slash_commands'
end
def fields
[
{ type: 'text', name: 'token', placeholder: '' }
]
end
def configure!(user, params)
token = Mattermost::Command.new(user).
create(command(params))
......@@ -36,18 +30,6 @@ class MattermostSlashCommandsService < ChatService
Mattermost::Team.new(user).all
end
def trigger(params)
return nil unless valid_token?(params[:token])
user = find_chat_user(params)
unless user
url = authorize_chat_name_url(params)
return Mattermost::Presenter.authorize_chat_name(url)
end
Gitlab::ChatCommands::Command.new(project, user, params).execute
end
private
def command(params)
......@@ -62,12 +44,4 @@ class MattermostSlashCommandsService < ChatService
method: 'P',
user_name: 'GitLab')
end
def find_chat_user(params)
ChatNames::FindUserService.new(self, params).execute
end
def authorize_chat_name_url(params)
ChatNames::AuthorizeUserService.new(self, params).execute
end
end
class SlackSlashCommandsService < ChatSlashCommandsService
include TriggersHelper
def title
'Slack Command'
end
def description
"Perform common operations on GitLab in Slack"
end
def to_param
'slack_slash_commands'
end
def trigger(params)
# Format messages to be Slack-compatible
super.tap do |result|
result[:text] = format(result[:text])
end
end
private
def format(text)
Slack::Notifier::LinkFormatter.format(text) if text
end
end
......@@ -13,7 +13,7 @@ class Route < ActiveRecord::Base
def rename_children
# We update each row separately because MySQL does not have regexp_replace.
# 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.
# We need this to avoid recursive call of rename_children method
route.update_column(:path, route.path.sub(path_was, path))
......
......@@ -216,11 +216,12 @@ class Service < ActiveRecord::Base
jira
kubernetes
mattermost_slash_commands
mattermost_notification
pipelines_email
pivotaltracker
pushover
redmine
mattermost_notification
slack_slash_commands
slack_notification
teamcity
]
......
- status = local_assigns.fetch(:status)
- css_classes = "ci-status ci-#{status.group}"
- 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)
= status.text
- else
%span{ class: "ci-status ci-#{status}" }
%span{ class: css_classes }
= custom_icon(status.icon)
= status.text
......@@ -2,15 +2,16 @@
- subject = local_assigns.fetch(:subject)
- 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?
= 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)
.ci-status-text= subject.name
.ci-status-text{ 'data-toggle' => 'tooltip', 'data-title' => "#{subject.name} - #{status.label}" }= subject.name
- else
%span{ class: klass }= custom_icon(status.icon)
.ci-status-text= subject.name
.build-content
%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?
= link_to status.action_path, method: status.action_method,
......
......@@ -18,11 +18,19 @@
= link_to project_path(forked_from_project) do
= forked_from_project.namespace.try(:name)
.project-repo-buttons.project-action-buttons
.project-repo-buttons
.count-buttons
= render 'projects/buttons/star'
= render 'projects/buttons/fork'
- if @project.feature_available?(:repository, current_user)
.project-clone-holder
= render "shared/clone_panel"
%span.hidden-xs
- if @project.feature_available?(:repository, current_user)
.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
- if !project.empty_repo? && can?(current_user, :download_code, project)
.dropdown.inline.download-button
.project-action-button.dropdown.inline
%button.btn{ 'data-toggle' => 'dropdown' }
= icon('download')
= icon("caret-down")
......
- if current_user
.dropdown.inline
.project-action-button.dropdown.inline
%a.btn.dropdown-toggle{href: '#', "data-toggle" => "dropdown"}
= icon('plus')
= icon("caret-down")
......
- if koding_enabled? && current_user && can_push_branch?(@project, @project.default_branch)
- if @repository.koding_yml
= link_to koding_project_url(@project), class: 'btn', target: '_blank' do
Run in IDE (Koding)
- else
= link_to add_koding_stack_path(@project), class: 'btn' do
Set Up Koding
- if koding_enabled? && current_user && @repository.koding_yml && can_push_branch?(@project, @project.default_branch)
= link_to koding_project_url(@project), class: 'btn project-action-button inline', target: '_blank' do
Run in IDE (Koding)
- run_actions_text = "Perform common operations on this project: #{@project.name_with_namespace}"
.well
This service allows GitLab users to perform common operations on this
project by entering slash commands in Slack.
%br
See list of available commands in Slack after setting up this service,
by entering
%code /&lt;command&gt; help
%br
%br
To setup this service:
%ul.list-unstyled
%li
1.
= link_to 'Add a slash command', 'https://my.slack.com/services/new/slash-commands'
in your Slack team with these options:
%hr
.help-form
.form-group
= label_tag nil, 'Command', class: 'col-sm-2 col-xs-12 control-label'
.col-sm-10.col-xs-12.text-block
%p Fill in the word that works best for your team.
%p
Suggestions:
%code= 'gitlab'
%code= @project.path # Path contains no spaces, but dashes
%code= @project.path_with_namespace
.form-group
= label_tag :url, 'URL', class: 'col-sm-2 col-xs-12 control-label'
.col-sm-10.col-xs-12.input-group
= text_field_tag :url, service_trigger_url(subject), class: 'form-control input-sm', readonly: 'readonly'
.input-group-btn
= clipboard_button(clipboard_target: '#url')
.form-group
= label_tag nil, 'Method', class: 'col-sm-2 col-xs-12 control-label'
.col-sm-10.col-xs-12.text-block POST
.form-group
= label_tag :customize_name, 'Customize name', class: 'col-sm-2 col-xs-12 control-label'
.col-sm-10.col-xs-12.input-group
= text_field_tag :customize_name, 'GitLab', class: 'form-control input-sm', readonly: 'readonly'
.input-group-btn
= clipboard_button(clipboard_target: '#customize_name')
.form-group
= label_tag nil, 'Customize icon', class: 'col-sm-2 col-xs-12 control-label'
.col-sm-10.col-xs-12.text-block
= image_tag(asset_url('gitlab_logo.png'), width: 36, height: 36)
= link_to('Download image', asset_url('gitlab_logo.png'), class: 'btn btn-sm', target: '_blank')
.form-group
= label_tag nil, 'Autocomplete', class: 'col-sm-2 col-xs-12 control-label'
.col-sm-10.col-xs-12.text-block Show this command in the autocomplete list
.form-group
= label_tag :autocomplete_description, 'Autocomplete description', class: 'col-sm-2 col-xs-12 control-label'
.col-sm-10.col-xs-12.input-group
= text_field_tag :autocomplete_description, run_actions_text, class: 'form-control input-sm', readonly: 'readonly'
.input-group-btn
= clipboard_button(clipboard_target: '#autocomplete_description')
.form-group
= label_tag :autocomplete_usage_hint, 'Autocomplete usage hint', class: 'col-sm-2 col-xs-12 control-label'
.col-sm-10.col-xs-12.input-group
= text_field_tag :autocomplete_usage_hint, '[help]', class: 'form-control input-sm', readonly: 'readonly'
.input-group-btn
= clipboard_button(clipboard_target: '#autocomplete_usage_hint')
.form-group
= label_tag :descriptive_label, 'Descriptive label', class: 'col-sm-2 col-xs-12 control-label'
.col-sm-10.col-xs-12.input-group
= text_field_tag :descriptive_label, 'Perform common operations on GitLab project', class: 'form-control input-sm', readonly: 'readonly'
.input-group-btn
= clipboard_button(clipboard_target: '#descriptive_label')
%hr
%ul.list-unstyled
%li
2. Paste the
%strong Token
into the field below
%li
3. Select the
%strong Active
checkbox, press
%strong Save changes
and start using GitLab inside Slack!
......@@ -64,20 +64,11 @@
- unless @repository.gitlab_ci_yml
%li.missing
= link_to add_special_file_path(@project, file_name: '.gitlab-ci.yml') do
Set Up CI
%li.project-repo-buttons.right
.project-right-buttons
- 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'
Set up CI
- if koding_enabled? && @repository.koding_yml.blank?
%li.missing
= link_to 'Set up Koding', add_koding_stack_path(@project)
.pull-right
= render 'shared/notifications/button', notification_setting: @notification_setting
- if @repository.commit
.project-last-commit{ class: container_class }
= render 'projects/last_commit', commit: @repository.commit, ref: current_ref, project: @project
......
......@@ -10,12 +10,11 @@
- status_groups.each do |group_name, grouped_statuses|
- if grouped_statuses.one?
- status = grouped_statuses.first
%li.build
%li.build{ 'id' => "ci-badge-#{group_name}" }
.curve
.build-content
= render 'ci/status/graph_badge', subject: status
= render 'ci/status/graph_badge', subject: status
- else
%li.build
%li.build{ 'id' => "ci-badge-#{group_name}" }
.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
%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}"}
= ci_icon_for_status(group_status)
%span.ci-status-text
%span.ci-status-text{ 'data-toggle' => 'tooltip', 'data-title' => "#{name} - #{group_status}" }
= name
%span.dropdown-counter-badge= subject.size
.dropdown-menu.grouped-pipeline-dropdown
......
- 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))
= link_to "Leave #{model_name}", polymorphic_path([:leave, source, :members]),
method: :delete,
data: { confirm: leave_confirmation_message(source) },
class: 'btn'
- elsif requester = source.requesters.find_by(user_id: current_user.id)
= link_to 'Withdraw Access Request', polymorphic_path([:leave, source, :members]),
method: :delete,
data: { confirm: remove_member_message(requester) },
class: 'btn'
- elsif source.request_access_enabled && can?(current_user, :request_access, source)
= link_to 'Request Access', polymorphic_path([:request_access, source, :members]),
method: :post,
class: 'btn'
.project-action-button.inline
- if can?(current_user, :"destroy_#{model_name}_member", source.members.find_by(user_id: current_user.id))
= link_to "Leave #{model_name}", polymorphic_path([:leave, source, :members]),
method: :delete,
data: { confirm: leave_confirmation_message(source) },
class: 'btn'
- elsif requester = source.requesters.find_by(user_id: current_user.id)
= link_to 'Withdraw Access Request', polymorphic_path([:leave, source, :members]),
method: :delete,
data: { confirm: remove_member_message(requester) },
class: 'btn'
- elsif source.request_access_enabled && can?(current_user, :request_access, source)
= link_to 'Request Access', polymorphic_path([:request_access, source, :members]),
method: :post,
class: 'btn'
......@@ -3,10 +3,12 @@
- panel_class = primary ? 'panel-primary' : 'panel-default'
.panel{ class: panel_class }
.panel-heading
= title
.panel-heading.split
.left
= title
- if show_counter
.pull-right= issuables.size
.right
= issuables.size
- class_prefix = dom_class(issuables).pluralize
%ul{ class: "well-list #{class_prefix}-sortable-list", id: "#{class_prefix}-list-#{id}", "data-state" => id }
......
- 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|
= hidden_setting_source_input(notification_setting)
= f.hidden_field :level, class: "notification_setting_level"
......
---
title: Moved Leave Project and Leave Group buttons to access_request_buttons from
the settings dropdown
merge_request: 7600
author:
---
title: Remove wrong '.builds-feature' class from the MR settings fieldset
merge_request: 7930
author:
---
title: Made the padding on the plus button in the breadcrumb menu even
merge_request:
author: Ryan Harris
---
title: Fixed timeago re-rendering every timeago
title: Fix Route#rename_children behavior
merge_request:
author:
---
title: Fix blame 500 error on invalid path.
merge_request: 25761
author: Jeff Stubler
---
title: Shows group members in project members list
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: Displays milestone remaining days only when it's present
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: "fix display hook error message"
merge_request: 7775
author: basyura
---
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: Allow branch names with dots on API endpoint
title: Make CI badge hitboxes match parent
merge_request:
author:
---
title: Avoid escaping relative links in Markdown twice
merge_request: 7940
author: winniehell
---
title: Refactor presenters ChatCommands
merge_request: 7846
author:
class Gitlab::Seeder::Pipelines
STAGES = %w[build test deploy notify]
BUILDS = [
{ name: 'build:linux', stage: 'build', status: :success },
{ name: 'build:osx', stage: 'build', status: :success },
{ name: 'rspec:linux 0 3', stage: 'test', status: :success },
{ name: 'rspec:linux 1 3', stage: 'test', status: :success },
{ name: 'rspec:linux 2 3', stage: 'test', status: :success },
{ name: 'rspec:windows 0 3', stage: 'test', status: :success },
{ name: 'rspec:windows 1 3', stage: 'test', status: :success },
{ name: 'rspec:windows 2 3', stage: 'test', status: :success },
{ name: 'rspec:windows 2 3', stage: 'test', status: :success },
{ name: 'rspec:osx', stage: 'test', status_event: :success },
{ name: 'spinach:linux', stage: 'test', status: :success },
{ name: 'spinach:osx', stage: 'test', status: :failed, allow_failure: true},
{ name: 'env:alpha', stage: 'deploy', environment: 'alpha', status: :pending },
{ name: 'env:beta', stage: 'deploy', environment: 'beta', status: :running },
{ name: 'env:gamma', stage: 'deploy', environment: 'gamma', status: :canceled },
{ name: 'staging', stage: 'deploy', environment: 'staging', status_event: :success, options: { environment: { on_stop: 'stop staging' } } },
{ name: 'stop staging', stage: 'deploy', environment: 'staging', when: 'manual', status: :skipped },
{ name: 'production', stage: 'deploy', environment: 'production', when: 'manual', status: :skipped },
# build stage
{ name: 'build:linux', stage: 'build', status: :success,
queued_at: 10.hour.ago, started_at: 9.hour.ago, finished_at: 8.hour.ago },
{ name: 'build:osx', stage: 'build', status: :success,
queued_at: 10.hour.ago, started_at: 10.hour.ago, finished_at: 9.hour.ago },
# test stage
{ name: 'rspec:linux 0 3', stage: 'test', status: :success,
queued_at: 8.hour.ago, started_at: 8.hour.ago, finished_at: 7.hour.ago },
{ name: 'rspec:linux 1 3', stage: 'test', status: :success,
queued_at: 8.hour.ago, started_at: 8.hour.ago, finished_at: 7.hour.ago },
{ name: 'rspec:linux 2 3', stage: 'test', status: :success,
queued_at: 8.hour.ago, started_at: 8.hour.ago, finished_at: 7.hour.ago },
{ name: 'rspec:windows 0 3', stage: 'test', status: :success,
queued_at: 8.hour.ago, started_at: 8.hour.ago, finished_at: 7.hour.ago },
{ name: 'rspec:windows 1 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: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 },
]
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)
@project = project
......@@ -30,11 +54,12 @@ class Gitlab::Seeder::Pipelines
pipelines.each do |pipeline|
begin
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 '.'
rescue ActiveRecord::RecordInvalid
print 'F'
ensure
pipeline.update_duration
pipeline.update_status
end
end
......
......@@ -74,24 +74,5 @@ Example output:
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]
```
executed as part of the `gitlab:check` task, but can run independently.
See [LDAP Rake Tasks - LDAP Check](ldap.md#check) for details.
# 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
```
......@@ -1056,7 +1056,7 @@ variables:
GET_SOURCES_ATTEMPTS: "3"
```
You can set the them in the global [`variables`](#variables) section or the [`variables`](#job-variables)
You can set them in the global [`variables`](#variables) section or the [`variables`](#job-variables)
section for individual jobs.
## Shallow cloning
......
......@@ -37,7 +37,7 @@ graphs/dashboards.
GitLab provides built-in tools to aid the process of improving performance:
* [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)
GitLab employees can use GitLab.com's performance monitoring systems located at
......
......@@ -5,7 +5,7 @@ Bitbucket.org account.
## 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
Bitbucket.org.
......@@ -50,6 +50,7 @@ you to use.
Repositories: Read
Pull Requests: Read
Issues: Read
Wiki: Read and Write
```
![Bitbucket OAuth settings page](img/bitbucket_oauth_settings_page.png)
......
......@@ -4,7 +4,8 @@
- [Check](check.md)
- [Cleanup](cleanup.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)
- [Webhooks](web_hooks.md)
- [Import](import.md) of git repositories in bulk
......
......@@ -72,7 +72,7 @@ sudo -u git -H git checkout 8-15-stable-ee
```bash
cd /home/git/gitlab-shell
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
......
......@@ -17,6 +17,7 @@ to enable this if not already.
- the pull requests (GitLab 8.4+)
- the pull request comments (GitLab 8.15+)
- the milestones (GitLab 8.15+)
- the wiki (GitLab 8.15+)
- References to pull requests and issues are preserved (GitLab 8.7+)
- Repository public access is retained. If a repository is private in Bitbucket
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 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
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
......@@ -37,11 +37,11 @@ Feature: Project Services
And I fill Assembla settings
Then I should see Assembla service settings saved
Scenario: Activate Slack service
Scenario: Activate Slack notifications service
When I visit project "Shop" services page
And I click Slack service link
And I fill Slack settings
Then I should see Slack service settings saved
And I click Slack notifications service link
And I fill Slack notifications settings
Then I should see Slack Notifications service settings saved
Scenario: Activate Pushover service
When I visit project "Shop" services page
......
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
......@@ -137,17 +137,17 @@ class Spinach::Features::ProjectServices < Spinach::FeatureSteps
expect(find_field('Colorize messages').value).to eq '1'
end
step 'I click Slack service link' do
click_link 'Slack'
step 'I click Slack notifications service link' do
click_link 'Slack notifications'
end
step 'I fill Slack settings' do
step 'I fill Slack notifications settings' do
check 'Active'
fill_in 'Webhook', with: 'https://hooks.slack.com/services/SVRWFV0VVAR97N/B02R25XN3/ZBqu7xMupaEEICInN685'
click_button 'Save'
end
step 'I should see Slack service settings saved' do
step 'I should see Slack Notifications service settings saved' do
expect(find_field('Webhook').value).to eq 'https://hooks.slack.com/services/SVRWFV0VVAR97N/B02R25XN3/ZBqu7xMupaEEICInN685'
end
......
......@@ -195,10 +195,6 @@ module SharedPaths
visit admin_groups_path
end
step 'I visit admin appearance page' do
visit admin_appearances_path
end
step 'I visit admin teams page' do
visit admin_teams_path
end
......
......@@ -378,7 +378,6 @@ module API
desc: 'A custom certificate authority bundle to verify the Kubernetes cluster with (PEM format)'
},
],
'mattermost-slash-commands' => [
{
required: true,
......@@ -387,6 +386,14 @@ module API
desc: 'The Mattermost token'
}
],
'slack-slash-commands' => [
{
required: true,
name: :token,
type: String,
desc: 'The Slack token'
}
],
'pipelines-email' => [
{
required: true,
......
......@@ -51,6 +51,10 @@ module Bitbucket
raw['scm'] == 'git'
end
def has_wiki?
raw['has_wiki']
end
def visibility_level
if raw['is_private']
Gitlab::VisibilityLevel::PRIVATE
......
......@@ -41,7 +41,7 @@ module Ci
put ":id" do
authenticate_runner!
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
......@@ -71,9 +71,7 @@ module Ci
# PATCH /builds/:id/trace.txt
patch ":id/trace.txt" do
build = Ci::Build.find_by_id(params[:id])
not_found! unless build
authenticate_build_token!(build)
forbidden!('Build has been erased!') if build.erased?
authenticate_build!(build)
error!('400 Missing header Content-Range', 400) unless request.headers.has_key?('Content-Range')
content_range = request.headers['Content-Range']
......@@ -104,8 +102,7 @@ module Ci
Gitlab::Workhorse.verify_api_request!(headers)
not_allowed! unless Gitlab.config.artifacts.enabled
build = Ci::Build.find_by_id(params[:id])
not_found! unless build
authenticate_build_token!(build)
authenticate_build!(build)
forbidden!('build is not running') unless build.running?
if params[:filesize]
......@@ -142,10 +139,8 @@ module Ci
require_gitlab_workhorse!
not_allowed! unless Gitlab.config.artifacts.enabled
build = Ci::Build.find_by_id(params[:id])
not_found! unless build
authenticate_build_token!(build)
authenticate_build!(build)
forbidden!('Build is not running!') unless build.running?
forbidden!('Build has been erased!') if build.erased?
artifacts_upload_path = ArtifactUploader.artifacts_upload_path
artifacts = uploaded_file(:file, artifacts_upload_path)
......@@ -176,8 +171,7 @@ module Ci
# GET /builds/:id/artifacts
get ":id/artifacts" do
build = Ci::Build.find_by_id(params[:id])
not_found! unless build
authenticate_build_token!(build)
authenticate_build!(build)
artifacts_file = build.artifacts_file
unless artifacts_file.file_storage?
......@@ -202,8 +196,7 @@ module Ci
# DELETE /builds/:id/artifacts
delete ":id/artifacts" do
build = Ci::Build.find_by_id(params[:id])
not_found! unless build
authenticate_build_token!(build)
authenticate_build!(build)
build.erase_artifacts!
end
......
......@@ -13,8 +13,19 @@ module Ci
forbidden! unless current_runner
end
def authenticate_build_token!(build)
forbidden! unless build_token_valid?(build)
def authenticate_build!(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
def runner_registration_token_valid?
......
......@@ -118,7 +118,7 @@ module Ci
.merge(job_variables(name))
variables.map do |key, value|
{ key: key, value: value, public: true }
{ key: key.to_s, value: value, public: true }
end
end
......
module Gitlab
module BitbucketImport
class Importer
include Gitlab::ShellAdapter
LABELS = [{ title: 'bug', color: '#FF0000' },
{ title: 'enhancement', color: '#428BCA' },
{ title: 'proposal', color: '#69D100' },
......@@ -18,6 +20,7 @@ module Gitlab
end
def execute
import_wiki
import_issues
import_pull_requests
handle_errors
......@@ -55,6 +58,16 @@ module Gitlab
@repo ||= client.repo(project.import_source)
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
return unless repo.issues_enabled?
......
......@@ -22,9 +22,16 @@ module Gitlab
import_type: 'bitbucket',
import_source: repo.full_name,
import_url: repo.clone_url(session_data[:token]),
import_data: { credentials: session_data }
import_data: { credentials: session_data },
skip_wiki: skip_wiki
).execute
end
private
def skip_wiki
repo.has_wiki?
end
end
end
end
......@@ -42,6 +42,10 @@ module Gitlab
def find_by_iid(iid)
collection.find_by(iid: iid)
end
def presenter
Gitlab::ChatCommands::Presenter.new
end
end
end
end
......@@ -22,8 +22,6 @@ module Gitlab
end
end
private
def match_command
match = nil
service = available_commands.find do |klass|
......@@ -33,6 +31,8 @@ module Gitlab
[service, match]
end
private
def help_messages
available_commands.map(&:help_message)
end
......@@ -48,15 +48,15 @@ module Gitlab
end
def help(messages)
Mattermost::Presenter.help(messages, params[:command])
presenter.help(messages, params[:command])
end
def access_denied
Mattermost::Presenter.access_denied
presenter.access_denied
end
def present(resource)
Mattermost::Presenter.present(resource)
presenter.present(resource)
end
end
end
......
......@@ -4,7 +4,7 @@ module Gitlab
include Gitlab::Routing.url_helpers
def self.match(text)
/\Adeploy\s+(?<from>.*)\s+to+\s+(?<to>.*)\z/.match(text)
/\Adeploy\s+(?<from>\S+.*)\s+to+\s+(?<to>\S+.*)\z/.match(text)
end
def self.help_message
......
module Mattermost
class Presenter
class << self
include Gitlab::Routing.url_helpers
module Gitlab
module ChatCommands
class Presenter
include Gitlab::Routing
def authorize_chat_name(url)
message = if url
......@@ -64,7 +64,7 @@ module Mattermost
def single_resource(resource)
return error(resource) if resource.errors.any? || !resource.persisted?
message = "### #{title(resource)}"
message = "#{title(resource)}:"
message << "\n\n#{resource.description}" if resource.try(:description)
in_channel_response(message)
......
......@@ -17,6 +17,10 @@ module Gitlab
'icon_status_manual'
end
def group
'manual'
end
def has_action?
can?(user, :update_build, subject)
end
......
......@@ -17,6 +17,10 @@ module Gitlab
'icon_status_manual'
end
def group
'manual'
end
def has_action?
can?(user, :update_build, subject)
end
......
......@@ -22,15 +22,8 @@ module Gitlab
raise NotImplementedError
end
# Deprecation warning: this method is here because we need to maintain
# backwards compatibility with legacy statuses. We often do something
# 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
def group
self.class.name.demodulize.underscore
end
def has_details?
......
......@@ -17,7 +17,7 @@ module Gitlab
'icon_status_warning'
end
def to_s
def group
'success_with_warnings'
end
......
......@@ -22,7 +22,7 @@ module Gitlab
def valid?
environment_variables.all? do |(name, value)|
value.start_with?(project.repository.path_to_repo)
value.to_s.start_with?(project.repository.path_to_repo)
end
end
......@@ -35,7 +35,7 @@ module Gitlab
end
def environment_variables
@environment_variables ||= env.slice(*ALLOWED_VARIABLES)
@environment_variables ||= env.slice(*ALLOWED_VARIABLES).compact
end
end
end
......
......@@ -120,7 +120,7 @@ module Gitlab
members_mapper: members_mapper,
user: @user,
project_id: restored_project.id)
end
end.compact
relation_hash_list.is_a?(Array) ? relation_array : relation_array.first
end
......
......@@ -14,7 +14,7 @@ module Gitlab
priorities: :label_priorities,
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
......@@ -40,6 +40,8 @@ module Gitlab
# the relation_hash, updating references with new object IDs, mapping users using
# the "members_mapper" object, also updating notes if required.
def create
return nil if unknown_service?
setup_models
generate_imported_object
......@@ -99,6 +101,8 @@ module Gitlab
def generate_imported_object
if BUILD_MODELS.include?(@relation_name) # call #trace= method after assigning the other attributes
trace = @relation_hash.delete('trace')
@relation_hash.delete('token')
imported_object do |object|
object.trace = trace
object.commit_id = nil
......@@ -215,6 +219,11 @@ module Gitlab
existing_object
end
end
def unknown_service?
@relation_name == :services && parsed_relation_hash['type'] &&
!Object.const_defined?(parsed_relation_hash['type'])
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
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
let(:id) { 'master/files/ruby/popen.rb' }
it { is_expected.to respond_with(:success) }
end
context "invalid file" do
let(:id) { 'master/files/ruby/missing_file.rb'}
it { expect(response).to have_http_status(404) }
end
end
end
......@@ -22,7 +22,7 @@ FactoryGirl.define do
yaml_variables do
[
{ key: :DB_NAME, value: 'postgres', public: true }
{ key: 'DB_NAME', value: 'postgres', public: true }
]
end
......
class Spinach::Features::AdminAppearance < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
require 'spec_helper'
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_description', with: 'dev server'
click_button 'Save'
end
step 'I should be redirected to admin appearance page' do
expect(current_path).to eq admin_appearances_path
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_description', with: 'dev server')
expect(page).to have_content 'Last edit'
end
step 'I click preview button' do
scenario 'Preview appearance' do
login_as :admin
visit admin_appearances_path
click_link "Preview"
end
step 'application has custom appearance' do
create(:appearance)
expect_page_has_custom_appearance(appearance)
end
step 'I should see a customized appearance' do
expect(page).to have_content appearance.title
expect(page).to have_content appearance.description
scenario 'Custom sign-in page' do
visit new_user_session_path
expect_page_has_custom_appearance(appearance)
end
step 'I attach a logo' do
attach_file(:appearance_logo, Rails.root.join('spec', 'fixtures', 'dk.png'))
click_button 'Save'
end
scenario 'Appearance logo' do
login_as :admin
visit admin_appearances_path
step 'I attach header logos' do
attach_file(:appearance_header_logo, Rails.root.join('spec', 'fixtures', 'dk.png'))
attach_file(:appearance_logo, logo_fixture)
click_button 'Save'
end
expect(page).to have_css(logo_selector)
step 'I should see a logo' do
expect(page).to have_xpath('//img[@src="/uploads/appearance/logo/1/dk.png"]')
click_link 'Remove logo'
expect(page).not_to have_css(logo_selector)
end
step 'I should see header logos' do
expect(page).to have_xpath('//img[@src="/uploads/appearance/header_logo/1/dk.png"]')
end
scenario 'Header logos' do
login_as :admin
visit admin_appearances_path
step 'I remove the logo' do
click_link 'Remove logo'
end
attach_file(:appearance_header_logo, logo_fixture)
click_button 'Save'
expect(page).to have_css(header_logo_selector)
step 'I remove the header logos' do
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
step 'I should see logo removed' do
expect(page).not_to have_xpath('//img[@src="/uploads/appearance/logo/1/gitlab_logo.png"]')
def logo_selector
'//img[@src^="/uploads/appearance/logo"]'
end
step 'I should see header logos removed' do
expect(page).not_to have_xpath('//img[@src="/uploads/appearance/header_logo/1/header_logo_light.png"]')
def header_logo_selector
'//img[@src^="/uploads/appearance/header_logo"]'
end
def appearance
Appearance.last
def logo_fixture
Rails.root.join('spec', 'fixtures', 'dk.png')
end
end
class Spinach::Features::AdminBroadcastMessages < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
require 'spec_helper'
step 'application already has a broadcast message' do
FactoryGirl.create(:broadcast_message, :expired, message: "Migration to new server")
feature 'Admin Broadcast Messages', feature: true do
before do
login_as :admin
create(:broadcast_message, :expired, message: 'Migration to new server')
visit admin_broadcast_messages_path
end
step 'I should see all broadcast messages' do
expect(page).to have_content "Migration to new server"
scenario 'See broadcast messages list' do
expect(page).to have_content 'Migration to new server'
end
step 'I should be redirected to admin messages page' 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
scenario 'Create a customized broadcast message' do
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_font', with: '#b94a48'
select Date.today.next_year.year, from: "broadcast_message_ends_at_1i"
click_button "Add broadcast message"
end
select Date.today.next_year.year, from: 'broadcast_message_ends_at_1i'
click_button 'Add broadcast message'
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_selector 'strong', text: '4:00 CST to 5:00 CST'
expect(page).to have_selector %(div[style="background-color: #f2dede; color: #b94a48"])
end
step 'I edit an existing broadcast message' do
scenario 'Edit an existing broadcast message' do
click_link 'Edit'
end
step 'I change the broadcast message text' do
fill_in 'broadcast_message_message', with: 'Application update RIGHT NOW'
click_button 'Update broadcast message'
end
step 'I should see the updated broadcast message' do
expect(page).to have_content "Application update RIGHT NOW"
expect(current_path).to eq admin_broadcast_messages_path
expect(page).to have_content 'Application update RIGHT NOW'
end
step 'I remove an existing broadcast message' do
scenario 'Remove an existing broadcast message' do
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'
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:"
end
step 'I should see a live preview of the rendered broadcast message' do
page.within('.broadcast-message-preview') do
expect(page).to have_selector('strong', text: 'Markdown')
expect(page).to have_selector('img.emoji')
......
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
......@@ -17,9 +17,9 @@ feature 'Admin updates settings', feature: true do
expect(page).to have_content "Application settings saved successfully"
end
scenario 'Change Slack Service template settings' do
scenario 'Change Slack Notifications Service template settings' do
click_link 'Service Templates'
click_link 'Slack'
click_link 'Slack notifications'
fill_in 'Webhook', with: 'http://localhost'
fill_in 'Username', with: 'test_user'
fill_in 'service_push_channel', with: '#test_channel'
......@@ -30,7 +30,7 @@ feature 'Admin updates settings', feature: true do
expect(page).to have_content 'Application settings saved successfully'
click_link 'Slack'
click_link 'Slack notifications'
page.all('input[type=checkbox]').each do |checkbox|
expect(checkbox).to be_checked
......
......@@ -19,7 +19,7 @@ describe "Pipelines", feature: true, js: true do
@success = create(:ci_build, :success, pipeline: pipeline, stage: 'build', name: 'build')
@failed = create(:ci_build, :failed, pipeline: pipeline, stage: 'test', name: 'test', commands: 'test')
@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')
end
......@@ -41,37 +41,34 @@ describe "Pipelines", feature: true, js: true do
describe 'pipeline graph' do
context 'when pipeline has running builds' 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_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_content('deploy')
end
end
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')
end
end
context 'when pipeline has successful builds' do
it 'shows the success icon and a retry action for the successfull build' do
page.within('a[data-title="build - passed"]') do
it 'shows the success icon and a retry action for the successful build' do
page.within('#ci-badge-build') do
expect(page).to have_selector('.ci-status-icon-success')
expect(page).to have_content('build')
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')
end
end
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')
end
......@@ -79,18 +76,18 @@ describe "Pipelines", feature: true, js: true do
context 'when pipeline has failed builds' 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_content('test')
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')
end
end
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')
end
......@@ -98,18 +95,18 @@ describe "Pipelines", feature: true, js: true do
context 'when pipeline has manual builds' 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
expect(page).to have_selector('.ci-status-icon-skipped')
page.within('#ci-badge-manual-build') do
expect(page).to have_selector('.ci-status-icon-manual')
expect(page).to have_content('manual')
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')
end
end
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')
end
......@@ -167,7 +164,7 @@ describe "Pipelines", feature: true, js: true do
@success = create(:ci_build, :success, pipeline: pipeline, stage: 'build', name: 'build')
@failed = create(:ci_build, :failed, pipeline: pipeline, stage: 'test', name: 'test', commands: 'test')
@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')
end
......
require 'spec_helper'
feature 'Slack slash commands', feature: true do
include WaitForAjax
given(:user) { create(:user) }
given(:project) { create(:project) }
given(:service) { project.create_slack_slash_commands_service }
background do
project.team << [user, :master]
login_as(user)
end
scenario 'user visits the slack slash command config page and shows a help message', js: true do
visit edit_namespace_project_service_path(project.namespace, project, service)
wait_for_ajax
expect(page).to have_content('This service allows GitLab users to perform common')
end
scenario 'shows the token after saving' do
visit edit_namespace_project_service_path(project.namespace, project, service)
fill_in 'service_token', with: 'token'
click_on 'Save'
value = find_field('service_token').value
expect(value).to eq('token')
end
scenario 'shows the correct trigger url' do
visit edit_namespace_project_service_path(project.namespace, project, service)
value = find_field('url').value
expect(value).to match("api/v3/projects/#{project.id}/services/slack_slash_commands/trigger")
end
end
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment