Commit a5835110 authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-05-01

# Conflicts:
#	app/helpers/auth_helper.rb
#	doc/api/discussions.md
#	lib/api/discussions.rb
#	spec/helpers/auth_helper_spec.rb
#	spec/requests/api/discussions_spec.rb

[ci skip]
parents e5fc2b1e b8a84830
...@@ -17,7 +17,7 @@ export default { ...@@ -17,7 +17,7 @@ export default {
}, },
computed: { computed: {
/** /**
* This method is based on app/helpers/application_helper.rb#project_identicon * This method is based on app/helpers/avatars_helper.rb#project_identicon
*/ */
identiconStyles() { identiconStyles() {
const allowedColors = [ const allowedColors = [
......
...@@ -39,7 +39,7 @@ class GroupsFinder < UnionFinder ...@@ -39,7 +39,7 @@ class GroupsFinder < UnionFinder
def all_groups def all_groups
return [owned_groups] if params[:owned] return [owned_groups] if params[:owned]
return [Group.all] if current_user&.full_private_access? return [Group.all] if current_user&.full_private_access? && all_available?
groups = [] groups = []
groups << Gitlab::GroupHierarchy.new(groups_for_ancestors, groups_for_descendants).all_groups if current_user groups << Gitlab::GroupHierarchy.new(groups_for_ancestors, groups_for_descendants).all_groups if current_user
...@@ -67,6 +67,10 @@ class GroupsFinder < UnionFinder ...@@ -67,6 +67,10 @@ class GroupsFinder < UnionFinder
end end
def include_public_groups? def include_public_groups?
current_user.nil? || params.fetch(:all_available, true) current_user.nil? || all_available?
end
def all_available?
params.fetch(:all_available, true)
end end
end end
...@@ -34,80 +34,6 @@ module ApplicationHelper ...@@ -34,80 +34,6 @@ module ApplicationHelper
args.any? { |v| v.to_s.downcase == action_name } args.any? { |v| v.to_s.downcase == action_name }
end end
def project_icon(project_id, options = {})
project =
if project_id.respond_to?(:avatar_url)
project_id
else
Project.find_by_full_path(project_id)
end
if project.avatar_url
image_tag project.avatar_url, options
else # generated icon
project_identicon(project, options)
end
end
def project_identicon(project, options = {})
allowed_colors = {
red: 'FFEBEE',
purple: 'F3E5F5',
indigo: 'E8EAF6',
blue: 'E3F2FD',
teal: 'E0F2F1',
orange: 'FBE9E7',
gray: 'EEEEEE'
}
options[:class] ||= ''
options[:class] << ' identicon'
bg_key = project.id % 7
style = "background-color: ##{allowed_colors.values[bg_key]}; color: #555"
content_tag(:div, class: options[:class], style: style) do
project.name[0, 1].upcase
end
end
# Takes both user and email and returns the avatar_icon by
# user (preferred) or email.
def avatar_icon_for(user = nil, email = nil, size = nil, scale = 2, only_path: true)
if user
avatar_icon_for_user(user, size, scale, only_path: only_path)
elsif email
avatar_icon_for_email(email, size, scale, only_path: only_path)
else
default_avatar
end
end
def avatar_icon_for_email(email = nil, size = nil, scale = 2, only_path: true)
user = User.find_by_any_email(email.try(:downcase))
if user
avatar_icon_for_user(user, size, scale, only_path: only_path)
else
gravatar_icon(email, size, scale)
end
end
def avatar_icon_for_user(user = nil, size = nil, scale = 2, only_path: true)
if user
user.avatar_url(size: size, only_path: only_path) || default_avatar
else
gravatar_icon(nil, size, scale)
end
end
def gravatar_icon(user_email = '', size = nil, scale = 2)
GravatarService.new.execute(user_email, size, scale) ||
default_avatar
end
def default_avatar
asset_path('no_avatar.png')
end
def last_commit(project) def last_commit(project)
if project.repo_exists? if project.repo_exists?
time_ago_with_tooltip(project.repository.commit.committed_date) time_ago_with_tooltip(project.repository.commit.committed_date)
......
...@@ -3,8 +3,11 @@ module AuthHelper ...@@ -3,8 +3,11 @@ module AuthHelper
PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2 facebook azure_oauth2 authentiq).freeze PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2 facebook azure_oauth2 authentiq).freeze
LDAP_PROVIDER = /\Aldap/ LDAP_PROVIDER = /\Aldap/
<<<<<<< HEAD
delegate :slack_app_id, to: :'Gitlab::CurrentSettings.current_application_settings' delegate :slack_app_id, to: :'Gitlab::CurrentSettings.current_application_settings'
=======
>>>>>>> upstream/master
def ldap_enabled? def ldap_enabled?
Gitlab::Auth::LDAP::Config.enabled? Gitlab::Auth::LDAP::Config.enabled?
......
module AvatarsHelper module AvatarsHelper
def project_icon(project_id, options = {})
project =
if project_id.respond_to?(:avatar_url)
project_id
else
Project.find_by_full_path(project_id)
end
if project.avatar_url
image_tag project.avatar_url, options
else # generated icon
project_identicon(project, options)
end
end
def project_identicon(project, options = {})
allowed_colors = {
red: 'FFEBEE',
purple: 'F3E5F5',
indigo: 'E8EAF6',
blue: 'E3F2FD',
teal: 'E0F2F1',
orange: 'FBE9E7',
gray: 'EEEEEE'
}
options[:class] ||= ''
options[:class] << ' identicon'
bg_key = project.id % 7
style = "background-color: ##{allowed_colors.values[bg_key]}; color: #555"
content_tag(:div, class: options[:class], style: style) do
project.name[0, 1].upcase
end
end
# Takes both user and email and returns the avatar_icon by
# user (preferred) or email.
def avatar_icon_for(user = nil, email = nil, size = nil, scale = 2, only_path: true)
if user
avatar_icon_for_user(user, size, scale, only_path: only_path)
elsif email
avatar_icon_for_email(email, size, scale, only_path: only_path)
else
default_avatar
end
end
def avatar_icon_for_email(email = nil, size = nil, scale = 2, only_path: true)
user = User.find_by_any_email(email.try(:downcase))
if user
avatar_icon_for_user(user, size, scale, only_path: only_path)
else
gravatar_icon(email, size, scale)
end
end
def avatar_icon_for_user(user = nil, size = nil, scale = 2, only_path: true)
if user
user.avatar_url(size: size, only_path: only_path) || default_avatar
else
gravatar_icon(nil, size, scale)
end
end
def gravatar_icon(user_email = '', size = nil, scale = 2)
GravatarService.new.execute(user_email, size, scale) ||
default_avatar
end
def default_avatar
ActionController::Base.helpers.image_path('no_avatar.png')
end
def author_avatar(commit_or_event, options = {}) def author_avatar(commit_or_event, options = {})
user_avatar(options.merge({ user_avatar(options.merge({
user: commit_or_event.author, user: commit_or_event.author,
......
...@@ -3,14 +3,14 @@ module SystemNoteHelper ...@@ -3,14 +3,14 @@ module SystemNoteHelper
ICON_NAMES_BY_ACTION = { ICON_NAMES_BY_ACTION = {
'commit' => 'commit', 'commit' => 'commit',
'description' => 'pencil', 'description' => 'pencil-square',
'merge' => 'git-merge', 'merge' => 'git-merge',
'merged' => 'git-merge', 'merged' => 'git-merge',
'opened' => 'issue-open', 'opened' => 'issue-open',
'closed' => 'issue-close', 'closed' => 'issue-close',
'time_tracking' => 'timer', 'time_tracking' => 'timer',
'assignee' => 'user', 'assignee' => 'user',
'title' => 'pencil', 'title' => 'pencil-square',
'task' => 'task-done', 'task' => 'task-done',
'label' => 'label', 'label' => 'label',
'cross_reference' => 'comment-dots', 'cross_reference' => 'comment-dots',
...@@ -20,7 +20,7 @@ module SystemNoteHelper ...@@ -20,7 +20,7 @@ module SystemNoteHelper
'milestone' => 'clock', 'milestone' => 'clock',
'discussion' => 'comment', 'discussion' => 'comment',
'moved' => 'arrow-right', 'moved' => 'arrow-right',
'outdated' => 'pencil', 'outdated' => 'pencil-square',
'duplicate' => 'issue-duplicate', 'duplicate' => 'issue-duplicate',
'approved' => 'approval', 'approved' => 'approval',
'unapproved' => 'unapproval', 'unapproved' => 'unapproval',
......
...@@ -20,6 +20,7 @@ class Notify < BaseMailer ...@@ -20,6 +20,7 @@ class Notify < BaseMailer
helper BlobHelper helper BlobHelper
helper EmailsHelper helper EmailsHelper
helper MembersHelper helper MembersHelper
helper AvatarsHelper
helper GitlabRoutingHelper helper GitlabRoutingHelper
def test_email(recipient_email, subject, body) def test_email(recipient_email, subject, body)
......
...@@ -59,7 +59,20 @@ class DiffNote < Note ...@@ -59,7 +59,20 @@ class DiffNote < Note
end end
def diff_file def diff_file
@diff_file ||= self.original_position.diff_file(self.project.repository) @diff_file ||=
begin
if created_at_diff?(noteable.diff_refs)
# We're able to use the already persisted diffs (Postgres) if we're
# presenting a "current version" of the MR discussion diff.
# So no need to make an extra Gitaly diff request for it.
# As an extra benefit, the returned `diff_file` already
# has `highlighted_diff_lines` data set from Redis on
# `Diff::FileCollection::MergeRequestDiff`.
noteable.diffs(paths: original_position.paths, expanded: true).diff_files.first
else
original_position.diff_file(self.project.repository)
end
end
end end
def diff_line def diff_line
......
---
title: Fix commit trailer rendering when Gravatar is disabled
merge_request:
author:
type: fixed
---
title: For group dashboard, we no longer show groups which the visitor is not a member of (this applies to admins and auditors)
merge_request: 17884
author: Roger Rüttimann
type: changed
---
title: Increase cluster applications installer availability using alpine linux mirrors
merge_request:
author:
type: performance
---
title: Use persisted diff data instead fetching Git on discussions
merge_request:
author:
type: performance
---
title: Update timeline icon for description edit
merge_request: 18633
author: George Tsiolis
type: changed
var path = require('path'); const path = require('path');
var webpack = require('webpack'); const glob = require('glob');
var argumentsParser = require('commander'); const chalk = require('chalk');
var webpackConfig = require('./webpack.config.js'); const webpack = require('webpack');
var ROOT_PATH = path.resolve(__dirname, '..'); const argumentsParser = require('commander');
const webpackConfig = require('./webpack.config.js');
const ROOT_PATH = path.resolve(__dirname, '..');
function fatalError(message) {
console.error(chalk.red(`\nError: ${message}\n`));
process.exit(1);
}
// remove problematic plugins // remove problematic plugins
if (webpackConfig.plugins) { if (webpackConfig.plugins) {
...@@ -15,33 +23,70 @@ if (webpackConfig.plugins) { ...@@ -15,33 +23,70 @@ if (webpackConfig.plugins) {
}); });
} }
var testFiles = argumentsParser const specFilters = argumentsParser
.option( .option(
'-f, --filter-spec [filter]', '-f, --filter-spec [filter]',
'Filter run spec files by path. Multiple filters are like a logical OR.', 'Filter run spec files by path. Multiple filters are like a logical OR.',
(val, memo) => { (filter, memo) => {
memo.push(val); memo.push(filter, filter.replace(/\/?$/, '/**/*.js'));
return memo; return memo;
}, },
[] []
) )
.parse(process.argv).filterSpec; .parse(process.argv).filterSpec;
webpackConfig.plugins.push( if (specFilters.length) {
new webpack.DefinePlugin({ const specsPath = /^(?:\.[\\\/])?spec[\\\/]javascripts[\\\/]/;
'process.env.TEST_FILES': JSON.stringify(testFiles),
// resolve filters
let filteredSpecFiles = specFilters.map(filter =>
glob
.sync(filter, {
root: ROOT_PATH,
matchBase: true,
}) })
); .filter(path => path.endsWith('spec.js'))
);
// flatten
filteredSpecFiles = Array.prototype.concat.apply([], filteredSpecFiles);
// remove duplicates
filteredSpecFiles = [...new Set(filteredSpecFiles)];
if (filteredSpecFiles.length < 1) {
fatalError('Your filter did not match any test files.');
}
if (!filteredSpecFiles.every(file => specsPath.test(file))) {
fatalError('Test files must be located within /spec/javascripts.');
}
const newContext = filteredSpecFiles.reduce((context, file) => {
const relativePath = file.replace(specsPath, '');
context[file] = `./${relativePath}`;
return context;
}, {});
webpackConfig.plugins.push(
new webpack.ContextReplacementPlugin(
/spec[\\\/]javascripts$/,
path.join(ROOT_PATH, 'spec/javascripts'),
newContext
)
);
}
webpackConfig.devtool = process.env.BABEL_ENV !== 'coverage' && 'cheap-inline-source-map'; webpackConfig.entry = undefined;
webpackConfig.devtool = 'cheap-inline-source-map';
// Karma configuration // Karma configuration
module.exports = function(config) { module.exports = function(config) {
process.env.TZ = 'Etc/UTC'; process.env.TZ = 'Etc/UTC';
var progressReporter = process.env.CI ? 'mocha' : 'progress'; const progressReporter = process.env.CI ? 'mocha' : 'progress';
var karmaConfig = { const karmaConfig = {
basePath: ROOT_PATH, basePath: ROOT_PATH,
browsers: ['ChromeHeadlessCustom'], browsers: ['ChromeHeadlessCustom'],
customLaunchers: { customLaunchers: {
......
...@@ -76,6 +76,9 @@ const config = { ...@@ -76,6 +76,9 @@ const config = {
test: /\.js$/, test: /\.js$/,
exclude: /(node_modules|vendor\/assets)/, exclude: /(node_modules|vendor\/assets)/,
loader: 'babel-loader', loader: 'babel-loader',
options: {
cacheDirectory: path.join(ROOT_PATH, 'tmp/cache/babel-loader'),
},
}, },
{ {
test: /\.vue$/, test: /\.vue$/,
......
# Discussions API # Discussions API
<<<<<<< HEAD
Discussions are set of related notes on snippets, issues, epics, merge requests or commits. Discussions are set of related notes on snippets, issues, epics, merge requests or commits.
=======
Discussions are set of related notes on snippets, issues, merge requests or commits.
>>>>>>> upstream/master
## Issues ## Issues
...@@ -414,6 +418,7 @@ Parameters: ...@@ -414,6 +418,7 @@ Parameters:
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions/636 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions/636
``` ```
<<<<<<< HEAD
## Epics ## Epics
### List group epic discussions ### List group epic discussions
...@@ -621,6 +626,8 @@ Parameters: ...@@ -621,6 +626,8 @@ Parameters:
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/5/epics/11/discussions/636 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/groups/5/epics/11/discussions/636
``` ```
=======
>>>>>>> upstream/master
## Merge requests ## Merge requests
### List project merge request discussions ### List project merge request discussions
......
...@@ -10,7 +10,7 @@ Parameters: ...@@ -10,7 +10,7 @@ Parameters:
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- | | --------- | ---- | -------- | ----------- |
| `skip_groups` | array of integers | no | Skip the group IDs passed | | `skip_groups` | array of integers | no | Skip the group IDs passed |
| `all_available` | boolean | no | Show all the groups you have access to (defaults to `false` for authenticated users) | | `all_available` | boolean | no | Show all the groups you have access to (defaults to `false` for authenticated users, `true` for admin) |
| `search` | string | no | Return the list of authorized groups matching the search criteria | | `search` | string | no | Return the list of authorized groups matching the search criteria |
| `order_by` | string | no | Order groups by `name` or `path`. Default is `name` | | `order_by` | string | no | Order groups by `name` or `path`. Default is `name` |
| `sort` | string | no | Order groups in `asc` or `desc` order. Default is `asc` | | `sort` | string | no | Order groups in `asc` or `desc` order. Default is `asc` |
...@@ -94,7 +94,7 @@ Parameters: ...@@ -94,7 +94,7 @@ Parameters:
| --------- | ---- | -------- | ----------- | | --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) of the parent group | | `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) of the parent group |
| `skip_groups` | array of integers | no | Skip the group IDs passed | | `skip_groups` | array of integers | no | Skip the group IDs passed |
| `all_available` | boolean | no | Show all the groups you have access to (defaults to `false` for authenticated users) | | `all_available` | boolean | no | Show all the groups you have access to (defaults to `false` for authenticated users, `true` for admin) |
| `search` | string | no | Return the list of authorized groups matching the search criteria | | `search` | string | no | Return the list of authorized groups matching the search criteria |
| `order_by` | string | no | Order groups by `name` or `path`. Default is `name` | | `order_by` | string | no | Order groups by `name` or `path`. Default is `name` |
| `sort` | string | no | Order groups in `asc` or `desc` order. Default is `asc` | | `sort` | string | no | Order groups in `asc` or `desc` order. Default is `asc` |
......
...@@ -62,6 +62,7 @@ describe('.methodName', () => { ...@@ -62,6 +62,7 @@ describe('.methodName', () => {
}); });
}); });
``` ```
#### Testing promises #### Testing promises
When testing Promises you should always make sure that the test is asynchronous and rejections are handled. When testing Promises you should always make sure that the test is asynchronous and rejections are handled.
...@@ -69,9 +70,9 @@ Your Promise chain should therefore end with a call of the `done` callback and ` ...@@ -69,9 +70,9 @@ Your Promise chain should therefore end with a call of the `done` callback and `
```javascript ```javascript
// Good // Good
it('tests a promise', (done) => { it('tests a promise', done => {
promise promise
.then((data) => { .then(data => {
expect(data).toBe(asExpected); expect(data).toBe(asExpected);
}) })
.then(done) .then(done)
...@@ -79,10 +80,10 @@ it('tests a promise', (done) => { ...@@ -79,10 +80,10 @@ it('tests a promise', (done) => {
}); });
// Good // Good
it('tests a promise rejection', (done) => { it('tests a promise rejection', done => {
promise promise
.then(done.fail) .then(done.fail)
.catch((error) => { .catch(error => {
expect(error).toBe(expectedError); expect(error).toBe(expectedError);
}) })
.then(done) .then(done)
...@@ -91,38 +92,37 @@ it('tests a promise rejection', (done) => { ...@@ -91,38 +92,37 @@ it('tests a promise rejection', (done) => {
// Bad (missing done callback) // Bad (missing done callback)
it('tests a promise', () => { it('tests a promise', () => {
promise promise.then(data => {
.then((data) => {
expect(data).toBe(asExpected); expect(data).toBe(asExpected);
}) });
}); });
// Bad (missing catch) // Bad (missing catch)
it('tests a promise', (done) => { it('tests a promise', done => {
promise promise
.then((data) => { .then(data => {
expect(data).toBe(asExpected); expect(data).toBe(asExpected);
}) })
.then(done) .then(done);
}); });
// Bad (use done.fail in asynchronous tests) // Bad (use done.fail in asynchronous tests)
it('tests a promise', (done) => { it('tests a promise', done => {
promise promise
.then((data) => { .then(data => {
expect(data).toBe(asExpected); expect(data).toBe(asExpected);
}) })
.then(done) .then(done)
.catch(fail) .catch(fail);
}); });
// Bad (missing catch) // Bad (missing catch)
it('tests a promise rejection', (done) => { it('tests a promise rejection', done => {
promise promise
.catch((error) => { .catch(error => {
expect(error).toBe(expectedError); expect(error).toBe(expectedError);
}) })
.then(done) .then(done);
}); });
``` ```
...@@ -181,8 +181,8 @@ See this [section][vue-test]. ...@@ -181,8 +181,8 @@ See this [section][vue-test].
`rake karma` runs the frontend-only (JavaScript) tests. `rake karma` runs the frontend-only (JavaScript) tests.
It consists of two subtasks: It consists of two subtasks:
- `rake karma:fixtures` (re-)generates fixtures * `rake karma:fixtures` (re-)generates fixtures
- `rake karma:tests` actually executes the tests * `rake karma:tests` actually executes the tests
As long as the fixtures don't change, `rake karma:tests` (or `yarn karma`) As long as the fixtures don't change, `rake karma:tests` (or `yarn karma`)
is sufficient (and saves you some time). is sufficient (and saves you some time).
...@@ -217,6 +217,14 @@ yarn karma-start --filter-spec profile/account/components/ ...@@ -217,6 +217,14 @@ yarn karma-start --filter-spec profile/account/components/
yarn karma-start -f vue_shared -f vue_mr_widget yarn karma-start -f vue_shared -f vue_mr_widget
``` ```
You can also use glob syntax to match files. Remember to put quotes around the
glob otherwise your shell may split it into multiple arguments:
```bash
# Run all specs named `file_spec` within the IDE subdirectory
yarn karma -f 'spec/javascripts/ide/**/file_spec.js'
```
## RSpec feature integration tests ## RSpec feature integration tests
Information on setting up and running RSpec integration tests with Information on setting up and running RSpec integration tests with
...@@ -231,14 +239,14 @@ supported by the PhantomJS test runner which is used for both Karma and RSpec ...@@ -231,14 +239,14 @@ supported by the PhantomJS test runner which is used for both Karma and RSpec
tests. We polyfill some JavaScript objects for older browsers, but some tests. We polyfill some JavaScript objects for older browsers, but some
features are still unavailable: features are still unavailable:
- Array.from * Array.from
- Array.first * Array.first
- Async functions * Async functions
- Generators * Generators
- Array destructuring * Array destructuring
- For..Of * For..Of
- Symbol/Symbol.iterator * Symbol/Symbol.iterator
- Spread * Spread
Until these are polyfilled appropriately, they should not be used. Please Until these are polyfilled appropriately, they should not be used. Please
update this list with additional unsupported features. update this list with additional unsupported features.
...@@ -295,11 +303,11 @@ Scenario: Developer can approve merge request ...@@ -295,11 +303,11 @@ Scenario: Developer can approve merge request
[jasmine-focus]: https://jasmine.github.io/2.5/focused_specs.html [jasmine-focus]: https://jasmine.github.io/2.5/focused_specs.html
[jasmine-jquery]: https://github.com/velesin/jasmine-jquery [jasmine-jquery]: https://github.com/velesin/jasmine-jquery
[karma]: http://karma-runner.github.io/ [karma]: http://karma-runner.github.io/
[vue-test]:https://docs.gitlab.com/ce/development/fe_guide/vue.html#testing-vue-components [vue-test]: https://docs.gitlab.com/ce/development/fe_guide/vue.html#testing-vue-components
[RSpec]: https://github.com/rspec/rspec-rails#feature-specs [rspec]: https://github.com/rspec/rspec-rails#feature-specs
[Capybara]: https://github.com/teamcapybara/capybara [capybara]: https://github.com/teamcapybara/capybara
[Karma]: http://karma-runner.github.io/ [karma]: http://karma-runner.github.io/
[Jasmine]: https://jasmine.github.io/ [jasmine]: https://jasmine.github.io/
--- ---
......
...@@ -5,7 +5,11 @@ module API ...@@ -5,7 +5,11 @@ module API
before { authenticate! } before { authenticate! }
<<<<<<< HEAD
NOTEABLE_TYPES = [Issue, Snippet, Epic, MergeRequest, Commit].freeze NOTEABLE_TYPES = [Issue, Snippet, Epic, MergeRequest, Commit].freeze
=======
NOTEABLE_TYPES = [Issue, Snippet, MergeRequest, Commit].freeze
>>>>>>> upstream/master
NOTEABLE_TYPES.each do |noteable_type| NOTEABLE_TYPES.each do |noteable_type|
parent_type = noteable_type.parent_class.to_s.underscore parent_type = noteable_type.parent_class.to_s.underscore
......
...@@ -46,13 +46,11 @@ module API ...@@ -46,13 +46,11 @@ module API
use :pagination use :pagination
end end
def find_groups(params) def find_groups(params, parent_id = nil)
find_params = { find_params = params.slice(:all_available, :custom_attributes, :owned)
all_available: params[:all_available], find_params[:parent] = find_group!(parent_id) if parent_id
custom_attributes: params[:custom_attributes], find_params[:all_available] =
owned: params[:owned] find_params.fetch(:all_available, current_user&.full_private_access?)
}
find_params[:parent] = find_group!(params[:id]) if params[:id]
groups = GroupsFinder.new(current_user, find_params).execute groups = GroupsFinder.new(current_user, find_params).execute
# EE-only # EE-only
...@@ -96,7 +94,7 @@ module API ...@@ -96,7 +94,7 @@ module API
use :with_custom_attributes use :with_custom_attributes
end end
get do get do
groups = find_groups(params) groups = find_groups(declared_params(include_missing: false), params[:id])
present_groups params, groups present_groups params, groups
end end
...@@ -250,7 +248,7 @@ module API ...@@ -250,7 +248,7 @@ module API
use :with_custom_attributes use :with_custom_attributes
end end
get ":id/subgroups" do get ":id/subgroups" do
groups = find_groups(params) groups = find_groups(declared_params(include_missing: false), params[:id])
present_groups params, groups present_groups params, groups
end end
......
...@@ -7,6 +7,9 @@ module API ...@@ -7,6 +7,9 @@ module API
helpers do helpers do
params :with_custom_attributes do params :with_custom_attributes do
optional :with_custom_attributes, type: Boolean, default: false, desc: 'Include custom attributes in the response' optional :with_custom_attributes, type: Boolean, default: false, desc: 'Include custom attributes in the response'
optional :custom_attributes, type: Hash,
desc: 'Filter with custom attributes'
end end
def with_custom_attributes(collection_or_resource, options = {}) def with_custom_attributes(collection_or_resource, options = {})
......
...@@ -13,7 +13,6 @@ module Banzai ...@@ -13,7 +13,6 @@ module Banzai
# * https://git.wiki.kernel.org/index.php/CommitMessageConventions # * https://git.wiki.kernel.org/index.php/CommitMessageConventions
class CommitTrailersFilter < HTML::Pipeline::Filter class CommitTrailersFilter < HTML::Pipeline::Filter
include ActionView::Helpers::TagHelper include ActionView::Helpers::TagHelper
include ApplicationHelper
include AvatarsHelper include AvatarsHelper
TRAILER_REGEXP = /(?<label>[[:alpha:]-]+-by:)/i.freeze TRAILER_REGEXP = /(?<label>[[:alpha:]-]+-by:)/i.freeze
......
...@@ -36,6 +36,8 @@ module Gitlab ...@@ -36,6 +36,8 @@ module Gitlab
private private
def decorate_diff!(diff) def decorate_diff!(diff)
return diff if diff.is_a?(File)
Gitlab::Diff::File.new(diff, repository: project.repository, diff_refs: diff_refs, fallback_diff_refs: fallback_diff_refs) Gitlab::Diff::File.new(diff, repository: project.repository, diff_refs: diff_refs, fallback_diff_refs: fallback_diff_refs)
end end
end end
......
...@@ -38,7 +38,9 @@ module Gitlab ...@@ -38,7 +38,9 @@ module Gitlab
end end
def extract_operation def extract_operation
case @raw_operation&.first(1) return :unknown unless @raw_operation
case @raw_operation[0]
when 'A' when 'A'
:added :added
when 'C' when 'C'
......
...@@ -15,6 +15,9 @@ module Gitlab ...@@ -15,6 +15,9 @@ module Gitlab
def generate_script def generate_script
<<~HEREDOC <<~HEREDOC
set -eo pipefail set -eo pipefail
ALPINE_VERSION=$(cat /etc/alpine-release | cut -d '.' -f 1,2)
echo http://mirror.clarkson.edu/alpine/v$ALPINE_VERSION/main >> /etc/apk/repositories
echo http://mirror1.hs-esslingen.de/pub/Mirrors/alpine/v$ALPINE_VERSION/main >> /etc/apk/repositories
apk add -U ca-certificates openssl >/dev/null apk add -U ca-certificates openssl >/dev/null
wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v#{Gitlab::Kubernetes::Helm::HELM_VERSION}-linux-amd64.tar.gz | tar zxC /tmp >/dev/null wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v#{Gitlab::Kubernetes::Helm::HELM_VERSION}-linux-amd64.tar.gz | tar zxC /tmp >/dev/null
mv /tmp/linux-amd64/helm /usr/bin/ mv /tmp/linux-amd64/helm /usr/bin/
......
...@@ -47,7 +47,7 @@ GEM ...@@ -47,7 +47,7 @@ GEM
mini_portile2 (2.3.0) mini_portile2 (2.3.0)
minitest (5.11.1) minitest (5.11.1)
netrc (0.11.0) netrc (0.11.0)
nokogiri (1.8.1) nokogiri (1.8.2)
mini_portile2 (~> 2.3.0) mini_portile2 (~> 2.3.0)
pry (0.11.3) pry (0.11.3)
coderay (~> 1.1.0) coderay (~> 1.1.0)
......
...@@ -40,7 +40,7 @@ feature 'Dashboard Groups page', :js do ...@@ -40,7 +40,7 @@ feature 'Dashboard Groups page', :js do
expect(page).to have_content(nested_group.name) expect(page).to have_content(nested_group.name)
end end
describe 'when filtering groups', :nested_groups do context 'when filtering groups', :nested_groups do
before do before do
group.add_owner(user) group.add_owner(user)
nested_group.add_owner(user) nested_group.add_owner(user)
...@@ -75,7 +75,7 @@ feature 'Dashboard Groups page', :js do ...@@ -75,7 +75,7 @@ feature 'Dashboard Groups page', :js do
end end
end end
describe 'group with subgroups', :nested_groups do context 'with subgroups', :nested_groups do
let!(:subgroup) { create(:group, :public, parent: group) } let!(:subgroup) { create(:group, :public, parent: group) }
before do before do
...@@ -106,7 +106,7 @@ feature 'Dashboard Groups page', :js do ...@@ -106,7 +106,7 @@ feature 'Dashboard Groups page', :js do
end end
end end
describe 'when using pagination' do context 'when using pagination' do
let(:group) { create(:group, created_at: 5.days.ago) } let(:group) { create(:group, created_at: 5.days.ago) }
let(:group2) { create(:group, created_at: 2.days.ago) } let(:group2) { create(:group, created_at: 2.days.ago) }
...@@ -141,4 +141,20 @@ feature 'Dashboard Groups page', :js do ...@@ -141,4 +141,20 @@ feature 'Dashboard Groups page', :js do
expect(page).not_to have_selector("#group-#{group2.id}") expect(page).not_to have_selector("#group-#{group2.id}")
end end
end end
context 'when signed in as admin' do
let(:admin) { create(:admin) }
it 'shows only groups admin is member of' do
group.add_owner(admin)
expect(another_group).to be_persisted
sign_in(admin)
visit dashboard_groups_path
wait_for_requests
expect(page).to have_content(group.name)
expect(page).not_to have_content(another_group.name)
end
end
end end
require "spec_helper" require "spec_helper"
describe "User toggles subscription", :js do describe "User toggles subscription", :js do
set(:project) { create(:project_empty_repo, :public) } let(:project) { create(:project_empty_repo, :public) }
set(:user) { create(:user) } let(:user) { create(:user) }
set(:issue) { create(:issue, project: project, author: user) } let(:issue) { create(:issue, project: project, author: user) }
before do before do
project.add_developer(user) project.add_developer(user)
...@@ -12,7 +12,7 @@ describe "User toggles subscription", :js do ...@@ -12,7 +12,7 @@ describe "User toggles subscription", :js do
visit(project_issue_path(project, issue)) visit(project_issue_path(project, issue))
end end
it "unsibscribes from issue" do it "unsubscribes from issue" do
subscription_button = find(".js-issuable-subscribe-button") subscription_button = find(".js-issuable-subscribe-button")
# Check we're subscribed. # Check we're subscribed.
......
...@@ -4,41 +4,69 @@ describe GroupsFinder do ...@@ -4,41 +4,69 @@ describe GroupsFinder do
describe '#execute' do describe '#execute' do
let(:user) { create(:user) } let(:user) { create(:user) }
context 'root level groups' do describe 'root level groups' do
let!(:private_group) { create(:group, :private) } using RSpec::Parameterized::TableSyntax
let!(:internal_group) { create(:group, :internal) }
let!(:public_group) { create(:group, :public) }
context 'without a user' do where(:user_type, :params, :results) do
subject { described_class.new.execute } nil | { all_available: true } | %i(public_group user_public_group)
nil | { all_available: false } | %i(public_group user_public_group)
nil | {} | %i(public_group user_public_group)
it { is_expected.to eq([public_group]) } :regular | { all_available: true } | %i(public_group internal_group user_public_group user_internal_group
end user_private_group)
:regular | { all_available: false } | %i(user_public_group user_internal_group user_private_group)
:regular | {} | %i(public_group internal_group user_public_group user_internal_group user_private_group)
context 'with a user' do :external | { all_available: true } | %i(public_group user_public_group user_internal_group user_private_group)
subject { described_class.new(user).execute } :external | { all_available: false } | %i(user_public_group user_internal_group user_private_group)
:external | {} | %i(public_group user_public_group user_internal_group user_private_group)
context 'normal user' do :admin | { all_available: true } | %i(public_group internal_group private_group user_public_group
it { is_expected.to contain_exactly(public_group, internal_group) } user_internal_group user_private_group)
:admin | { all_available: false } | %i(user_public_group user_internal_group user_private_group)
:admin | {} | %i(public_group internal_group private_group user_public_group user_internal_group
user_private_group)
end end
context 'external user' do with_them do
let(:user) { create(:user, external: true) } before do
# Fixme: Because of an issue: https://github.com/tomykaira/rspec-parameterized/issues/8#issuecomment-381888428
# The groups need to be created here, not with let syntax, and also compared by name and not ids
it { is_expected.to contain_exactly(public_group) } @groups = {
end private_group: create(:group, :private, name: 'private_group'),
internal_group: create(:group, :internal, name: 'internal_group'),
public_group: create(:group, :public, name: 'public_group'),
context 'user is member of the private group' do user_private_group: create(:group, :private, name: 'user_private_group'),
before do user_internal_group: create(:group, :internal, name: 'user_internal_group'),
private_group.add_guest(user) user_public_group: create(:group, :public, name: 'user_public_group')
end }
it { is_expected.to contain_exactly(public_group, internal_group, private_group) } if user_type
user =
case user_type
when :regular
create(:user)
when :external
create(:user, external: true)
when :admin
create(:user, :admin)
end
@groups.values_at(:user_private_group, :user_internal_group, :user_public_group).each do |group|
group.add_developer(user)
end end
end end
end end
subject { described_class.new(User.last, params).execute.to_a }
it { is_expected.to match_array(@groups.values_at(*results)) }
end
end
context 'subgroups', :nested_groups do context 'subgroups', :nested_groups do
let(:user) { create(:user) }
let!(:parent_group) { create(:group, :public) } let!(:parent_group) { create(:group, :public) }
let!(:public_subgroup) { create(:group, :public, parent: parent_group) } let!(:public_subgroup) { create(:group, :public, parent: parent_group) }
let!(:internal_subgroup) { create(:group, :internal, parent: parent_group) } let!(:internal_subgroup) { create(:group, :internal, parent: parent_group) }
......
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
require 'spec_helper' require 'spec_helper'
describe ApplicationHelper do describe ApplicationHelper do
include UploadHelpers
describe 'current_controller?' do describe 'current_controller?' do
it 'returns true when controller matches argument' do it 'returns true when controller matches argument' do
stub_controller_name('foo') stub_controller_name('foo')
...@@ -54,143 +52,6 @@ describe ApplicationHelper do ...@@ -54,143 +52,6 @@ describe ApplicationHelper do
end end
end end
describe 'project_icon' do
it 'returns an url for the avatar' do
project = create(:project, :public, avatar: File.open(uploaded_image_temp_path))
expect(helper.project_icon(project.full_path).to_s)
.to eq "<img data-src=\"#{project.avatar.url}\" class=\" lazy\" src=\"#{LazyImageTagHelper.placeholder_image}\" />"
end
end
describe 'avatar_icon_for' do
let!(:user) { create(:user, avatar: File.open(uploaded_image_temp_path), email: 'bar@example.com') }
let(:email) { 'foo@example.com' }
let!(:another_user) { create(:user, avatar: File.open(uploaded_image_temp_path), email: email) }
it 'prefers the user to retrieve the avatar_url' do
expect(helper.avatar_icon_for(user, email).to_s)
.to eq(user.avatar.url)
end
it 'falls back to email lookup if no user given' do
expect(helper.avatar_icon_for(nil, email).to_s)
.to eq(another_user.avatar.url)
end
end
describe 'avatar_icon_for_email' do
let(:user) { create(:user, avatar: File.open(uploaded_image_temp_path)) }
context 'using an email' do
context 'when there is a matching user' do
it 'returns a relative URL for the avatar' do
expect(helper.avatar_icon_for_email(user.email).to_s)
.to eq(user.avatar.url)
end
end
context 'when no user exists for the email' do
it 'calls gravatar_icon' do
expect(helper).to receive(:gravatar_icon).with('foo@example.com', 20, 2)
helper.avatar_icon_for_email('foo@example.com', 20, 2)
end
end
context 'without an email passed' do
it 'calls gravatar_icon' do
expect(helper).to receive(:gravatar_icon).with(nil, 20, 2)
helper.avatar_icon_for_email(nil, 20, 2)
end
end
end
end
describe 'avatar_icon_for_user' do
let(:user) { create(:user, avatar: File.open(uploaded_image_temp_path)) }
context 'with a user object passed' do
it 'returns a relative URL for the avatar' do
expect(helper.avatar_icon_for_user(user).to_s)
.to eq(user.avatar.url)
end
end
context 'without a user object passed' do
it 'calls gravatar_icon' do
expect(helper).to receive(:gravatar_icon).with(nil, 20, 2)
helper.avatar_icon_for_user(nil, 20, 2)
end
end
end
describe 'gravatar_icon' do
let(:user_email) { 'user@email.com' }
context 'with Gravatar disabled' do
before do
stub_application_setting(gravatar_enabled?: false)
end
it 'returns a generic avatar' do
expect(helper.gravatar_icon(user_email)).to match_asset_path('no_avatar.png')
end
end
context 'with Gravatar enabled' do
before do
stub_application_setting(gravatar_enabled?: true)
end
it 'returns a generic avatar when email is blank' do
expect(helper.gravatar_icon('')).to match_asset_path('no_avatar.png')
end
it 'returns a valid Gravatar URL' do
stub_config_setting(https: false)
expect(helper.gravatar_icon(user_email))
.to match('https://www.gravatar.com/avatar/b58c6f14d292556214bd64909bcdb118')
end
it 'uses HTTPs when configured' do
stub_config_setting(https: true)
expect(helper.gravatar_icon(user_email))
.to match('https://secure.gravatar.com')
end
it 'returns custom gravatar path when gravatar_url is set' do
stub_gravatar_setting(plain_url: 'http://example.local/?s=%{size}&hash=%{hash}')
expect(gravatar_icon(user_email, 20))
.to eq('http://example.local/?s=40&hash=b58c6f14d292556214bd64909bcdb118')
end
it 'accepts a custom size argument' do
expect(helper.gravatar_icon(user_email, 64)).to include '?s=128'
end
it 'defaults size to 40@2x when given an invalid size' do
expect(helper.gravatar_icon(user_email, nil)).to include '?s=80'
end
it 'accepts a scaling factor' do
expect(helper.gravatar_icon(user_email, 40, 3)).to include '?s=120'
end
it 'ignores case and surrounding whitespace' do
normal = helper.gravatar_icon('foo@example.com')
upcase = helper.gravatar_icon(' FOO@EXAMPLE.COM ')
expect(normal).to eq upcase
end
end
end
describe 'simple_sanitize' do describe 'simple_sanitize' do
let(:a_tag) { '<a href="#">Foo</a>' } let(:a_tag) { '<a href="#">Foo</a>' }
......
...@@ -33,11 +33,14 @@ describe AuthHelper do ...@@ -33,11 +33,14 @@ describe AuthHelper do
allow(helper).to receive(:auth_providers) { [:twitter, :ldapmain] } allow(helper).to receive(:auth_providers) { [:twitter, :ldapmain] }
expect(helper.providers_for_base_controller).not_to include(:ldapmain) expect(helper.providers_for_base_controller).not_to include(:ldapmain)
end end
<<<<<<< HEAD
it 'excludes group_saml' do it 'excludes group_saml' do
allow(helper).to receive(:auth_providers) { [:group_saml] } allow(helper).to receive(:auth_providers) { [:group_saml] }
expect(helper.providers_for_base_controller).to eq([]) expect(helper.providers_for_base_controller).to eq([])
end end
=======
>>>>>>> upstream/master
end end
describe "form_based_providers" do describe "form_based_providers" do
...@@ -50,11 +53,14 @@ describe AuthHelper do ...@@ -50,11 +53,14 @@ describe AuthHelper do
allow(helper).to receive(:auth_providers) { [:twitter, :crowd] } allow(helper).to receive(:auth_providers) { [:twitter, :crowd] }
expect(helper.form_based_providers).to eq %i(crowd) expect(helper.form_based_providers).to eq %i(crowd)
end end
<<<<<<< HEAD
it 'includes kerberos provider' do it 'includes kerberos provider' do
allow(helper).to receive(:auth_providers) { [:twitter, :kerberos] } allow(helper).to receive(:auth_providers) { [:twitter, :kerberos] }
expect(helper.form_based_providers).to eq %i(kerberos) expect(helper.form_based_providers).to eq %i(kerberos)
end end
=======
>>>>>>> upstream/master
end end
describe 'enabled_button_based_providers' do describe 'enabled_button_based_providers' do
......
require 'rails_helper' require 'rails_helper'
describe AvatarsHelper do describe AvatarsHelper do
include ApplicationHelper include UploadHelpers
let(:user) { create(:user) } let(:user) { create(:user) }
describe '#project_icon' do
it 'returns an url for the avatar' do
project = create(:project, :public, avatar: File.open(uploaded_image_temp_path))
expect(helper.project_icon(project.full_path).to_s)
.to eq "<img data-src=\"#{project.avatar.url}\" class=\" lazy\" src=\"#{LazyImageTagHelper.placeholder_image}\" />"
end
end
describe '#avatar_icon_for' do
let!(:user) { create(:user, avatar: File.open(uploaded_image_temp_path), email: 'bar@example.com') }
let(:email) { 'foo@example.com' }
let!(:another_user) { create(:user, avatar: File.open(uploaded_image_temp_path), email: email) }
it 'prefers the user to retrieve the avatar_url' do
expect(helper.avatar_icon_for(user, email).to_s)
.to eq(user.avatar.url)
end
it 'falls back to email lookup if no user given' do
expect(helper.avatar_icon_for(nil, email).to_s)
.to eq(another_user.avatar.url)
end
end
describe '#avatar_icon_for_email' do
let(:user) { create(:user, avatar: File.open(uploaded_image_temp_path)) }
context 'using an email' do
context 'when there is a matching user' do
it 'returns a relative URL for the avatar' do
expect(helper.avatar_icon_for_email(user.email).to_s)
.to eq(user.avatar.url)
end
end
context 'when no user exists for the email' do
it 'calls gravatar_icon' do
expect(helper).to receive(:gravatar_icon).with('foo@example.com', 20, 2)
helper.avatar_icon_for_email('foo@example.com', 20, 2)
end
end
context 'without an email passed' do
it 'calls gravatar_icon' do
expect(helper).to receive(:gravatar_icon).with(nil, 20, 2)
helper.avatar_icon_for_email(nil, 20, 2)
end
end
end
end
describe '#avatar_icon_for_user' do
let(:user) { create(:user, avatar: File.open(uploaded_image_temp_path)) }
context 'with a user object passed' do
it 'returns a relative URL for the avatar' do
expect(helper.avatar_icon_for_user(user).to_s)
.to eq(user.avatar.url)
end
end
context 'without a user object passed' do
it 'calls gravatar_icon' do
expect(helper).to receive(:gravatar_icon).with(nil, 20, 2)
helper.avatar_icon_for_user(nil, 20, 2)
end
end
end
describe '#gravatar_icon' do
let(:user_email) { 'user@email.com' }
context 'with Gravatar disabled' do
before do
stub_application_setting(gravatar_enabled?: false)
end
it 'returns a generic avatar' do
expect(helper.gravatar_icon(user_email)).to match_asset_path('no_avatar.png')
end
end
context 'with Gravatar enabled' do
before do
stub_application_setting(gravatar_enabled?: true)
end
it 'returns a generic avatar when email is blank' do
expect(helper.gravatar_icon('')).to match_asset_path('no_avatar.png')
end
it 'returns a valid Gravatar URL' do
stub_config_setting(https: false)
expect(helper.gravatar_icon(user_email))
.to match('https://www.gravatar.com/avatar/b58c6f14d292556214bd64909bcdb118')
end
it 'uses HTTPs when configured' do
stub_config_setting(https: true)
expect(helper.gravatar_icon(user_email))
.to match('https://secure.gravatar.com')
end
it 'returns custom gravatar path when gravatar_url is set' do
stub_gravatar_setting(plain_url: 'http://example.local/?s=%{size}&hash=%{hash}')
expect(gravatar_icon(user_email, 20))
.to eq('http://example.local/?s=40&hash=b58c6f14d292556214bd64909bcdb118')
end
it 'accepts a custom size argument' do
expect(helper.gravatar_icon(user_email, 64)).to include '?s=128'
end
it 'defaults size to 40@2x when given an invalid size' do
expect(helper.gravatar_icon(user_email, nil)).to include '?s=80'
end
it 'accepts a scaling factor' do
expect(helper.gravatar_icon(user_email, 40, 3)).to include '?s=120'
end
it 'ignores case and surrounding whitespace' do
normal = helper.gravatar_icon('foo@example.com')
upcase = helper.gravatar_icon(' FOO@EXAMPLE.COM ')
expect(normal).to eq upcase
end
end
end
describe '#user_avatar' do describe '#user_avatar' do
subject { helper.user_avatar(user: user) } subject { helper.user_avatar(user: user) }
......
...@@ -83,21 +83,11 @@ beforeEach(() => { ...@@ -83,21 +83,11 @@ beforeEach(() => {
const axiosDefaultAdapter = getDefaultAdapter(); const axiosDefaultAdapter = getDefaultAdapter();
let testFiles = process.env.TEST_FILES || [];
if (testFiles.length > 0) {
testFiles = testFiles.map(path => path.replace(/^spec\/javascripts\//, '').replace(/\.js$/, ''));
console.log(`Running only tests matching: ${testFiles}`);
} else {
console.log('Running all tests');
}
// render all of our tests // render all of our tests
const testsContext = require.context('.', true, /_spec$/); const testsContext = require.context('.', true, /_spec$/);
testsContext.keys().forEach(function(path) { testsContext.keys().forEach(function(path) {
try { try {
if (testFiles.length === 0 || testFiles.some(p => path.includes(p))) {
testsContext(path); testsContext(path);
}
} catch (err) { } catch (err) {
console.error('[ERROR] Unable to load spec: ', path); console.error('[ERROR] Unable to load spec: ', path);
describe('Test bundle', function() { describe('Test bundle', function() {
......
...@@ -47,7 +47,9 @@ describe Banzai::Filter::CommitTrailersFilter do ...@@ -47,7 +47,9 @@ describe Banzai::Filter::CommitTrailersFilter do
) )
end end
it 'non GitLab users and replaces them with mailto links' do context 'non GitLab users' do
shared_examples 'mailto links' do
it 'replaces them with mailto links' do
_, message_html = build_commit_message( _, message_html = build_commit_message(
trailer: trailer, trailer: trailer,
name: FFaker::Name.name, name: FFaker::Name.name,
...@@ -56,7 +58,25 @@ describe Banzai::Filter::CommitTrailersFilter do ...@@ -56,7 +58,25 @@ describe Banzai::Filter::CommitTrailersFilter do
doc = filter(message_html) doc = filter(message_html)
expect_to_have_mailto_link(doc, email: email, trailer: trailer) expect_to_have_mailto_link_with_avatar(doc, email: email, trailer: trailer)
end
end
context 'when Gravatar is disabled' do
before do
stub_application_setting(gravatar_enabled: false)
end
it_behaves_like 'mailto links'
end
context 'when Gravatar is enabled' do
before do
stub_application_setting(gravatar_enabled: true)
end
it_behaves_like 'mailto links'
end
end end
it 'multiple trailers in the same message' do it 'multiple trailers in the same message' do
...@@ -69,7 +89,7 @@ describe Banzai::Filter::CommitTrailersFilter do ...@@ -69,7 +89,7 @@ describe Banzai::Filter::CommitTrailersFilter do
doc = filter(message) doc = filter(message)
expect_to_have_user_link_with_avatar(doc, user: user, trailer: trailer) expect_to_have_user_link_with_avatar(doc, user: user, trailer: trailer)
expect_to_have_mailto_link(doc, email: email, trailer: different_trailer) expect_to_have_mailto_link_with_avatar(doc, email: email, trailer: different_trailer)
end end
context 'special names' do context 'special names' do
...@@ -90,7 +110,7 @@ describe Banzai::Filter::CommitTrailersFilter do ...@@ -90,7 +110,7 @@ describe Banzai::Filter::CommitTrailersFilter do
doc = filter(message_html) doc = filter(message_html)
expect_to_have_mailto_link(doc, email: email, trailer: trailer) expect_to_have_mailto_link_with_avatar(doc, email: email, trailer: trailer)
expect(doc.text).to match Regexp.escape(message) expect(doc.text).to match Regexp.escape(message)
end end
end end
......
...@@ -4,22 +4,10 @@ describe Gitlab::Kubernetes::Helm::BaseCommand do ...@@ -4,22 +4,10 @@ describe Gitlab::Kubernetes::Helm::BaseCommand do
let(:application) { create(:clusters_applications_helm) } let(:application) { create(:clusters_applications_helm) }
let(:base_command) { described_class.new(application.name) } let(:base_command) { described_class.new(application.name) }
describe '#generate_script' do subject { base_command }
let(:helm_version) { Gitlab::Kubernetes::Helm::HELM_VERSION }
let(:command) do
<<~HEREDOC
set -eo pipefail
apk add -U ca-certificates openssl >/dev/null
wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v#{helm_version}-linux-amd64.tar.gz | tar zxC /tmp >/dev/null
mv /tmp/linux-amd64/helm /usr/bin/
HEREDOC
end
subject { base_command.generate_script }
it 'should return a command that prepares the environment for helm-cli' do it_behaves_like 'helm commands' do
expect(subject).to eq(command) let(:commands) { '' }
end
end end
describe '#pod_resource' do describe '#pod_resource' do
......
...@@ -2,23 +2,9 @@ require 'spec_helper' ...@@ -2,23 +2,9 @@ require 'spec_helper'
describe Gitlab::Kubernetes::Helm::InitCommand do describe Gitlab::Kubernetes::Helm::InitCommand do
let(:application) { create(:clusters_applications_helm) } let(:application) { create(:clusters_applications_helm) }
let(:init_command) { described_class.new(application.name) } let(:commands) { 'helm init >/dev/null' }
describe '#generate_script' do subject { described_class.new(application.name) }
let(:command) do
<<~MSG.chomp
set -eo pipefail
apk add -U ca-certificates openssl >/dev/null
wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-amd64.tar.gz | tar zxC /tmp >/dev/null
mv /tmp/linux-amd64/helm /usr/bin/
helm init >/dev/null
MSG
end
subject { init_command.generate_script } it_behaves_like 'helm commands'
it 'should return the appropriate command' do
is_expected.to eq(command)
end
end
end end
...@@ -12,22 +12,15 @@ describe Gitlab::Kubernetes::Helm::InstallCommand do ...@@ -12,22 +12,15 @@ describe Gitlab::Kubernetes::Helm::InstallCommand do
) )
end end
describe '#generate_script' do subject { install_command }
let(:command) do
<<~MSG it_behaves_like 'helm commands' do
set -eo pipefail let(:commands) do
apk add -U ca-certificates openssl >/dev/null <<~EOS
wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-amd64.tar.gz | tar zxC /tmp >/dev/null
mv /tmp/linux-amd64/helm /usr/bin/
helm init --client-only >/dev/null helm init --client-only >/dev/null
helm install #{application.chart} --name #{application.name} --namespace #{namespace} -f /data/helm/#{application.name}/config/values.yaml >/dev/null helm install #{application.chart} --name #{application.name} --namespace #{namespace} -f /data/helm/#{application.name}/config/values.yaml >/dev/null
MSG EOS
end end
subject { install_command.generate_script }
it 'should return appropriate command' do
is_expected.to eq(command)
end end
context 'with an application with a repository' do context 'with an application with a repository' do
...@@ -42,20 +35,13 @@ describe Gitlab::Kubernetes::Helm::InstallCommand do ...@@ -42,20 +35,13 @@ describe Gitlab::Kubernetes::Helm::InstallCommand do
) )
end end
let(:command) do it_behaves_like 'helm commands' do
<<~MSG let(:commands) do
set -eo pipefail <<~EOS
apk add -U ca-certificates openssl >/dev/null
wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-amd64.tar.gz | tar zxC /tmp >/dev/null
mv /tmp/linux-amd64/helm /usr/bin/
helm init --client-only >/dev/null helm init --client-only >/dev/null
helm repo add #{application.name} #{application.repository} helm repo add #{application.name} #{application.repository}
helm install #{application.chart} --name #{application.name} --namespace #{namespace} -f /data/helm/#{application.name}/config/values.yaml >/dev/null helm install #{application.chart} --name #{application.name} --namespace #{namespace} -f /data/helm/#{application.name}/config/values.yaml >/dev/null
MSG EOS
end
it 'should return appropriate command' do
is_expected.to eq(command)
end end
end end
end end
......
...@@ -85,7 +85,8 @@ describe DiffNote do ...@@ -85,7 +85,8 @@ describe DiffNote do
end end
describe "#diff_file" do describe "#diff_file" do
it "returns the correct diff file" do context 'when the discussion was created in the diff' do
it 'returns correct diff file' do
diff_file = subject.diff_file diff_file = subject.diff_file
expect(diff_file.old_path).to eq(position.old_path) expect(diff_file.old_path).to eq(position.old_path)
...@@ -94,6 +95,28 @@ describe DiffNote do ...@@ -94,6 +95,28 @@ describe DiffNote do
end end
end end
context 'when discussion is outdated or not created in the diff' do
let(:diff_refs) { project.commit(sample_commit.id).diff_refs }
let(:position) do
Gitlab::Diff::Position.new(
old_path: "files/ruby/popen.rb",
new_path: "files/ruby/popen.rb",
old_line: nil,
new_line: 14,
diff_refs: diff_refs
)
end
it 'returns the correct diff file' do
diff_file = subject.diff_file
expect(diff_file.old_path).to eq(position.old_path)
expect(diff_file.new_path).to eq(position.new_path)
expect(diff_file.diff_refs).to eq(position.diff_refs)
end
end
end
describe "#diff_line" do describe "#diff_line" do
it "returns the correct diff line" do it "returns the correct diff line" do
diff_line = subject.diff_line diff_line = subject.diff_line
......
...@@ -31,6 +31,7 @@ describe API::Discussions do ...@@ -31,6 +31,7 @@ describe API::Discussions do
end end
end end
<<<<<<< HEAD
context 'when noteable is an Epic' do context 'when noteable is an Epic' do
let(:group) { create(:group, :public) } let(:group) { create(:group, :public) }
let(:ext_group) { create(:group, :public) } let(:ext_group) { create(:group, :public) }
...@@ -49,6 +50,8 @@ describe API::Discussions do ...@@ -49,6 +50,8 @@ describe API::Discussions do
end end
end end
=======
>>>>>>> upstream/master
context 'when noteable is a Merge Request' do context 'when noteable is a Merge Request' do
let!(:noteable) { create(:merge_request_with_diffs, source_project: project, target_project: project, author: user) } let!(:noteable) { create(:merge_request_with_diffs, source_project: project, target_project: project, author: user) }
let!(:note) { create(:discussion_note_on_merge_request, noteable: noteable, project: project, author: user) } let!(:note) { create(:discussion_note_on_merge_request, noteable: noteable, project: project, author: user) }
......
...@@ -8,7 +8,7 @@ module CommitTrailersSpecHelper ...@@ -8,7 +8,7 @@ module CommitTrailersSpecHelper
expect(wrapper.attribute('data-user').value).to eq user.id.to_s expect(wrapper.attribute('data-user').value).to eq user.id.to_s
end end
def expect_to_have_mailto_link(doc, email:, trailer:) def expect_to_have_mailto_link_with_avatar(doc, email:, trailer:)
wrapper = find_user_wrapper(doc, trailer) wrapper = find_user_wrapper(doc, trailer)
expect_to_have_links_with_url_and_avatar(wrapper, "mailto:#{CGI.escape_html(email)}", email) expect_to_have_links_with_url_and_avatar(wrapper, "mailto:#{CGI.escape_html(email)}", email)
......
shared_examples 'helm commands' do
describe '#generate_script' do
let(:helm_setup) do
<<~EOS
set -eo pipefail
ALPINE_VERSION=$(cat /etc/alpine-release | cut -d '.' -f 1,2)
echo http://mirror.clarkson.edu/alpine/v$ALPINE_VERSION/main >> /etc/apk/repositories
echo http://mirror1.hs-esslingen.de/pub/Mirrors/alpine/v$ALPINE_VERSION/main >> /etc/apk/repositories
apk add -U ca-certificates openssl >/dev/null
wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-amd64.tar.gz | tar zxC /tmp >/dev/null
mv /tmp/linux-amd64/helm /usr/bin/
EOS
end
it 'should return appropriate command' do
expect(subject.generate_script).to eq(helm_setup + commands)
end
end
end
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