Commit 76a4f1e6 authored by Mike Greiling's avatar Mike Greiling

Merge branch 'master' into go-go-gadget-webpack

* master: (24 commits)
  Allow to use + symbol in filenames
  Use string for class_name option for lazy autoload class
  change how pagination component is loaded
  revise sortable_name test formatting
  fix pagination component handling different header styles from different server proxies
  Improve disabled state select
  Fix Rubocop offense in build specs
  Add Changelog for commit links fix on pipelines page
  Remove empty build spec file from invalid location
  Merge build specs into file that has valid location
  Fixed spacing of labels in issuable row on milestone#show
  Update commit entity to point to valid commit page
  Allow to use ENV variables in redis config
  Check for env[Grape::Env::GRAPE_ROUTING_ARGS] instead of endpoint.route
  Mutate the attribute instead of issuing a write operation to the DB
  Remove useless permission checks in Gitlab::Checks::ChangeAccess
  Fix broken link in docs
  prefer unit test on model over view test
  rename sort method
  add CHANGELOG.md entry for !8277
  ...
parents c9dbd5f5 b56e57ec
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
window.Vue = require('vue'); window.Vue = require('vue');
window.Vue.use(require('vue-resource')); window.Vue.use(require('vue-resource'));
require('../vue_common_component/commit'); require('../vue_common_component/commit');
require('../vue_pagination/index');
require('../boards/vue_resource_interceptor'); require('../boards/vue_resource_interceptor');
require('./status'); require('./status');
require('./store'); require('./store');
......
...@@ -3,14 +3,24 @@ ...@@ -3,14 +3,24 @@
require('../vue_realtime_listener'); require('../vue_realtime_listener');
((gl) => { ((gl) => {
const pageValues = headers => ({ const pageValues = (headers) => {
perPage: +headers['X-Per-Page'], const normalizedHeaders = {};
page: +headers['X-Page'],
total: +headers['X-Total'], Object.keys(headers).forEach((e) => {
totalPages: +headers['X-Total-Pages'], normalizedHeaders[e.toUpperCase()] = headers[e];
nextPage: +headers['X-Next-Page'], });
previousPage: +headers['X-Prev-Page'],
}); const paginationInfo = {
perPage: +normalizedHeaders['X-PER-PAGE'],
page: +normalizedHeaders['X-PAGE'],
total: +normalizedHeaders['X-TOTAL'],
totalPages: +normalizedHeaders['X-TOTAL-PAGES'],
nextPage: +normalizedHeaders['X-NEXT-PAGE'],
previousPage: +normalizedHeaders['X-PREV-PAGE'],
};
return paginationInfo;
};
gl.PipelineStore = class { gl.PipelineStore = class {
fetchDataLoop(Vue, pageNum, url, apiScope) { fetchDataLoop(Vue, pageNum, url, apiScope) {
......
...@@ -109,6 +109,10 @@ ...@@ -109,6 +109,10 @@
.avatar { .avatar {
float: none; float: none;
} }
> a:not(:last-of-type) {
margin-right: 5px;
}
} }
} }
......
...@@ -137,4 +137,10 @@ class CommitStatus < ActiveRecord::Base ...@@ -137,4 +137,10 @@ class CommitStatus < ActiveRecord::Base
.new(self, current_user) .new(self, current_user)
.fabricate! .fabricate!
end end
def sortable_name
name.split(/(\d+)/).map do |v|
v =~ /\d+/ ? v.to_i : v
end
end
end end
...@@ -32,6 +32,6 @@ module ProjectFeaturesCompatibility ...@@ -32,6 +32,6 @@ module ProjectFeaturesCompatibility
build_project_feature unless project_feature build_project_feature unless project_feature
access_level = Gitlab::Utils.to_boolean(value) ? ProjectFeature::ENABLED : ProjectFeature::DISABLED access_level = Gitlab::Utils.to_boolean(value) ? ProjectFeature::ENABLED : ProjectFeature::DISABLED
project_feature.update_attribute(field, access_level) project_feature.send(:write_attribute, field, access_level)
end end
end end
class ForkedProjectLink < ActiveRecord::Base class ForkedProjectLink < ActiveRecord::Base
belongs_to :forked_to_project, class_name: Project belongs_to :forked_to_project, class_name: 'Project'
belongs_to :forked_from_project, class_name: Project belongs_to :forked_from_project, class_name: 'Project'
end end
...@@ -122,7 +122,7 @@ class Project < ActiveRecord::Base ...@@ -122,7 +122,7 @@ class Project < ActiveRecord::Base
# Merge Requests for target project should be removed with it # Merge Requests for target project should be removed with it
has_many :merge_requests, dependent: :destroy, foreign_key: 'target_project_id' has_many :merge_requests, dependent: :destroy, foreign_key: 'target_project_id'
# Merge requests from source project should be kept when source project was removed # Merge requests from source project should be kept when source project was removed
has_many :fork_merge_requests, foreign_key: 'source_project_id', class_name: MergeRequest has_many :fork_merge_requests, foreign_key: 'source_project_id', class_name: 'MergeRequest'
has_many :issues, dependent: :destroy has_many :issues, dependent: :destroy
has_many :labels, dependent: :destroy, class_name: 'ProjectLabel' has_many :labels, dependent: :destroy, class_name: 'ProjectLabel'
has_many :services, dependent: :destroy has_many :services, dependent: :destroy
......
...@@ -8,16 +8,16 @@ class CommitEntity < API::Entities::RepoCommit ...@@ -8,16 +8,16 @@ class CommitEntity < API::Entities::RepoCommit
end end
expose :commit_url do |commit| expose :commit_url do |commit|
namespace_project_tree_url( namespace_project_commit_url(
request.project.namespace, request.project.namespace,
request.project, request.project,
id: commit.id) commit)
end end
expose :commit_path do |commit| expose :commit_path do |commit|
namespace_project_tree_path( namespace_project_commit_path(
request.project.namespace, request.project.namespace,
request.project, request.project,
id: commit.id) commit)
end end
end end
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
git push -u origin master git push -u origin master
%fieldset %fieldset
%h5 Existing folder or Git repository %h5 Existing folder
%pre.light-well %pre.light-well
:preserve :preserve
cd existing_folder cd existing_folder
...@@ -62,6 +62,15 @@ ...@@ -62,6 +62,15 @@
git commit git commit
git push -u origin master git push -u origin master
%fieldset
%h5 Existing Git repository
%pre.light-well
:preserve
cd existing_repo
git remote add origin #{ content_tag(:span, default_url_to_repo, class: 'clone')}
git push -u origin --all
git push -u origin --tags
- if can? current_user, :remove_project, @project - if can? current_user, :remove_project, @project
.prepend-top-20 .prepend-top-20
= link_to 'Remove project', [@project.namespace.becomes(Namespace), @project], data: { confirm: remove_project_message(@project)}, method: :delete, class: "btn btn-remove pull-right" = link_to 'Remove project', [@project.namespace.becomes(Namespace), @project], data: { confirm: remove_project_message(@project)}, method: :delete, class: "btn btn-remove pull-right"
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
- content_for :page_specific_javascripts do - content_for :page_specific_javascripts do
= stylesheet_link_tag "xterm/xterm" = stylesheet_link_tag "xterm/xterm"
= page_specific_javascript_tag("terminal/terminal_bundle.js") = page_specific_javascript_bundle_tag("terminal")
%div{ class: container_class } %div{ class: container_class }
.top-area .top-area
......
...@@ -7,20 +7,21 @@ ...@@ -7,20 +7,21 @@
%p %p
= @teams.one? ? 'The team' : 'Select the team' = @teams.one? ? 'The team' : 'Select the team'
where the slash commands will be used in where the slash commands will be used in
- selected_id = @teams.keys.first if @teams.one? - selected_id = @teams.one? ? @teams.keys.first : 0
- options = mattermost_teams_options(@teams) - options = mattermost_teams_options(@teams)
- options = options_for_select(options, selected_id) - options = options_for_select(options, selected_id)
= f.select(:team_id, options, {}, { class: 'form-control', selected: "#{selected_id}" }) = f.select(:team_id, options, {}, { class: 'form-control', disabled: @teams.one?, selected: selected_id })
= f.hidden_field(:team_id, value: selected_id) if @teams.one?
.help-block .help-block
- if @teams.one? - if @teams.one?
This is the only team where you are an administrator. This is the only available team.
- else - else
The list shows teams where you are administrator The list shows all available teams.
To create a team, ask your Mattermost system administrator.
To create a team, To create a team,
= link_to "#{Gitlab.config.mattermost.host}/create_team" do = link_to "#{Gitlab.config.mattermost.host}/create_team" do
use Mattermost's interface use Mattermost's interface
= icon('external-link') = icon('external-link')
or ask your Mattermost system administrator.
%hr %hr
%h4 Command trigger word %h4 Command trigger word
%p Choose the word that will trigger commands %p Choose the word that will trigger commands
......
...@@ -64,5 +64,4 @@ ...@@ -64,5 +64,4 @@
.vue-pipelines-index .vue-pipelines-index
= page_specific_javascript_bundle_tag('vue_pagination')
= page_specific_javascript_bundle_tag('vue_pipelines') = page_specific_javascript_bundle_tag('vue_pipelines')
- stage = local_assigns.fetch(:stage) - stage = local_assigns.fetch(:stage)
- statuses = stage.statuses.latest - statuses = stage.statuses.latest
- status_groups = statuses.sort_by(&:name).group_by(&:group_name) - status_groups = statuses.sort_by(&:sortable_name).group_by(&:group_name)
%li.stage-column %li.stage-column
.stage-name .stage-name
%a{ name: stage.name } %a{ name: stage.name }
......
---
title: Check for env[Grape::Env::GRAPE_ROUTING_ARGS] instead of endpoint.route
merge_request: 8544
author:
---
title: Allow to use + symbol in filenames
merge_request: 6644
author: blackst0ne
---
title: Mutate the attribute instead of issuing a write operation to the DB in `ProjectFeaturesCompatibility`
concern.
merge_request: 8552
author:
---
title: Allow to use ENV variables in redis config
merge_request: 8073
author: Semyon Pupkov
---
title: Sort numbers in build names more intelligently
merge_request: 8277
author:
---
title: Fix links to commits pages on pipelines list page
merge_request: 8558
author:
...@@ -34,7 +34,6 @@ var config = { ...@@ -34,7 +34,6 @@ var config = {
users: './users/users_bundle.js', users: './users/users_bundle.js',
lib_chart: './lib/chart.js', lib_chart: './lib/chart.js',
lib_d3: './lib/d3.js', lib_d3: './lib/d3.js',
vue_pagination: './vue_pagination/index.js',
vue_pipelines: './vue_pipelines_index/index.js', vue_pipelines: './vue_pipelines_index/index.js',
}, },
......
...@@ -601,6 +601,12 @@ If you want to connect the Redis server via socket, then use the "unix:" URL sch ...@@ -601,6 +601,12 @@ If you want to connect the Redis server via socket, then use the "unix:" URL sch
production: production:
url: unix:/path/to/redis/socket url: unix:/path/to/redis/socket
Also you can use environment variables in the `config/resque.yml` file:
# example
production:
url: <%= ENV.fetch('GITLAB_REDIS_URL') %>
### Custom SSH Connection ### Custom SSH Connection
If you are running SSH on a non-standard port, you must change the GitLab user's SSH config. If you are running SSH on a non-standard port, you must change the GitLab user's SSH config.
......
...@@ -6,7 +6,7 @@ Slack commands give users an extra interface to perform common operations ...@@ -6,7 +6,7 @@ Slack commands give users an extra interface to perform common operations
from the chat environment. This allows one to, for example, create an issue as from the chat environment. This allows one to, for example, create an issue as
soon as the idea was discussed in chat. soon as the idea was discussed in chat.
For all available commands try the help subcommand, for example: `/gitlab help`, For all available commands try the help subcommand, for example: `/gitlab help`,
all review the [full list of commands](../integrations/chat_commands.md). all review the [full list of commands](../integration/chat_commands.md).
## Prerequisites ## Prerequisites
......
...@@ -30,9 +30,9 @@ module Gitlab ...@@ -30,9 +30,9 @@ module Gitlab
return unless @branch_name return unless @branch_name
return unless project.protected_branch?(@branch_name) return unless project.protected_branch?(@branch_name)
if forced_push? && user_access.cannot_do_action?(:force_push_code_to_protected_branches) if forced_push?
return "You are not allowed to force push code to a protected branch on this project." return "You are not allowed to force push code to a protected branch on this project."
elsif Gitlab::Git.blank_ref?(@newrev) && user_access.cannot_do_action?(:remove_protected_branches) elsif Gitlab::Git.blank_ref?(@newrev)
return "You are not allowed to delete protected branches from this project." return "You are not allowed to delete protected branches from this project."
end end
......
...@@ -71,10 +71,17 @@ module Gitlab ...@@ -71,10 +71,17 @@ module Gitlab
def tag_endpoint(trans, env) def tag_endpoint(trans, env)
endpoint = env[ENDPOINT_KEY] endpoint = env[ENDPOINT_KEY]
# endpoint.route is nil in the case of a 405 response begin
if endpoint.route route = endpoint.route
path = endpoint_paths_cache[endpoint.route.request_method][endpoint.route.path] rescue
trans.action = "Grape##{endpoint.route.request_method} #{path}" # endpoint.route is calling env[Grape::Env::GRAPE_ROUTING_ARGS][:route_info]
# but env[Grape::Env::GRAPE_ROUTING_ARGS] is nil in the case of a 405 response
# so we're rescuing exceptions and bailing out
end
if route
path = endpoint_paths_cache[route.request_method][route.path]
trans.action = "Grape##{route.request_method} #{path}"
end end
end end
......
...@@ -42,7 +42,7 @@ module Gitlab ...@@ -42,7 +42,7 @@ module Gitlab
return @_raw_config if defined?(@_raw_config) return @_raw_config if defined?(@_raw_config)
begin begin
@_raw_config = File.read(CONFIG_FILE).freeze @_raw_config = ERB.new(File.read(CONFIG_FILE)).result.freeze
rescue Errno::ENOENT rescue Errno::ENOENT
@_raw_config = false @_raw_config = false
end end
......
...@@ -61,11 +61,11 @@ module Gitlab ...@@ -61,11 +61,11 @@ module Gitlab
end end
def file_name_regex def file_name_regex
@file_name_regex ||= /\A[[[:alnum:]]_\-\.\@]*\z/.freeze @file_name_regex ||= /\A[[[:alnum:]]_\-\.\@\+]*\z/.freeze
end end
def file_name_regex_message def file_name_regex_message
"can contain only letters, digits, '_', '-', '@' and '.'." "can contain only letters, digits, '_', '-', '@', '+' and '.'."
end end
def file_path_regex def file_path_regex
......
#!/bin/bash #!/bin/sh
# Sends Slack notification ERROR_MSG to CHANNEL # Sends Slack notification ERROR_MSG to CHANNEL
# An env. variable CI_SLACK_WEBHOOK_URL needs to be set. # An env. variable CI_SLACK_WEBHOOK_URL needs to be set.
......
...@@ -33,10 +33,89 @@ feature 'Setup Mattermost slash commands', feature: true do ...@@ -33,10 +33,89 @@ feature 'Setup Mattermost slash commands', feature: true do
expect(value).to eq(token) expect(value).to eq(token)
end end
describe 'mattermost service is enabled' do it 'shows the add to mattermost button' do
it 'shows the add to mattermost button' do expect(page).to have_link('Add to Mattermost')
expect(page).to have_link 'Add to Mattermost' end
it 'shows an explanation if user is a member of no teams' do
stub_teams(count: 0)
click_link 'Add to Mattermost'
expect(page).to have_content('You aren’t a member of any team on the Mattermost instance')
expect(page).to have_link('join a team', href: "#{Gitlab.config.mattermost.host}/select_team")
end
it 'shows an explanation if user is a member of 1 team' do
stub_teams(count: 1)
click_link 'Add to Mattermost'
expect(page).to have_content('The team where the slash commands will be used in')
expect(page).to have_content('This is the only available team.')
end
it 'shows a disabled prefilled select if user is a member of 1 team' do
teams = stub_teams(count: 1)
click_link 'Add to Mattermost'
team_name = teams.first[1]['display_name']
select_element = find('select#mattermost_team_id')
selected_option = select_element.find('option[selected]')
expect(select_element['disabled']).to be(true)
expect(selected_option).to have_content(team_name.to_s)
end
it 'has a hidden input for the prefilled value if user is a member of 1 team' do
teams = stub_teams(count: 1)
click_link 'Add to Mattermost'
expect(find('input#mattermost_team_id', visible: false).value).to eq(teams.first[0].to_s)
end
it 'shows an explanation user is a member of multiple teams' do
stub_teams(count: 2)
click_link 'Add to Mattermost'
expect(page).to have_content('Select the team where the slash commands will be used in')
expect(page).to have_content('The list shows all available teams.')
end
it 'shows a select with team options user is a member of multiple teams' do
stub_teams(count: 2)
click_link 'Add to Mattermost'
select_element = find('select#mattermost_team_id')
selected_option = select_element.find('option[selected]')
expect(select_element['disabled']).to be(false)
expect(selected_option).to have_content('Select team...')
# The 'Select team...' placeholder is item `0`.
expect(select_element.all('option').count).to eq(3)
end
def stub_teams(count: 0)
teams = create_teams(count)
allow_any_instance_of(MattermostSlashCommandsService).to receive(:list_teams) { teams }
teams
end
def create_teams(count = 0)
teams = {}
count.times do |i|
i += 1
teams[i] = { id: i, display_name: i }
end end
teams
end end
describe 'mattermost service is not enabled' do describe 'mattermost service is not enabled' do
......
...@@ -17,4 +17,18 @@ feature 'Create Snippet', feature: true do ...@@ -17,4 +17,18 @@ feature 'Create Snippet', feature: true do
expect(page).to have_content('My Snippet Title') expect(page).to have_content('My Snippet Title')
expect(page).to have_content('Hello World!') expect(page).to have_content('Hello World!')
end end
scenario 'Authenticated user creates a snippet with + in filename' do
fill_in 'personal_snippet_title', with: 'My Snippet Title'
page.within('.file-editor') do
find(:xpath, "//input[@id='personal_snippet_file_name']").set 'snippet+file+name'
find(:xpath, "//input[@id='personal_snippet_content']").set 'Hello World!'
end
click_button 'Create snippet'
expect(page).to have_content('My Snippet Title')
expect(page).to have_content('snippet+file+name')
expect(page).to have_content('Hello World!')
end
end end
test:
url: <%= ENV['TEST_GITLAB_REDIS_URL'] %>
...@@ -56,7 +56,6 @@ describe Gitlab::Checks::ChangeAccess, lib: true do ...@@ -56,7 +56,6 @@ describe Gitlab::Checks::ChangeAccess, lib: true do
it 'returns an error if the user is not allowed to do forced pushes to protected branches' do it 'returns an error if the user is not allowed to do forced pushes to protected branches' do
expect(Gitlab::Checks::ForcePush).to receive(:force_push?).and_return(true) expect(Gitlab::Checks::ForcePush).to receive(:force_push?).and_return(true)
expect(user_access).to receive(:can_do_action?).with(:force_push_code_to_protected_branches).and_return(false)
expect(subject.status).to be(false) expect(subject.status).to be(false)
expect(subject.message).to eq('You are not allowed to force push code to a protected branch on this project.') expect(subject.message).to eq('You are not allowed to force push code to a protected branch on this project.')
...@@ -88,8 +87,6 @@ describe Gitlab::Checks::ChangeAccess, lib: true do ...@@ -88,8 +87,6 @@ describe Gitlab::Checks::ChangeAccess, lib: true do
end end
it 'returns an error if the user is not allowed to delete protected branches' do it 'returns an error if the user is not allowed to delete protected branches' do
expect(user_access).to receive(:can_do_action?).with(:remove_protected_branches).and_return(false)
expect(subject.status).to be(false) expect(subject.status).to be(false)
expect(subject.message).to eq('You are not allowed to delete protected branches from this project.') expect(subject.message).to eq('You are not allowed to delete protected branches from this project.')
end end
......
...@@ -126,5 +126,16 @@ describe Gitlab::Metrics::RackMiddleware do ...@@ -126,5 +126,16 @@ describe Gitlab::Metrics::RackMiddleware do
expect(transaction.action).to eq('Grape#GET /projects/:id/archive') expect(transaction.action).to eq('Grape#GET /projects/:id/archive')
end end
it 'does not tag a transaction if route infos are missing' do
endpoint = double(:endpoint)
allow(endpoint).to receive(:route).and_raise
env['api.endpoint'] = endpoint
middleware.tag_endpoint(transaction, env)
expect(transaction.action).to be_nil
end
end end
end end
require 'spec_helper' require 'spec_helper'
describe Gitlab::Redis do describe Gitlab::Redis do
let(:redis_config) { Rails.root.join('config', 'resque.yml').to_s } include StubENV
before(:each) { clear_raw_config } before(:each) { clear_raw_config }
after(:each) { clear_raw_config } after(:each) { clear_raw_config }
...@@ -72,6 +72,20 @@ describe Gitlab::Redis do ...@@ -72,6 +72,20 @@ describe Gitlab::Redis do
expect(url2).not_to end_with('foobar') expect(url2).not_to end_with('foobar')
end end
context 'when yml file with env variable' do
let(:redis_config) { Rails.root.join('spec/fixtures/config/redis_config_with_env.yml') }
before do
stub_env('TEST_GITLAB_REDIS_URL', 'redis://redishost:6379')
end
it 'reads redis url from env variable' do
stub_const("#{described_class}::CONFIG_FILE", redis_config)
expect(described_class.url).to eq 'redis://redishost:6379'
end
end
end end
describe '._raw_config' do describe '._raw_config' do
......
This diff is collapsed.
This diff is collapsed.
...@@ -243,4 +243,23 @@ describe CommitStatus, models: true do ...@@ -243,4 +243,23 @@ describe CommitStatus, models: true do
.to be_a Gitlab::Ci::Status::Success .to be_a Gitlab::Ci::Status::Success
end end
end end
describe '#sortable_name' do
tests = {
'karma' => ['karma'],
'karma 0 20' => ['karma ', 0, ' ', 20],
'karma 10 20' => ['karma ', 10, ' ', 20],
'karma 50:100' => ['karma ', 50, ':', 100],
'karma 1.10' => ['karma ', 1, '.', 10],
'karma 1.5.1' => ['karma ', 1, '.', 5, '.', 1],
'karma 1 a' => ['karma ', 1, ' a']
}
tests.each do |name, sortable_name|
it "'#{name}' sorts as '#{sortable_name}'" do
commit_status.name = name
expect(commit_status.sortable_name).to eq(sortable_name)
end
end
end
end end
...@@ -33,10 +33,12 @@ describe CommitEntity do ...@@ -33,10 +33,12 @@ describe CommitEntity do
it 'contains path to commit' do it 'contains path to commit' do
expect(subject).to include(:commit_path) expect(subject).to include(:commit_path)
expect(subject[:commit_path]).to include "commit/#{commit.id}"
end end
it 'contains URL to commit' do it 'contains URL to commit' do
expect(subject).to include(:commit_url) expect(subject).to include(:commit_url)
expect(subject[:commit_path]).to include "commit/#{commit.id}"
end end
it 'needs to receive project in the request' do it 'needs to receive project in the request' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment