Commit a4c65c50 authored by Rémy Coutable's avatar Rémy Coutable

Merge branch 'rc/friday-ce-to-ee' into 'master'

Friday CE upstream

Closes gitlab-ce#27044

See merge request !1136
parents 5d81e994 2621458c
...@@ -286,14 +286,6 @@ request is as follows: ...@@ -286,14 +286,6 @@ request is as follows:
1. For tests that use Capybara or PhantomJS, see this [article on how 1. For tests that use Capybara or PhantomJS, see this [article on how
to write reliable asynchronous tests](https://robots.thoughtbot.com/write-reliable-asynchronous-integration-tests-with-capybara). to write reliable asynchronous tests](https://robots.thoughtbot.com/write-reliable-asynchronous-integration-tests-with-capybara).
The **official merge window** is in the beginning of the month from the 1st to
the 7th day of the month. This is the best time to submit an MR and get
feedback fast. Before this time the GitLab Inc. team is still dealing with work
that is created by the monthly release such as regressions requiring patch
releases. After the 7th it is already getting closer to the release date of the
next version. This means there is less time to fix the issues created by
merging large new features.
Please keep the change in a single MR **as small as possible**. If you want to Please keep the change in a single MR **as small as possible**. If you want to
contribute a large feature think very hard what the minimum viable change is. contribute a large feature think very hard what the minimum viable change is.
Can you split the functionality? Can you only submit the backend/API code? Can Can you split the functionality? Can you only submit the backend/API code? Can
......
/* eslint-disable class-methods-use-this */ /* eslint-disable class-methods-use-this */
//= require lib/utils/url_utility */
(() => { (() => {
const UNFOLD_COUNT = 20; const UNFOLD_COUNT = 20;
...@@ -104,11 +106,11 @@ ...@@ -104,11 +106,11 @@
} }
highlighSelectedLine() { highlighSelectedLine() {
const hash = gl.utils.getLocationHash();
const $diffFiles = $('.diff-file'); const $diffFiles = $('.diff-file');
$diffFiles.find('.hll').removeClass('hll'); $diffFiles.find('.hll').removeClass('hll');
if (window.location.hash !== '') { if (hash) {
const hash = window.location.hash.replace('#', '');
$diffFiles $diffFiles
.find(`tr#${hash}:not(.match) td, td#${hash}, td[data-line-code="${hash}"]`) .find(`tr#${hash}:not(.match) td, td#${hash}, td[data-line-code="${hash}"]`)
.addClass('hll'); .addClass('hll');
......
...@@ -9,6 +9,7 @@ require('../window')(function(w){ ...@@ -9,6 +9,7 @@ require('../window')(function(w){
w.droplabAjax = { w.droplabAjax = {
_loadUrlData: function _loadUrlData(url) { _loadUrlData: function _loadUrlData(url) {
var self = this;
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest; var xhr = new XMLHttpRequest;
xhr.open('GET', url, true); xhr.open('GET', url, true);
...@@ -16,6 +17,7 @@ require('../window')(function(w){ ...@@ -16,6 +17,7 @@ require('../window')(function(w){
if(xhr.readyState === XMLHttpRequest.DONE) { if(xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) { if (xhr.status === 200) {
var data = JSON.parse(xhr.responseText); var data = JSON.parse(xhr.responseText);
self.cache[url] = data;
return resolve(data); return resolve(data);
} else { } else {
return reject([xhr.responseText, xhr.status]); return reject([xhr.responseText, xhr.status]);
...@@ -26,8 +28,21 @@ require('../window')(function(w){ ...@@ -26,8 +28,21 @@ require('../window')(function(w){
}); });
}, },
_loadData: function _loadData(data, config, self) {
if (config.loadingTemplate) {
var dataLoadingTemplate = self.hook.list.list.querySelector('[data-loading-template]');
if (dataLoadingTemplate) {
dataLoadingTemplate.outerHTML = self.listTemplate;
}
}
self.hook.list[config.method].call(self.hook.list, data);
},
init: function init(hook) { init: function init(hook) {
var self = this; var self = this;
self.cache = self.cache || {};
var config = hook.config.droplabAjax; var config = hook.config.droplabAjax;
this.hook = hook; this.hook = hook;
...@@ -50,22 +65,16 @@ require('../window')(function(w){ ...@@ -50,22 +65,16 @@ require('../window')(function(w){
dynamicList.outerHTML = loadingTemplate.outerHTML; dynamicList.outerHTML = loadingTemplate.outerHTML;
} }
this._loadUrlData(config.endpoint) if (self.cache[config.endpoint]) {
.then(function(d) { self._loadData(self.cache[config.endpoint], config, self);
if (config.loadingTemplate) { } else {
var dataLoadingTemplate = self.hook.list.list.querySelector('[data-loading-template]'); this._loadUrlData(config.endpoint)
.then(function(d) {
if (dataLoadingTemplate) { self._loadData(d, config, self);
dataLoadingTemplate.outerHTML = self.listTemplate; }).catch(function(e) {
} throw new droplabAjaxException(e.message || e);
} });
}
if (!self.hook.list.hidden) {
self.hook.list[config.method].call(self.hook.list, d);
}
}).catch(function(e) {
throw new droplabAjaxException(e.message || e);
});
}, },
destroy: function() { destroy: function() {
......
...@@ -72,32 +72,22 @@ require('../window')(function(w){ ...@@ -72,32 +72,22 @@ require('../window')(function(w){
var params = config.params || {}; var params = config.params || {};
params[config.searchKey] = searchValue; params[config.searchKey] = searchValue;
var self = this; var self = this;
this._loadUrlData(config.endpoint + this.buildParams(params)).then(function(data) { self.cache = self.cache || {};
if (config.loadingTemplate && self.hook.list.data === undefined || var url = config.endpoint + this.buildParams(params);
self.hook.list.data.length === 0) { var urlCachedData = self.cache[url];
const dataLoadingTemplate = self.hook.list.list.querySelector('[data-loading-template]');
if (urlCachedData) {
if (dataLoadingTemplate) { self._loadData(urlCachedData, config, self);
dataLoadingTemplate.outerHTML = self.listTemplate; } else {
} this._loadUrlData(url)
} .then(function(data) {
self._loadData(data, config, self);
if (!self.destroyed) { });
var hookListChildren = self.hook.list.list.children; }
var onlyDynamicList = hookListChildren.length === 1 && hookListChildren[0].hasAttribute('data-dynamic');
if (onlyDynamicList && data.length === 0) {
self.hook.list.hide();
}
self.hook.list.setData.call(self.hook.list, data);
}
self.notLoading();
self.hook.list.currentIndex = 0;
});
}, },
_loadUrlData: function _loadUrlData(url) { _loadUrlData: function _loadUrlData(url) {
var self = this;
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest; var xhr = new XMLHttpRequest;
xhr.open('GET', url, true); xhr.open('GET', url, true);
...@@ -105,6 +95,7 @@ require('../window')(function(w){ ...@@ -105,6 +95,7 @@ require('../window')(function(w){
if(xhr.readyState === XMLHttpRequest.DONE) { if(xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) { if (xhr.status === 200) {
var data = JSON.parse(xhr.responseText); var data = JSON.parse(xhr.responseText);
self.cache[url] = data;
return resolve(data); return resolve(data);
} else { } else {
return reject([xhr.responseText, xhr.status]); return reject([xhr.responseText, xhr.status]);
...@@ -115,6 +106,30 @@ require('../window')(function(w){ ...@@ -115,6 +106,30 @@ require('../window')(function(w){
}); });
}, },
_loadData: function _loadData(data, config, self) {
if (config.loadingTemplate && self.hook.list.data === undefined ||
self.hook.list.data.length === 0) {
const dataLoadingTemplate = self.hook.list.list.querySelector('[data-loading-template]');
if (dataLoadingTemplate) {
dataLoadingTemplate.outerHTML = self.listTemplate;
}
}
if (!self.destroyed) {
var hookListChildren = self.hook.list.list.children;
var onlyDynamicList = hookListChildren.length === 1 && hookListChildren[0].hasAttribute('data-dynamic');
if (onlyDynamicList && data.length === 0) {
self.hook.list.hide();
}
self.hook.list.setData.call(self.hook.list, data);
}
self.notLoading();
self.hook.list.currentIndex = 0;
},
buildParams: function(params) { buildParams: function(params) {
if (!params) return ''; if (!params) return '';
var paramsArray = Object.keys(params).map(function(param) { var paramsArray = Object.keys(params).map(function(param) {
......
...@@ -26,6 +26,15 @@ ...@@ -26,6 +26,15 @@
symbol: '', symbol: '',
}]; }];
const alternativeTokenKeys = [{
key: 'label',
type: 'string',
param: 'name',
symbol: '~',
}];
const tokenKeysWithAlternative = tokenKeys.concat(alternativeTokenKeys);
const conditions = [{ const conditions = [{
url: 'assignee_id=0', url: 'assignee_id=0',
tokenKey: 'assignee', tokenKey: 'assignee',
...@@ -57,6 +66,10 @@ ...@@ -57,6 +66,10 @@
return tokenKeys; return tokenKeys;
} }
static getAlternatives() {
return alternativeTokenKeys;
}
static getConditions() { static getConditions() {
return conditions; return conditions;
} }
...@@ -70,7 +83,7 @@ ...@@ -70,7 +83,7 @@
} }
static searchByKeyParam(keyParam) { static searchByKeyParam(keyParam) {
return tokenKeys.find((tokenKey) => { return tokenKeysWithAlternative.find((tokenKey) => {
let tokenKeyParam = tokenKey.key; let tokenKeyParam = tokenKey.key;
if (tokenKey.param) { if (tokenKey.param) {
......
...@@ -74,8 +74,9 @@ ...@@ -74,8 +74,9 @@
// If not done this way, the line number anchor will sometimes keep its // If not done this way, the line number anchor will sometimes keep its
// active state even when the event is cancelled, resulting in an ugly border // active state even when the event is cancelled, resulting in an ugly border
// around the link and/or a persisted underline text decoration. // around the link and/or a persisted underline text decoration.
return $('#blob-content-holder').on('click', 'a[data-line-number]', function(event) { $('#blob-content-holder').on('click', 'a[data-line-number]', function(event) {
return event.preventDefault(); event.preventDefault();
event.stopPropagation();
}); });
}; };
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
} }
onSubmitForm(e) { onSubmitForm(e) {
e.preventDefault();
return this.saveForm(); return this.saveForm();
} }
......
...@@ -37,6 +37,8 @@ ...@@ -37,6 +37,8 @@
display: inline-block; display: inline-block;
margin-left: 4px; margin-left: 4px;
margin-bottom: 2px; margin-bottom: 2px;
flex-shrink: 0;
-webkit-flex-shrink: 0;
&.s16 { margin-right: 4px; } &.s16 { margin-right: 4px; }
&.s24 { margin-right: 4px; } &.s24 { margin-right: 4px; }
......
...@@ -125,7 +125,8 @@ ...@@ -125,7 +125,8 @@
top: 100%; top: 100%;
left: 0; left: 0;
z-index: 9; z-index: 9;
width: 240px; max-width: 280px;
min-width: 240px;
margin-top: 2px; margin-top: 2px;
margin-bottom: 0; margin-bottom: 0;
font-size: 14px; font-size: 14px;
......
...@@ -132,6 +132,11 @@ ...@@ -132,6 +132,11 @@
display: flex; display: flex;
-webkit-flex-direction: column; -webkit-flex-direction: column;
flex-direction: column; flex-direction: column;
&> span {
white-space: normal;
word-break: break-all;
}
} }
} }
...@@ -141,10 +146,6 @@ ...@@ -141,10 +146,6 @@
} }
} }
.hint-dropdown {
width: 250px;
}
.filter-dropdown-loading { .filter-dropdown-loading {
padding: 8px 16px; padding: 8px 16px;
} }
...@@ -214,9 +214,9 @@ ...@@ -214,9 +214,9 @@
&:not(:last-child) { &:not(:last-child) {
&::after { &::after {
content: ''; content: '';
width: 8px; width: 7px;
position: absolute; position: absolute;
right: -8px; right: -7px;
top: 10px; top: 10px;
border-bottom: 2px solid $border-color; border-bottom: 2px solid $border-color;
} }
......
...@@ -22,6 +22,7 @@ class Explore::ProjectsController < Explore::ApplicationController ...@@ -22,6 +22,7 @@ class Explore::ProjectsController < Explore::ApplicationController
def trending def trending
@projects = filter_projects(Project.trending) @projects = filter_projects(Project.trending)
@projects = @projects.sort(@sort = params[:sort])
@projects = @projects.page(params[:page]) @projects = @projects.page(params[:page])
respond_to do |format| respond_to do |format|
......
...@@ -94,7 +94,7 @@ class Projects::BuildsController < Projects::ApplicationController ...@@ -94,7 +94,7 @@ class Projects::BuildsController < Projects::ApplicationController
private private
def build def build
@build ||= project.builds.find_by!(id: params[:id]).present(user: current_user) @build ||= project.builds.find_by!(id: params[:id]).present(current_user: current_user)
end end
def build_path(build) def build_path(build)
......
...@@ -33,12 +33,6 @@ class Projects::RefsController < Projects::ApplicationController ...@@ -33,12 +33,6 @@ class Projects::RefsController < Projects::ApplicationController
redirect_to new_path redirect_to new_path
end end
format.js do
@ref = params[:ref]
define_tree_vars
tree
render "tree"
end
end end
end end
......
...@@ -1337,7 +1337,18 @@ class Repository ...@@ -1337,7 +1337,18 @@ class Repository
end end
def tags_sorted_by_committed_date def tags_sorted_by_committed_date
tags.sort_by { |tag| tag.dereferenced_target.committed_date } tags.sort_by do |tag|
# Annotated tags can point to any object (e.g. a blob), but generally
# tags point to a commit. If we don't have a commit, then just default
# to putting the tag at the end of the list.
target = tag.dereferenced_target
if target
target.committed_date
else
Time.now
end
end
end end
def keep_around_ref_name(sha) def keep_around_ref_name(sha)
......
...@@ -113,7 +113,7 @@ detects the presenter based on the presented subject's class. ...@@ -113,7 +113,7 @@ detects the presenter based on the presented subject's class.
class Projects::LabelsController < Projects::ApplicationController class Projects::LabelsController < Projects::ApplicationController
def edit def edit
@label = Gitlab::View::Presenter::Factory @label = Gitlab::View::Presenter::Factory
.new(@label, user: current_user) .new(@label, current_user: current_user)
.fabricate! .fabricate!
end end
end end
...@@ -132,7 +132,7 @@ and then in the controller: ...@@ -132,7 +132,7 @@ and then in the controller:
```ruby ```ruby
class Projects::LabelsController < Projects::ApplicationController class Projects::LabelsController < Projects::ApplicationController
def edit def edit
@label = @label.present(user: current_user) @label = @label.present(current_user: current_user)
end end
end end
``` ```
...@@ -147,7 +147,7 @@ end ...@@ -147,7 +147,7 @@ end
You can also present the model in the view: You can also present the model in the view:
```ruby ```ruby
- label = @label.present(current_user) - label = @label.present(current_user: current_user)
%div{ class: label.text_color } %div{ class: label.text_color }
= render partial: label, label: label = render partial: label, label: label
......
...@@ -33,6 +33,8 @@ module Projects ...@@ -33,6 +33,8 @@ module Projects
if project.update_attributes(params) if project.update_attributes(params)
if project.previous_changes.include?('path') if project.previous_changes.include?('path')
project.rename_repo project.rename_repo
else
system_hook_service.execute_hooks_for(project, :update)
end end
success success
......
...@@ -17,6 +17,13 @@ ...@@ -17,6 +17,13 @@
%pre.dark %pre.dark
:preserve :preserve
gem install gollum gem install gollum
%p
It is recommended to install
%code github-markdown
so that GFM features render locally:
%pre.dark
:preserve
gem install github-markdown
%h3 Clone your wiki %h3 Clone your wiki
%pre.dark %pre.dark
......
...@@ -47,10 +47,6 @@ ...@@ -47,10 +47,6 @@
%li.filter-dropdown-item{ 'data-value' => 'none' } %li.filter-dropdown-item{ 'data-value' => 'none' }
%button.btn.btn-link %button.btn.btn-link
No Assignee No Assignee
- if current_user
%li.filter-dropdown-item{ 'data-value' => current_user.to_reference }
%button.btn.btn-link
Assigned to me
%li.divider %li.divider
%ul.filter-dropdown{ 'data-dynamic' => true, 'data-dropdown' => true } %ul.filter-dropdown{ 'data-dynamic' => true, 'data-dropdown' => true }
%li.filter-dropdown-item %li.filter-dropdown-item
......
---
title: Add caching of droplab ajax requests
merge_request: 8725
author:
---
title: Fix /explore sorting
merge_request:
author:
---
title: fixed small mini pipeline graph line glitch
merge_request: 8804
author:
---
title: Add system hook for when a project is updated (other than rename/transfer)
merge_request: 5711
author: Tommy Beadle
---
title: Make notification_service spec DRYer by making test reusable
merge_request:
author: YarNayar
---
title: Remove unused js response from refs controller
merge_request:
author:
---
title: Revert 3f17f29a
merge_request: 8785
author:
---
title: Fix Error 500 when repositories contain annotated tags pointing to blobs
merge_request:
author:
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
# #
production: production:
adapter: mysql2 adapter: mysql2
encoding: utf8mb4 encoding: utf8
collation: utf8mb4_general_ci collation: utf8_general_ci
reconnect: false reconnect: false
database: gitlabhq_production database: gitlabhq_production
pool: 10 pool: 10
...@@ -18,8 +18,8 @@ production: ...@@ -18,8 +18,8 @@ production:
# #
development: development:
adapter: mysql2 adapter: mysql2
encoding: utf8mb4 encoding: utf8
collation: utf8mb4_general_ci collation: utf8_general_ci
reconnect: false reconnect: false
database: gitlabhq_development database: gitlabhq_development
pool: 5 pool: 5
......
...@@ -79,11 +79,15 @@ main: # 'main' is the GitLab 'provider ID' of this LDAP server ...@@ -79,11 +79,15 @@ main: # 'main' is the GitLab 'provider ID' of this LDAP server
# #
# Example: 'Paris' or 'Acme, Ltd.' # Example: 'Paris' or 'Acme, Ltd.'
label: 'LDAP' label: 'LDAP'
# Example: 'ldap.mydomain.com'
host: '_your_ldap_server' host: '_your_ldap_server'
# This port is an example, it is sometimes different but it is always an integer and not a string
port: 389 port: 389
uid: 'sAMAccountName' uid: 'sAMAccountName'
method: 'plain' # "tls" or "ssl" or "plain" method: 'plain' # "tls" or "ssl" or "plain"
# Examples: 'america\\momo' or 'CN=Gitlab Git,CN=Users,DC=mydomain,DC=com'
bind_dn: '_the_full_dn_of_the_user_you_will_bind_with' bind_dn: '_the_full_dn_of_the_user_you_will_bind_with'
password: '_the_password_of_the_bind_user' password: '_the_password_of_the_bind_user'
...@@ -115,7 +119,7 @@ main: # 'main' is the GitLab 'provider ID' of this LDAP server ...@@ -115,7 +119,7 @@ main: # 'main' is the GitLab 'provider ID' of this LDAP server
# Base where we can search for users # Base where we can search for users
# #
# Ex. ou=People,dc=gitlab,dc=example # Ex. 'ou=People,dc=gitlab,dc=example' or 'DC=mydomain,DC=com'
# #
base: '' base: ''
...@@ -126,6 +130,9 @@ main: # 'main' is the GitLab 'provider ID' of this LDAP server ...@@ -126,6 +130,9 @@ main: # 'main' is the GitLab 'provider ID' of this LDAP server
# #
# Note: GitLab does not support omniauth-ldap's custom filter syntax. # Note: GitLab does not support omniauth-ldap's custom filter syntax.
# #
# Below an example for get only specific users
# Example: '(&(objectclass=user)(|(samaccountname=momo)(samaccountname=toto)))'
#
user_filter: '' user_filter: ''
# LDAP attributes that GitLab will use to create an account for the LDAP user. # LDAP attributes that GitLab will use to create an account for the LDAP user.
......
...@@ -13,12 +13,12 @@ checks failed you can see their output on the admin log page under ...@@ -13,12 +13,12 @@ checks failed you can see their output on the admin log page under
## Periodic checks ## Periodic checks
GitLab periodically runs a repository check on all project repositories and When enabled, GitLab periodically runs a repository check on all project
wiki repositories in order to detect data corruption problems. A repositories and wiki repositories in order to detect data corruption problems.
project will be checked no more than once per week. If any projects A project will be checked no more than once per month. If any projects
fail their repository checks all GitLab administrators will receive an email fail their repository checks all GitLab administrators will receive an email
notification of the situation. This notification is sent out no more notification of the situation. This notification is sent out once a week on
than once a day. Sunday, by default.
## Disabling periodic checks ## Disabling periodic checks
......
...@@ -14,6 +14,12 @@ Apart from those, here is an collection of tutorials and guides on setting up yo ...@@ -14,6 +14,12 @@ Apart from those, here is an collection of tutorials and guides on setting up yo
- [Test a Phoenix application](test-phoenix-application.md) - [Test a Phoenix application](test-phoenix-application.md)
- [Using `dpl` as deployment tool](deployment/README.md) - [Using `dpl` as deployment tool](deployment/README.md)
- [Example project that shows how to use Review Apps](https://gitlab.com/gitlab-examples/review-apps-nginx/) - [Example project that shows how to use Review Apps](https://gitlab.com/gitlab-examples/review-apps-nginx/)
- [Run PHP Composer & NPM scripts then deploy them to a staging server](deployment/composer-npm-deploy.md)
- Help your favorite programming language and GitLab by sending a merge request
with a guide for that language.
## Outside the documentation
- [Blog post about using GitLab CI for iOS projects](https://about.gitlab.com/2016/03/10/setting-up-gitlab-ci-for-ios-projects/) - [Blog post about using GitLab CI for iOS projects](https://about.gitlab.com/2016/03/10/setting-up-gitlab-ci-for-ios-projects/)
- [Repositories with examples for various languages](https://gitlab.com/groups/gitlab-examples) - [Repositories with examples for various languages](https://gitlab.com/groups/gitlab-examples)
- [The .gitlab-ci.yml file for GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab-ci.yml) - [The .gitlab-ci.yml file for GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab-ci.yml)
......
## Running Composer and NPM scripts with deployment via SCP
This guide covers the building dependencies of a PHP project while compiling assets via an NPM script.
While is possible to create your own image with custom PHP and Node JS versions, for brevity, we will use an existing [Docker image](https://hub.docker.com/r/tetraweb/php/) that contains both PHP and NodeJS installed.
```yaml
image: tetraweb/php
```
The next step is to install zip/unzip packages and make composer available. We will place these in the `before_script` section:
```yaml
before_script:
- apt-get update
- apt-get install zip unzip
- php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
- php composer-setup.php
- php -r "unlink('composer-setup.php');"
```
This will make sure we have all requirements ready. Next, we want to run `composer update` to fetch all PHP dependencies and `npm install` to load node packages, then run the `npm` script. We need to append them into `before_script` section:
```yaml
before_script:
# ...
- php composer.phar update
- npm install
- npm run deploy
```
In this particular case, the `npm deploy` script is a Gulp script that does the following:
1. Compile CSS & JS
2. Create sprites
3. Copy various assets (images, fonts) around
4. Replace some strings
All these operations will put all files into a `build` folder, which is ready to be deployed to a live server.
### How to transfer files to a live server?
You have multiple options: rsync, scp, sftp and so on. For now, we will use scp.
To make this work, you need to add a GitLab Secret Variable (accessible on _gitlab.example/your-project-name/variables_). That variable will be called `STAGING_PRIVATE_KEY` and it's the **private** ssh key of your server.
#### Security tip
Create a user that has access **only** to the folder that needs to be updated!
After you create that variable, you need to make sure that key will be added to the docker container on run:
```yaml
before_script:
# - ....
- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
- mkdir -p ~/.ssh
- eval $(ssh-agent -s)
- '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
```
In order, this means that:
1. We check if the `ssh-agent` is available and we install it if it's not;
2. We create the `~/.ssh` folder;
3. We make sure we're running bash;
4. We disable host checking (we don't ask for user accept when we first connect to a server; and since every build will equal a first connect, we kind of need this)
And this is basically all you need in the `before_script` section.
## How to deploy things?
As we stated above, we need to deploy the `build` folder from the docker image to our server. To do so, we create a new job:
```yaml
stage_deploy:
artifacts:
paths:
- build/
only:
- dev
script:
- ssh-add <(echo "$STAGING_PRIVATE_KEY")
- ssh -p22 server_user@server_host "mkdir htdocs/wp-content/themes/_tmp"
- scp -P22 -r build/* server_user@server_host:htdocs/wp-content/themes/_tmp
- ssh -p22 server_user@server_host "mv htdocs/wp-content/themes/live htdocs/wp-content/themes/_old && mv htdocs/wp-content/themes/_tmp htdocs/wp-content/themes/live"
- ssh -p22 server_user@server_host "rm -rf htdocs/wp-content/themes/_old"
```
### What's going on here?
1. `only:dev` means that this build will run only when something is pushed to the `dev` branch. You can remove this block completely and have everything be ran on every push (but probably this is something you don't want)
2. `ssh-add ...` we will add that private key you added on the web UI to the docker container
3. We will connect via `ssh` and create a new `_tmp` folder
4. We will connect via `scp` and upload the `build` folder (which was generated by a `npm` script) to our previously created `_tmp` folder
5. We will connect again to `ssh` and move the `live` folder to an `_old` folder, then move `_tmp` to `live`.
6. We connect to ssh and remove the `_old` folder
What's the deal with the artifacts? We just tell GitLab CI to keep the `build` directory (later on, you can download that as needed).
#### Why we do it this way?
If you're using this only for stage server, you could do this in two steps:
```yaml
- ssh -p22 server_user@server_host "rm -rf htdocs/wp-content/themes/live/*"
- scp -P22 -r build/* server_user@server_host:htdocs/wp-content/themes/live
```
The problem is that there will be a small period of time when you won't have the app on your server.
So we use so many steps because we want to make sure that at any given time we have a functional app in place.
## Where to go next?
Since this was a WordPress project, I gave real life code snippets. Some ideas you can pursuit:
- Having a slightly different script for `master` branch will allow you to deploy to a production server from that branch and to a stage server from any other branches;
- Instead of pushing it live, you can push it to WordPress official repo (with creating a SVN commit & stuff);
- You could generate i18n text domains on the fly.
---
Our final `.gitlab-ci.yml` will look like this:
```yaml
image: tetraweb/php
before_script:
- apt-get update
- apt-get install zip unzip
- php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
- php composer-setup.php
- php -r "unlink('composer-setup.php');"
- php composer.phar update
- npm install
- npm run deploy
- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
- mkdir -p ~/.ssh
- eval $(ssh-agent -s)
- '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
stage_deploy:
artifacts:
paths:
- build/
only:
- dev
script:
- ssh-add <(echo "$STAGING_PRIVATE_KEY")
- ssh -p22 server_user@server_host "mkdir htdocs/wp-content/themes/_tmp"
- scp -P22 -r build/* server_user@server_host:htdocs/wp-content/themes/_tmp
- ssh -p22 server_user@server_host "mv htdocs/wp-content/themes/live htdocs/wp-content/themes/_old && mv htdocs/wp-content/themes/_tmp htdocs/wp-content/themes/live"
- ssh -p22 server_user@server_host "rm -rf htdocs/wp-content/themes/_old"
```
\ No newline at end of file
...@@ -86,7 +86,7 @@ used for time of the build. The configuration of this feature is covered in ...@@ -86,7 +86,7 @@ used for time of the build. The configuration of this feature is covered in
### before_script ### before_script
`before_script` is used to define the command that should be run before all `before_script` is used to define the command that should be run before all
builds, including deploy builds. This can be an array or a multi-line string. builds, including deploy builds, but after the restoration of artifacts. This can be an array or a multi-line string.
### after_script ### after_script
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
- [Frontend guidelines](frontend.md) - [Frontend guidelines](frontend.md)
- [SQL guidelines](sql.md) for working with SQL queries - [SQL guidelines](sql.md) for working with SQL queries
- [Sidekiq guidelines](sidekiq_style_guide.md) for working with Sidekiq workers - [Sidekiq guidelines](sidekiq_style_guide.md) for working with Sidekiq workers
- [`Gemfile` guidelines](gemfile.md)
## Process ## Process
......
# `Gemfile` guidelines
When adding a new entry to `Gemfile` or upgrading an existing dependency pay
attention to the following rules.
## No gems fetched from git repositories
We do not allow gems that are fetched from git repositories. All gems have
to be available in the RubyGems index. We want to minimize external build
dependencies and build times.
## License compliance
Refer to [licensing guidelines](licensing.md) for ensuring license compliance.
# How to add an image # How to add an image
The following are the steps to add images to your repository in Using your standard tool for copying files (e.g. Finder in Mac OS, or Explorer
GitLab: in Windows, or...), put the image file into the GitLab project. You can find the
project as a regular folder in your files.
Find the image that you’d like to add. Go to your [shell](command-line-commands.md), and move into the folder of your
Gitlab project. This usually means running the following command until you get
to the desired destination:
In your computer files, find the GitLab project to which you'd like to add the image
(you'll find it as a regular file). Click on every file until you find exactly where you'd
like to add the image. There, paste the image.
Go to your [shell](command-line-commands.md), and add the following commands:
Add this command for every directory that you'd like to open:
``` ```
cd NAME-OF-FILE-YOU'D-LIKE-TO-OPEN cd NAME-OF-FOLDER-YOU'D-LIKE-TO-OPEN
``` ```
Create a new branch: Check if your image is actually present in the directory (if you are in Windows,
``` use `dir` instead):
git checkout -b NAME-OF-BRANCH
```
Check if your image was correctly added to the directory:
``` ```
ls ls
``` ```
You should see the name of the image in the list shown. You should see the name of the image in the list shown.
Move up the hierarchy through directories: Check the status:
```
cd ../
```
Check the status and you should see your image’s name in red:
``` ```
git status git status
``` ```
Add your changes: Your image's name should appear in red, so `git` took notice of it! Now add it
to the repository:
``` ```
git add NAME-OF-YOUR-IMAGE git add NAME-OF-YOUR-IMAGE
``` ```
Check the status and you should see your image’s name in green: Check the status again, your image's name should have turned green:
``` ```
git status git status
``` ```
Add the commit: Commit:
``` ```
git commit -m “DESCRIBE COMMIT IN A FEW WORDS” git commit -m "DESCRIBE COMMIT IN A FEW WORDS"
``` ```
Now you can push (send) your changes (in the branch NAME-OF-BRANCH) to GitLab (the git remote named 'origin'): Now you can push (send) your changes (in the branch NAME-OF-BRANCH) to GitLab
(the git remote named 'origin'):
``` ```
git push origin NAME-OF-BRANCH git push origin NAME-OF-BRANCH
``` ```
Your image will be added to your branch in your repository in GitLab. Create a [Merge Request](add-merge-request.md) Your image will be added to your branch in your repository in GitLab.
to integrate your changes to your project.
This diff is collapsed.
# System hooks # System hooks
Your GitLab instance can perform HTTP POST requests on the following events: `project_create`, `project_destroy`, `project_rename`, `project_transfer`, `user_add_to_team`, `user_remove_from_team`, `user_create`, `user_destroy`, `key_create`, `key_destroy`, `group_create`, `group_destroy`, `user_add_to_group` and `user_remove_from_group`. Your GitLab instance can perform HTTP POST requests on the following events: `project_create`, `project_destroy`, `project_rename`, `project_transfer`, `project_update`, `user_add_to_team`, `user_remove_from_team`, `user_create`, `user_destroy`, `key_create`, `key_destroy`, `group_create`, `group_destroy`, `user_add_to_group` and `user_remove_from_group`.
System hooks can be used, e.g. for logging or changing information in a LDAP server. System hooks can be used, e.g. for logging or changing information in a LDAP server.
...@@ -88,6 +88,23 @@ X-Gitlab-Event: System Hook ...@@ -88,6 +88,23 @@ X-Gitlab-Event: System Hook
} }
``` ```
**Project updated:**
```json
{
"created_at": "2012-07-21T07:30:54Z",
"updated_at": "2012-07-21T07:38:22Z",
"event_name": "project_update",
"name": "StoreCloud",
"owner_email": "johnsmith@gmail.com",
"owner_name": "John Smith",
"path": "storecloud",
"path_with_namespace": "jsmith/storecloud",
"project_id": 74,
"project_visibility": "private",
}
```
**New Team Member:** **New Team Member:**
```json ```json
......
...@@ -97,6 +97,8 @@ sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production ...@@ -97,6 +97,8 @@ sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS_ENV=production sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS_ENV=production
``` ```
**MySQL installations**: Run through the `MySQL strings limits` and `Tables and data conversion to utf8mb4` [tasks](../install/database_mysql.md).
### 6. Update gitlab-workhorse ### 6. Update gitlab-workhorse
Install and compile gitlab-workhorse. This requires Install and compile gitlab-workhorse. This requires
......
...@@ -140,75 +140,77 @@ into the password field. ...@@ -140,75 +140,77 @@ into the password field.
## Recovery options ## Recovery options
If you lose your code generation device (such as your mobile phone) and you need To disable two-factor authentication on your account (for example, if you
to disable two-factor authentication on your account, you have several options. have lost your code generation device) you can:
* [Use a saved recovery code](#use-a-saved-recovery-code)
* [Generate new recovery codes using SSH](#generate-new-recovery-codes-using-SSH)
* [Ask a GitLab administrator to disable two-factor authentication on your account](#ask-a-gitlab-administrator-to-disable-two-factor-authentication-on-your-account)
### Use a saved recovery code ### Use a saved recovery code
When you enabled two-factor authentication for your account, a series of Enabling two-factor authentication for your account generated several recovery
recovery codes were generated. If you saved those codes somewhere safe, you codes. If you saved these codes, you can use one of them to sign in.
may use one to sign in.
First, enter your username/email and password on the GitLab sign in page. When To use a recovery code, enter your username/email and password on the GitLab
prompted for a two-factor code, enter one of the recovery codes you saved sign-in page. When prompted for a two-factor code, enter the recovery code.
previously.
> **Note:** Once a particular recovery code has been used, it cannot be used again. > **Note:** Once you use a recovery code, you cannot re-use it. You can still
You may still use the other saved recovery codes at a later time. use the other recovery codes you saved.
### Generate new recovery codes using SSH ### Generate new recovery codes using SSH
It's not uncommon for users to forget to save the recovery codes when enabling Users often forget to save their recovery codes when enabling two-factor
two-factor authentication. If you have an SSH key added to your GitLab account, authentication. If an SSH key is added to your GitLab account, you can generate
you can generate a new set of recovery codes using SSH. a new set of recovery codes with SSH.
Run `ssh git@gitlab.example.com 2fa_recovery_codes`. You will be prompted to 1. Run `ssh git@gitlab.example.com 2fa_recovery_codes`.
confirm that you wish to generate new codes. If you choose to continue, any 2. You are prompted to confirm that you want to generate new codes. Continuing this process invalidates previously saved codes.
previously saved codes will be invalidated. ```
bash
```bash $ ssh git@gitlab.example.com 2fa_recovery_codes
$ ssh git@gitlab.example.com 2fa_recovery_codes Are you sure you want to generate new two-factor recovery codes?
Are you sure you want to generate new two-factor recovery codes? Any existing recovery codes you saved will be invalidated. (yes/no)
Any existing recovery codes you saved will be invalidated. (yes/no)
yes yes
Your two-factor authentication recovery codes are: Your two-factor authentication recovery codes are:
119135e5a3ebce8e 119135e5a3ebce8e
11f6v2a498810dcd 11f6v2a498810dcd
3924c7ab2089c902 3924c7ab2089c902
e79a3398bfe4f224 e79a3398bfe4f224
34bd7b74adbc8861 34bd7b74adbc8861
f061691d5107df1a f061691d5107df1a
169bf32a18e63e7f 169bf32a18e63e7f
b510e7422e81c947 b510e7422e81c947
20dbed24c5e74663 20dbed24c5e74663
df9d3b9403b9c9f0 df9d3b9403b9c9f0
During sign in, use one of the codes above when prompted for During sign in, use one of the codes above when prompted for your
your two-factor code. Then, visit your Profile Settings and add two-factor code. Then, visit your Profile Settings and add a new device
a new device so you do not lose access to your account again. so you do not lose access to your account again.
``` ```
3. Go to the GitLab sign-in page and enter your username/email and password. When prompted for a two-factor code, enter one of the recovery codes obtained
Next, go to the GitLab sign in page and enter your username/email and password. from the command-line output.
When prompted for a two-factor code, enter one of the recovery codes obtained
from the command line output. > **Note:** After signing in, visit your **Profile Settings -> Account** immediately to set up two-factor authentication with a new
device.
> **Note:** After signing in, you should immediately visit your **Profile Settings
-> Account** to set up two-factor authentication with a new device. ### Ask a GitLab administrator to disable two-factor authentication on your account
### Ask a GitLab administrator to disable two-factor on your account If you cannot use a saved recovery code or generate new recovery codes, ask a
GitLab global administrator to disable two-factor authentication for your
If the above two methods are not possible, you may ask a GitLab global account. This will temporarily leave your account in a less secure state.
administrator to disable two-factor authentication for your account. Please Sign in and re-enable two-factor authentication as soon as possible.
be aware that this will temporarily leave your account in a less secure state.
You should sign in and re-enable two-factor authentication as soon as possible
after the administrator disables it.
## Note to GitLab administrators ## Note to GitLab administrators
You need to take special care to that 2FA keeps working after - You need to take special care to that 2FA keeps working after
[restoring a GitLab backup](../../../raketasks/backup_restore.md). [restoring a GitLab backup](../raketasks/backup_restore.md).
- To ensure 2FA authorizes correctly with TOTP server, you may want to ensure
your GitLab server's time is synchronized via a service like NTP. Otherwise,
you may have cases where authorization always fails because of time differences.
[Google Authenticator]: https://support.google.com/accounts/answer/1066447?hl=en [Google Authenticator]: https://support.google.com/accounts/answer/1066447?hl=en
[FreeOTP]: https://fedorahosted.org/freeotp/ [FreeOTP]: https://fedorahosted.org/freeotp/
......
...@@ -42,6 +42,7 @@ module Gitlab ...@@ -42,6 +42,7 @@ module Gitlab
end end
chunks.join.lines.last(max_lines).join chunks.join.lines.last(max_lines).join
.force_encoding(Encoding.default_external)
end end
end end
end end
......
module Gitlab module Gitlab
module View module View
module Presenter module Presenter
CannotOverrideMethodError = Class.new(StandardError)
module Base module Base
extend ActiveSupport::Concern extend ActiveSupport::Concern
......
...@@ -8,6 +8,10 @@ module Gitlab ...@@ -8,6 +8,10 @@ module Gitlab
@subject = subject @subject = subject
attributes.each do |key, value| attributes.each do |key, value|
if subject.respond_to?(key)
raise CannotOverrideMethodError.new("#{subject} already respond to #{key}!")
end
define_singleton_method(key) { value } define_singleton_method(key) { value }
end end
......
require 'spec_helper'
describe Explore::ProjectsController do
let(:user) { create(:user) }
let(:visibility) { :public }
describe 'GET #trending' do
let!(:project_1) { create(:project, visibility, ci_id: 1) }
let!(:project_2) { create(:project, visibility, ci_id: 2) }
let!(:trending_project_1) { create(:trending_project, project: project_1) }
let!(:trending_project_2) { create(:trending_project, project: project_2) }
before do
sign_in(user)
end
context 'sorting by update date' do
it 'sorts by last updated' do
get :trending, sort: 'updated_desc'
expect(assigns(:projects)).to eq [project_2, project_1]
end
it 'sorts by oldest updated' do
get :trending, sort: 'updated_asc'
expect(assigns(:projects)).to eq [project_1, project_2]
end
end
end
end
FactoryGirl.define do
# TrendingProject
factory :trending_project, class: 'TrendingProject' do
project
end
end
...@@ -43,14 +43,6 @@ describe 'Dropdown assignee', js: true, feature: true do ...@@ -43,14 +43,6 @@ describe 'Dropdown assignee', js: true, feature: true do
expect(page).to have_css(js_dropdown_assignee, visible: true) expect(page).to have_css(js_dropdown_assignee, visible: true)
end end
it 'shows assigned to me link' do
filtered_search.set('assignee:')
page.within js_dropdown_assignee do
expect(page).to have_content('Assigned to me')
end
end
it 'closes when the search bar is unfocused' do it 'closes when the search bar is unfocused' do
find('body').click() find('body').click()
...@@ -129,14 +121,6 @@ describe 'Dropdown assignee', js: true, feature: true do ...@@ -129,14 +121,6 @@ describe 'Dropdown assignee', js: true, feature: true do
filtered_search.set('assignee:') filtered_search.set('assignee:')
end end
it 'filters by current user' do
page.within js_dropdown_assignee do
click_button 'Assigned to me'
end
expect(filtered_search.value).to eq("assignee:#{user.to_reference} ")
end
it 'fills in the assignee username when the assignee has not been filtered' do it 'fills in the assignee username when the assignee has not been filtered' do
click_assignee(user_jacob.name) click_assignee(user_jacob.name)
...@@ -185,4 +169,22 @@ describe 'Dropdown assignee', js: true, feature: true do ...@@ -185,4 +169,22 @@ describe 'Dropdown assignee', js: true, feature: true do
expect(page).to have_css(js_dropdown_assignee, visible: true) expect(page).to have_css(js_dropdown_assignee, visible: true)
end end
end end
describe 'caching requests' do
it 'caches requests after the first load' do
filtered_search.set('assignee')
send_keys_to_filtered_search(':')
initial_size = dropdown_assignee_size
expect(initial_size).to be > 0
new_user = create(:user)
project.team << [new_user, :master]
find('.filtered-search-input-container .clear-search').click
filtered_search.set('assignee')
send_keys_to_filtered_search(':')
expect(dropdown_assignee_size).to eq(initial_size)
end
end
end end
...@@ -157,4 +157,22 @@ describe 'Dropdown author', js: true, feature: true do ...@@ -157,4 +157,22 @@ describe 'Dropdown author', js: true, feature: true do
expect(page).to have_css(js_dropdown_author, visible: true) expect(page).to have_css(js_dropdown_author, visible: true)
end end
end end
describe 'caching requests' do
it 'caches requests after the first load' do
filtered_search.set('author')
send_keys_to_filtered_search(':')
initial_size = dropdown_author_size
expect(initial_size).to be > 0
new_user = create(:user)
project.team << [new_user, :master]
find('.filtered-search-input-container .clear-search').click
filtered_search.set('author')
send_keys_to_filtered_search(':')
expect(dropdown_author_size).to eq(initial_size)
end
end
end end
...@@ -249,4 +249,21 @@ describe 'Dropdown label', js: true, feature: true do ...@@ -249,4 +249,21 @@ describe 'Dropdown label', js: true, feature: true do
expect(page).to have_css(js_dropdown_label, visible: true) expect(page).to have_css(js_dropdown_label, visible: true)
end end
end end
describe 'caching requests' do
it 'caches requests after the first load' do
filtered_search.set('label')
send_keys_to_filtered_search(':')
initial_size = dropdown_label_size
expect(initial_size).to be > 0
create(:label, project: project)
find('.filtered-search-input-container .clear-search').click
filtered_search.set('label')
send_keys_to_filtered_search(':')
expect(dropdown_label_size).to eq(initial_size)
end
end
end end
...@@ -219,4 +219,21 @@ describe 'Dropdown milestone', js: true, feature: true do ...@@ -219,4 +219,21 @@ describe 'Dropdown milestone', js: true, feature: true do
expect(page).to have_css(js_dropdown_milestone, visible: true) expect(page).to have_css(js_dropdown_milestone, visible: true)
end end
end end
describe 'caching requests' do
it 'caches requests after the first load' do
filtered_search.set('milestone')
send_keys_to_filtered_search(':')
initial_size = dropdown_milestone_size
expect(initial_size).to be > 0
create(:milestone, project: project)
find('.filtered-search-input-container .clear-search').click
filtered_search.set('milestone')
send_keys_to_filtered_search(':')
expect(dropdown_milestone_size).to eq(initial_size)
end
end
end end
...@@ -72,6 +72,12 @@ ...@@ -72,6 +72,12 @@
const result = gl.FilteredSearchTokenKeys.searchByKeyParam(`${tokenKeys[0].key}_${tokenKeys[0].param}`); const result = gl.FilteredSearchTokenKeys.searchByKeyParam(`${tokenKeys[0].key}_${tokenKeys[0].param}`);
expect(result).toEqual(tokenKeys[0]); expect(result).toEqual(tokenKeys[0]);
}); });
it('should return alternative tokenKey when found by key param', () => {
const tokenKeys = gl.FilteredSearchTokenKeys.getAlternatives();
const result = gl.FilteredSearchTokenKeys.searchByKeyParam(`${tokenKeys[0].key}_${tokenKeys[0].param}`);
expect(result).toEqual(tokenKeys[0]);
});
}); });
describe('searchByConditionUrl', () => { describe('searchByConditionUrl', () => {
......
...@@ -11,13 +11,25 @@ describe Gitlab::Ci::TraceReader do ...@@ -11,13 +11,25 @@ describe Gitlab::Ci::TraceReader do
last_lines = random_lines last_lines = random_lines
expected = lines.last(last_lines).join expected = lines.last(last_lines).join
result = subject.read(last_lines: last_lines)
expect(subject.read(last_lines: last_lines)).to eq(expected) expect(result).to eq(expected)
expect(result.encoding).to eq(Encoding.default_external)
end end
end end
it 'returns everything if trying to get too many lines' do it 'returns everything if trying to get too many lines' do
expect(build_subject.read(last_lines: lines.size * 2)).to eq(lines.join) result = build_subject.read(last_lines: lines.size * 2)
expect(result).to eq(lines.join)
expect(result.encoding).to eq(Encoding.default_external)
end
it 'returns all contents if last_lines is not specified' do
result = build_subject.read
expect(result).to eq(lines.join)
expect(result.encoding).to eq(Encoding.default_external)
end end
it 'raises an error if not passing an integer for last_lines' do it 'raises an error if not passing an integer for last_lines' do
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::View::Presenter::Delegated do describe Gitlab::View::Presenter::Delegated do
let(:project) { double(:project, bar: 'baz') } let(:project) { double(:project, user: 'John Doe') }
let(:presenter_class) do let(:presenter_class) do
Class.new(described_class) Class.new(described_class)
end end
...@@ -12,10 +12,14 @@ describe Gitlab::View::Presenter::Delegated do ...@@ -12,10 +12,14 @@ describe Gitlab::View::Presenter::Delegated do
describe '#initialize' do describe '#initialize' do
it 'takes arbitrary key/values and exposes them' do it 'takes arbitrary key/values and exposes them' do
presenter = presenter_class.new(project, user: 'user', foo: 'bar') presenter = presenter_class.new(project, current_user: 'Jane Doe')
expect(presenter.user).to eq('user') expect(presenter.current_user).to eq('Jane Doe')
expect(presenter.foo).to eq('bar') end
it 'raise an error if the presentee already respond to method' do
expect { presenter_class.new(project, user: 'Jane Doe') }.
to raise_error Gitlab::View::Presenter::CannotOverrideMethodError
end end
end end
...@@ -23,7 +27,7 @@ describe Gitlab::View::Presenter::Delegated do ...@@ -23,7 +27,7 @@ describe Gitlab::View::Presenter::Delegated do
it 'forwards missing methods to subject' do it 'forwards missing methods to subject' do
presenter = presenter_class.new(project) presenter = presenter_class.new(project)
expect(presenter.bar).to eq('baz') expect(presenter.user).to eq('John Doe')
end end
end end
end end
...@@ -22,13 +22,6 @@ describe Gitlab::View::Presenter::Factory do ...@@ -22,13 +22,6 @@ describe Gitlab::View::Presenter::Factory do
end end
describe '#fabricate!' do describe '#fabricate!' do
it 'exposes given params' do
presenter = described_class.new(build, user: 'user', foo: 'bar').fabricate!
expect(presenter.user).to eq('user')
expect(presenter.foo).to eq('bar')
end
it 'detects the presenter based on the given subject' do it 'detects the presenter based on the given subject' do
presenter = described_class.new(build).fabricate! presenter = described_class.new(build).fabricate!
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::View::Presenter::Simple do describe Gitlab::View::Presenter::Simple do
let(:project) { double(:project) } let(:project) { double(:project, user: 'John Doe') }
let(:presenter_class) do let(:presenter_class) do
Class.new(described_class) Class.new(described_class)
end end
...@@ -12,10 +12,15 @@ describe Gitlab::View::Presenter::Simple do ...@@ -12,10 +12,15 @@ describe Gitlab::View::Presenter::Simple do
describe '#initialize' do describe '#initialize' do
it 'takes arbitrary key/values and exposes them' do it 'takes arbitrary key/values and exposes them' do
presenter = presenter_class.new(project, user: 'user', foo: 'bar') presenter = presenter_class.new(project, current_user: 'Jane Doe')
expect(presenter.user).to eq('user') expect(presenter.current_user).to eq('Jane Doe')
expect(presenter.foo).to eq('bar') end
it 'override the presentee attributes' do
presenter = presenter_class.new(project, user: 'Jane Doe')
expect(presenter.user).to eq('Jane Doe')
end end
end end
...@@ -23,7 +28,7 @@ describe Gitlab::View::Presenter::Simple do ...@@ -23,7 +28,7 @@ describe Gitlab::View::Presenter::Simple do
it 'does not forward missing methods to subject' do it 'does not forward missing methods to subject' do
presenter = presenter_class.new(project) presenter = presenter_class.new(project)
expect { presenter.foo }.to raise_error(NoMethodError) expect { presenter.user }.to raise_error(NoMethodError)
end end
end end
end end
...@@ -3,7 +3,7 @@ require 'spec_helper' ...@@ -3,7 +3,7 @@ require 'spec_helper'
describe Ability, lib: true do describe Ability, lib: true do
describe '.can_edit_note?' do describe '.can_edit_note?' do
let(:project) { create(:empty_project) } let(:project) { create(:empty_project) }
let!(:note) { create(:note_on_issue, project: project) } let(:note) { create(:note_on_issue, project: project) }
context 'using an anonymous user' do context 'using an anonymous user' do
it 'returns false' do it 'returns false' do
...@@ -60,7 +60,7 @@ describe Ability, lib: true do ...@@ -60,7 +60,7 @@ describe Ability, lib: true do
describe '.users_that_can_read_project' do describe '.users_that_can_read_project' do
context 'using a public project' do context 'using a public project' do
it 'returns all the users' do it 'returns all the users' do
project = create(:project, :public) project = create(:empty_project, :public)
user = build(:user) user = build(:user)
expect(described_class.users_that_can_read_project([user], project)). expect(described_class.users_that_can_read_project([user], project)).
...@@ -69,7 +69,7 @@ describe Ability, lib: true do ...@@ -69,7 +69,7 @@ describe Ability, lib: true do
end end
context 'using an internal project' do context 'using an internal project' do
let(:project) { create(:project, :internal) } let(:project) { create(:empty_project, :internal) }
it 'returns users that are administrators' do it 'returns users that are administrators' do
user = build(:user, admin: true) user = build(:user, admin: true)
...@@ -120,7 +120,7 @@ describe Ability, lib: true do ...@@ -120,7 +120,7 @@ describe Ability, lib: true do
end end
context 'using a private project' do context 'using a private project' do
let(:project) { create(:project, :private) } let(:project) { create(:empty_project, :private) }
it 'returns users that are administrators' do it 'returns users that are administrators' do
user = build(:user, admin: true) user = build(:user, admin: true)
...@@ -247,7 +247,7 @@ describe Ability, lib: true do ...@@ -247,7 +247,7 @@ describe Ability, lib: true do
end end
describe '.project_disabled_features_rules' do describe '.project_disabled_features_rules' do
let(:project) { create(:project, wiki_access_level: ProjectFeature::DISABLED) } let(:project) { create(:empty_project, wiki_access_level: ProjectFeature::DISABLED) }
subject { described_class.allowed(project.owner, project) } subject { described_class.allowed(project.owner, project) }
......
require 'spec_helper' require 'spec_helper'
describe Ci::Build, :models do describe Ci::Build, :models do
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
let(:build) { create(:ci_build, pipeline: pipeline) } let(:build) { create(:ci_build, pipeline: pipeline) }
let(:test_trace) { 'This is a test' } let(:test_trace) { 'This is a test' }
......
...@@ -284,7 +284,7 @@ describe Ci::Pipeline, models: true do ...@@ -284,7 +284,7 @@ describe Ci::Pipeline, models: true do
end end
describe 'merge request metrics' do describe 'merge request metrics' do
let(:project) { FactoryGirl.create :project } let(:project) { create(:project, :repository) }
let(:pipeline) { FactoryGirl.create(:ci_empty_pipeline, status: 'created', project: project, ref: 'master', sha: project.repository.commit('master').id) } let(:pipeline) { FactoryGirl.create(:ci_empty_pipeline, status: 'created', project: project, ref: 'master', sha: project.repository.commit('master').id) }
let!(:merge_request) { create(:merge_request, source_project: project, source_branch: pipeline.ref) } let!(:merge_request) { create(:merge_request, source_project: project, source_branch: pipeline.ref) }
...@@ -339,7 +339,7 @@ describe Ci::Pipeline, models: true do ...@@ -339,7 +339,7 @@ describe Ci::Pipeline, models: true do
end end
context 'with non-empty project' do context 'with non-empty project' do
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
let(:pipeline) do let(:pipeline) do
create(:ci_pipeline, create(:ci_pipeline,
...@@ -890,7 +890,7 @@ describe Ci::Pipeline, models: true do ...@@ -890,7 +890,7 @@ describe Ci::Pipeline, models: true do
end end
describe "#merge_requests" do describe "#merge_requests" do
let(:project) { FactoryGirl.create :project } let(:project) { create(:project, :repository) }
let(:pipeline) { FactoryGirl.create(:ci_empty_pipeline, status: 'created', project: project, ref: 'master', sha: project.repository.commit('master').id) } let(:pipeline) { FactoryGirl.create(:ci_empty_pipeline, status: 'created', project: project, ref: 'master', sha: project.repository.commit('master').id) }
it "returns merge requests whose `diff_head_sha` matches the pipeline's SHA" do it "returns merge requests whose `diff_head_sha` matches the pipeline's SHA" do
...@@ -956,7 +956,7 @@ describe Ci::Pipeline, models: true do ...@@ -956,7 +956,7 @@ describe Ci::Pipeline, models: true do
end end
describe 'notifications when pipeline success or failed' do describe 'notifications when pipeline success or failed' do
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
let(:pipeline) do let(:pipeline) do
create(:ci_pipeline, create(:ci_pipeline,
......
...@@ -91,8 +91,7 @@ describe Ci::Runner, models: true do ...@@ -91,8 +91,7 @@ describe Ci::Runner, models: true do
end end
describe '#can_pick?' do describe '#can_pick?' do
let(:project) { create(:project) } let(:pipeline) { create(:ci_pipeline) }
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:build) { create(:ci_build, pipeline: pipeline) } let(:build) { create(:ci_build, pipeline: pipeline) }
let(:runner) { create(:ci_runner) } let(:runner) { create(:ci_runner) }
...@@ -321,8 +320,8 @@ describe Ci::Runner, models: true do ...@@ -321,8 +320,8 @@ describe Ci::Runner, models: true do
describe '.assignable_for' do describe '.assignable_for' do
let(:runner) { create(:ci_runner) } let(:runner) { create(:ci_runner) }
let(:project) { create(:project) } let(:project) { create(:empty_project) }
let(:another_project) { create(:project) } let(:another_project) { create(:empty_project) }
before do before do
project.runners << runner project.runners << runner
......
...@@ -7,7 +7,7 @@ describe CommitRange, models: true do ...@@ -7,7 +7,7 @@ describe CommitRange, models: true do
it { is_expected.to include_module(Referable) } it { is_expected.to include_module(Referable) }
end end
let!(:project) { create(:project, :public) } let!(:project) { create(:project, :public, :repository) }
let!(:commit1) { project.commit("HEAD~2") } let!(:commit1) { project.commit("HEAD~2") }
let!(:commit2) { project.commit } let!(:commit2) { project.commit }
......
require 'spec_helper' require 'spec_helper'
describe Commit, models: true do describe Commit, models: true do
let(:project) { create(:project, :public) } let(:project) { create(:project, :public, :repository) }
let(:commit) { project.commit } let(:commit) { project.commit }
describe 'modules' do describe 'modules' do
...@@ -34,7 +34,7 @@ describe Commit, models: true do ...@@ -34,7 +34,7 @@ describe Commit, models: true do
end end
describe '#to_reference' do describe '#to_reference' do
let(:project) { create(:project, path: 'sample-project') } let(:project) { create(:project, :repository, path: 'sample-project') }
let(:commit) { project.commit } let(:commit) { project.commit }
it 'returns a String reference to the object' do it 'returns a String reference to the object' do
...@@ -42,13 +42,13 @@ describe Commit, models: true do ...@@ -42,13 +42,13 @@ describe Commit, models: true do
end end
it 'supports a cross-project reference' do it 'supports a cross-project reference' do
another_project = build(:project, name: 'another-project', namespace: project.namespace) another_project = build(:project, :repository, name: 'another-project', namespace: project.namespace)
expect(commit.to_reference(another_project)).to eq "sample-project@#{commit.id}" expect(commit.to_reference(another_project)).to eq "sample-project@#{commit.id}"
end end
end end
describe '#reference_link_text' do describe '#reference_link_text' do
let(:project) { create(:project, path: 'sample-project') } let(:project) { create(:project, :repository, path: 'sample-project') }
let(:commit) { project.commit } let(:commit) { project.commit }
it 'returns a String reference to the object' do it 'returns a String reference to the object' do
...@@ -56,7 +56,7 @@ describe Commit, models: true do ...@@ -56,7 +56,7 @@ describe Commit, models: true do
end end
it 'supports a cross-project reference' do it 'supports a cross-project reference' do
another_project = build(:project, name: 'another-project', namespace: project.namespace) another_project = build(:project, :repository, name: 'another-project', namespace: project.namespace)
expect(commit.reference_link_text(another_project)).to eq "sample-project@#{commit.short_id}" expect(commit.reference_link_text(another_project)).to eq "sample-project@#{commit.short_id}"
end end
end end
...@@ -131,7 +131,7 @@ eos ...@@ -131,7 +131,7 @@ eos
describe '#closes_issues' do describe '#closes_issues' do
let(:issue) { create :issue, project: project } let(:issue) { create :issue, project: project }
let(:other_project) { create :project, :public } let(:other_project) { create(:empty_project, :public) }
let(:other_issue) { create :issue, project: other_project } let(:other_issue) { create :issue, project: other_project }
let(:commiter) { create :user } let(:commiter) { create :user }
...@@ -154,7 +154,7 @@ eos ...@@ -154,7 +154,7 @@ eos
end end
it_behaves_like 'a mentionable' do it_behaves_like 'a mentionable' do
subject { create(:project).commit } subject { create(:project, :repository).commit }
let(:author) { create(:user, email: subject.author_email) } let(:author) { create(:user, email: subject.author_email) }
let(:backref_text) { "commit #{subject.id}" } let(:backref_text) { "commit #{subject.id}" }
......
require 'spec_helper' require 'spec_helper'
describe CommitStatus, models: true do describe CommitStatus, models: true do
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
let(:pipeline) do let(:pipeline) do
create(:ci_pipeline, project: project, sha: project.commit.id) create(:ci_pipeline, project: project, sha: project.commit.id)
......
...@@ -3,7 +3,7 @@ require 'spec_helper' ...@@ -3,7 +3,7 @@ require 'spec_helper'
describe Compare, models: true do describe Compare, models: true do
include RepoHelpers include RepoHelpers
let(:project) { create(:project, :public) } let(:project) { create(:project, :public, :repository) }
let(:commit) { project.commit } let(:commit) { project.commit }
let(:start_commit) { sample_image_commit } let(:start_commit) { sample_image_commit }
......
...@@ -318,7 +318,7 @@ describe Issue, "Issuable" do ...@@ -318,7 +318,7 @@ describe Issue, "Issuable" do
end end
describe '#labels_array' do describe '#labels_array' do
let(:project) { create(:project) } let(:project) { create(:empty_project) }
let(:bug) { create(:label, project: project, title: 'bug') } let(:bug) { create(:label, project: project, title: 'bug') }
let(:issue) { create(:issue, project: project) } let(:issue) { create(:issue, project: project) }
...@@ -332,7 +332,7 @@ describe Issue, "Issuable" do ...@@ -332,7 +332,7 @@ describe Issue, "Issuable" do
end end
describe '#user_notes_count' do describe '#user_notes_count' do
let(:project) { create(:project) } let(:project) { create(:empty_project) }
let(:issue1) { create(:issue, project: project) } let(:issue1) { create(:issue, project: project) }
let(:issue2) { create(:issue, project: project) } let(:issue2) { create(:issue, project: project) }
...@@ -376,7 +376,7 @@ describe Issue, "Issuable" do ...@@ -376,7 +376,7 @@ describe Issue, "Issuable" do
end end
describe ".with_label" do describe ".with_label" do
let(:project) { create(:project, :public) } let(:project) { create(:empty_project, :public) }
let(:bug) { create(:label, project: project, title: 'bug') } let(:bug) { create(:label, project: project, title: 'bug') }
let(:feature) { create(:label, project: project, title: 'feature') } let(:feature) { create(:label, project: project, title: 'feature') }
let(:enhancement) { create(:label, project: project, title: 'enhancement') } let(:enhancement) { create(:label, project: project, title: 'enhancement') }
......
...@@ -13,7 +13,7 @@ describe Mentionable do ...@@ -13,7 +13,7 @@ describe Mentionable do
end end
describe 'references' do describe 'references' do
let(:project) { create(:project) } let(:project) { create(:empty_project) }
let(:mentionable) { Example.new } let(:mentionable) { Example.new }
it 'excludes JIRA references' do it 'excludes JIRA references' do
...@@ -83,13 +83,13 @@ describe Issue, "Mentionable" do ...@@ -83,13 +83,13 @@ describe Issue, "Mentionable" do
end end
describe '#create_cross_references!' do describe '#create_cross_references!' do
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
let(:author) { build(:user) } let(:author) { build(:user) }
let(:commit) { project.commit } let(:commit) { project.commit }
let(:commit2) { project.commit } let(:commit2) { project.commit }
let!(:issue) do let!(:issue) do
create(:issue, project: project, description: commit.to_reference) create(:issue, project: project, description: "See #{commit.to_reference}")
end end
it 'correctly removes already-mentioned Commits' do it 'correctly removes already-mentioned Commits' do
...@@ -100,7 +100,7 @@ describe Issue, "Mentionable" do ...@@ -100,7 +100,7 @@ describe Issue, "Mentionable" do
end end
describe '#create_new_cross_references!' do describe '#create_new_cross_references!' do
let(:project) { create(:project) } let(:project) { create(:empty_project) }
let(:author) { create(:author) } let(:author) { create(:author) }
let(:issues) { create_list(:issue, 2, project: project, author: author) } let(:issues) { create_list(:issue, 2, project: project, author: author) }
......
...@@ -7,7 +7,7 @@ describe Milestone, 'Milestoneish' do ...@@ -7,7 +7,7 @@ describe Milestone, 'Milestoneish' do
let(:member) { create(:user) } let(:member) { create(:user) }
let(:guest) { create(:user) } let(:guest) { create(:user) }
let(:admin) { create(:admin) } let(:admin) { create(:admin) }
let(:project) { create(:project, :public) } let(:project) { create(:empty_project, :public) }
let(:milestone) { create(:milestone, project: project) } let(:milestone) { create(:milestone, project: project) }
let!(:issue) { create(:issue, project: project, milestone: milestone) } let!(:issue) { create(:issue, project: project, milestone: milestone) }
let!(:security_issue_1) { create(:issue, :confidential, project: project, author: author, milestone: milestone) } let!(:security_issue_1) { create(:issue, :confidential, project: project, author: author, milestone: milestone) }
......
require 'spec_helper' require 'spec_helper'
describe ProjectFeaturesCompatibility do describe ProjectFeaturesCompatibility do
let(:project) { create(:project) } let(:project) { create(:empty_project) }
let(:features) { %w(issues wiki builds merge_requests snippets) } let(:features) { %w(issues wiki builds merge_requests snippets) }
# We had issues_enabled, snippets_enabled, builds_enabled, merge_requests_enabled and issues_enabled fields on projects table # We had issues_enabled, snippets_enabled, builds_enabled, merge_requests_enabled and issues_enabled fields on projects table
......
...@@ -3,7 +3,7 @@ require 'spec_helper' ...@@ -3,7 +3,7 @@ require 'spec_helper'
describe 'CycleAnalytics#code', feature: true do describe 'CycleAnalytics#code', feature: true do
extend CycleAnalyticsHelpers::TestGeneration extend CycleAnalyticsHelpers::TestGeneration
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
let(:from_date) { 10.days.ago } let(:from_date) { 10.days.ago }
let(:user) { create(:user, :admin) } let(:user) { create(:user, :admin) }
subject { CycleAnalytics.new(project, from: from_date) } subject { CycleAnalytics.new(project, from: from_date) }
......
...@@ -3,7 +3,7 @@ require 'spec_helper' ...@@ -3,7 +3,7 @@ require 'spec_helper'
describe 'CycleAnalytics#issue', models: true do describe 'CycleAnalytics#issue', models: true do
extend CycleAnalyticsHelpers::TestGeneration extend CycleAnalyticsHelpers::TestGeneration
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
let(:from_date) { 10.days.ago } let(:from_date) { 10.days.ago }
let(:user) { create(:user, :admin) } let(:user) { create(:user, :admin) }
subject { CycleAnalytics.new(project, from: from_date) } subject { CycleAnalytics.new(project, from: from_date) }
......
...@@ -3,7 +3,7 @@ require 'spec_helper' ...@@ -3,7 +3,7 @@ require 'spec_helper'
describe 'CycleAnalytics#plan', feature: true do describe 'CycleAnalytics#plan', feature: true do
extend CycleAnalyticsHelpers::TestGeneration extend CycleAnalyticsHelpers::TestGeneration
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
let(:from_date) { 10.days.ago } let(:from_date) { 10.days.ago }
let(:user) { create(:user, :admin) } let(:user) { create(:user, :admin) }
subject { CycleAnalytics.new(project, from: from_date) } subject { CycleAnalytics.new(project, from: from_date) }
......
...@@ -3,7 +3,7 @@ require 'spec_helper' ...@@ -3,7 +3,7 @@ require 'spec_helper'
describe 'CycleAnalytics#production', feature: true do describe 'CycleAnalytics#production', feature: true do
extend CycleAnalyticsHelpers::TestGeneration extend CycleAnalyticsHelpers::TestGeneration
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
let(:from_date) { 10.days.ago } let(:from_date) { 10.days.ago }
let(:user) { create(:user, :admin) } let(:user) { create(:user, :admin) }
subject { CycleAnalytics.new(project, from: from_date) } subject { CycleAnalytics.new(project, from: from_date) }
......
...@@ -3,7 +3,7 @@ require 'spec_helper' ...@@ -3,7 +3,7 @@ require 'spec_helper'
describe 'CycleAnalytics#review', feature: true do describe 'CycleAnalytics#review', feature: true do
extend CycleAnalyticsHelpers::TestGeneration extend CycleAnalyticsHelpers::TestGeneration
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
let(:from_date) { 10.days.ago } let(:from_date) { 10.days.ago }
let(:user) { create(:user, :admin) } let(:user) { create(:user, :admin) }
subject { CycleAnalytics.new(project, from: from_date) } subject { CycleAnalytics.new(project, from: from_date) }
......
...@@ -3,9 +3,10 @@ require 'spec_helper' ...@@ -3,9 +3,10 @@ require 'spec_helper'
describe 'CycleAnalytics#staging', feature: true do describe 'CycleAnalytics#staging', feature: true do
extend CycleAnalyticsHelpers::TestGeneration extend CycleAnalyticsHelpers::TestGeneration
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
let(:from_date) { 10.days.ago } let(:from_date) { 10.days.ago }
let(:user) { create(:user, :admin) } let(:user) { create(:user, :admin) }
subject { CycleAnalytics.new(project, from: from_date) } subject { CycleAnalytics.new(project, from: from_date) }
generate_cycle_analytics_spec( generate_cycle_analytics_spec(
......
...@@ -3,7 +3,7 @@ require 'spec_helper' ...@@ -3,7 +3,7 @@ require 'spec_helper'
describe 'CycleAnalytics#test', feature: true do describe 'CycleAnalytics#test', feature: true do
extend CycleAnalyticsHelpers::TestGeneration extend CycleAnalyticsHelpers::TestGeneration
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
let(:from_date) { 10.days.ago } let(:from_date) { 10.days.ago }
let(:user) { create(:user, :admin) } let(:user) { create(:user, :admin) }
subject { CycleAnalytics.new(project, from: from_date) } subject { CycleAnalytics.new(project, from: from_date) }
......
...@@ -12,7 +12,7 @@ describe DeployKeysProject, models: true do ...@@ -12,7 +12,7 @@ describe DeployKeysProject, models: true do
end end
describe "Destroying" do describe "Destroying" do
let(:project) { create(:project) } let(:project) { create(:empty_project) }
subject { create(:deploy_keys_project, project: project) } subject { create(:deploy_keys_project, project: project) }
let(:deploy_key) { subject.deploy_key } let(:deploy_key) { subject.deploy_key }
...@@ -39,7 +39,7 @@ describe DeployKeysProject, models: true do ...@@ -39,7 +39,7 @@ describe DeployKeysProject, models: true do
end end
context "when the deploy key is used by more than one project" do context "when the deploy key is used by more than one project" do
let!(:other_project) { create(:project) } let!(:other_project) { create(:empty_project) }
before do before do
other_project.deploy_keys << deploy_key other_project.deploy_keys << deploy_key
......
...@@ -17,7 +17,7 @@ describe Deployment, models: true do ...@@ -17,7 +17,7 @@ describe Deployment, models: true do
it { is_expected.to validate_presence_of(:sha) } it { is_expected.to validate_presence_of(:sha) }
describe '#includes_commit?' do describe '#includes_commit?' do
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
let(:environment) { create(:environment, project: project) } let(:environment) { create(:environment, project: project) }
let(:deployment) do let(:deployment) do
create(:deployment, environment: environment, sha: project.commit.id) create(:deployment, environment: environment, sha: project.commit.id)
......
...@@ -3,8 +3,8 @@ require 'spec_helper' ...@@ -3,8 +3,8 @@ require 'spec_helper'
describe DiffNote, models: true do describe DiffNote, models: true do
include RepoHelpers include RepoHelpers
let(:project) { create(:project) } let(:merge_request) { create(:merge_request) }
let(:merge_request) { create(:merge_request, source_project: project) } let(:project) { merge_request.project }
let(:commit) { project.commit(sample_commit.id) } let(:commit) { project.commit(sample_commit.id) }
let(:path) { "files/ruby/popen.rb" } let(:path) { "files/ruby/popen.rb" }
......
...@@ -32,7 +32,7 @@ describe Environment, models: true do ...@@ -32,7 +32,7 @@ describe Environment, models: true do
end end
describe '#includes_commit?' do describe '#includes_commit?' do
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
context 'without a last deployment' do context 'without a last deployment' do
it "returns false" do it "returns false" do
...@@ -81,7 +81,7 @@ describe Environment, models: true do ...@@ -81,7 +81,7 @@ describe Environment, models: true do
end end
describe '#first_deployment_for' do describe '#first_deployment_for' do
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
let!(:deployment) { create(:deployment, environment: environment, ref: commit.parent.id) } let!(:deployment) { create(:deployment, environment: environment, ref: commit.parent.id) }
let!(:deployment1) { create(:deployment, environment: environment, ref: commit.id) } let!(:deployment1) { create(:deployment, environment: environment, ref: commit.id) }
let(:head_commit) { project.commit } let(:head_commit) { project.commit }
......
...@@ -27,7 +27,7 @@ describe Event, models: true do ...@@ -27,7 +27,7 @@ describe Event, models: true do
end end
describe "Push event" do describe "Push event" do
let(:project) { create(:project, :private) } let(:project) { create(:empty_project, :private) }
let(:user) { project.owner } let(:user) { project.owner }
let(:event) { create_event(project, user) } let(:event) { create_event(project, user) }
...@@ -187,7 +187,7 @@ describe Event, models: true do ...@@ -187,7 +187,7 @@ describe Event, models: true do
end end
context 'merge request diff note event' do context 'merge request diff note event' do
let(:project) { create(:project, :public) } let(:project) { create(:empty_project, :public) }
let(:merge_request) { create(:merge_request, source_project: project, author: author, assignee: assignee) } let(:merge_request) { create(:merge_request, source_project: project, author: author, assignee: assignee) }
let(:note_on_merge_request) { create(:legacy_diff_note_on_merge_request, noteable: merge_request, project: project) } let(:note_on_merge_request) { create(:legacy_diff_note_on_merge_request, noteable: merge_request, project: project) }
let(:target) { note_on_merge_request } let(:target) { note_on_merge_request }
...@@ -202,7 +202,7 @@ describe Event, models: true do ...@@ -202,7 +202,7 @@ describe Event, models: true do
end end
context 'private project' do context 'private project' do
let(:project) { create(:project, :private) } let(:project) { create(:empty_project, :private) }
it do it do
expect(event.visible_to_user?(non_member)).to eq false expect(event.visible_to_user?(non_member)).to eq false
......
require 'spec_helper' require 'spec_helper'
describe ForkedProjectLink, "add link on fork" do describe ForkedProjectLink, "add link on fork" do
let(:project_from) { create(:project) } let(:project_from) { create(:project, :repository) }
let(:namespace) { create(:namespace) } let(:namespace) { create(:namespace) }
let(:user) { create(:user, namespace: namespace) } let(:user) { create(:user, namespace: namespace) }
...@@ -21,7 +21,7 @@ end ...@@ -21,7 +21,7 @@ end
describe '#forked?' do describe '#forked?' do
let(:forked_project_link) { build(:forked_project_link) } let(:forked_project_link) { build(:forked_project_link) }
let(:project_from) { create(:project) } let(:project_from) { create(:project, :repository) }
let(:project_to) { create(:project, forked_project_link: forked_project_link) } let(:project_to) { create(:project, forked_project_link: forked_project_link) }
before :each do before :each do
......
...@@ -4,9 +4,9 @@ describe GlobalMilestone, models: true do ...@@ -4,9 +4,9 @@ describe GlobalMilestone, models: true do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:user2) { create(:user) } let(:user2) { create(:user) }
let(:group) { create(:group) } let(:group) { create(:group) }
let(:project1) { create(:project, group: group) } let(:project1) { create(:empty_project, group: group) }
let(:project2) { create(:project, path: 'gitlab-ci', group: group) } let(:project2) { create(:empty_project, path: 'gitlab-ci', group: group) }
let(:project3) { create(:project, path: 'cookbook-gitlab', group: group) } let(:project3) { create(:empty_project, path: 'cookbook-gitlab', group: group) }
describe '.build_collection' do describe '.build_collection' do
let(:milestone1_due_date) { 2.weeks.from_now.to_date } let(:milestone1_due_date) { 2.weeks.from_now.to_date }
......
...@@ -2,7 +2,7 @@ require 'spec_helper' ...@@ -2,7 +2,7 @@ require 'spec_helper'
describe GroupMilestone, models: true do describe GroupMilestone, models: true do
let(:group) { create(:group) } let(:group) { create(:group) }
let(:project) { create(:project, group: group) } let(:project) { create(:empty_project, group: group) }
let(:project_milestone) do let(:project_milestone) do
create(:milestone, title: "Milestone v1.2", project: project) create(:milestone, title: "Milestone v1.2", project: project)
end end
......
require 'spec_helper' require 'spec_helper'
describe Guest, lib: true do describe Guest, lib: true do
let(:public_project) { create(:project, :public) } let(:public_project) { build_stubbed(:empty_project, :public) }
let(:private_project) { create(:project, :private) } let(:private_project) { build_stubbed(:empty_project, :private) }
let(:internal_project) { create(:project, :internal) } let(:internal_project) { build_stubbed(:empty_project, :internal) }
describe '.can_pull?' do describe '.can_pull?' do
context 'when project is private' do context 'when project is private' do
......
...@@ -4,7 +4,7 @@ describe SystemHook, models: true do ...@@ -4,7 +4,7 @@ describe SystemHook, models: true do
describe "execute" do describe "execute" do
let(:system_hook) { create(:system_hook) } let(:system_hook) { create(:system_hook) }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project, namespace: user.namespace) } let(:project) { create(:empty_project, namespace: user.namespace) }
let(:group) { create(:group) } let(:group) { create(:group) }
before do before do
......
...@@ -25,7 +25,7 @@ describe WebHook, models: true do ...@@ -25,7 +25,7 @@ describe WebHook, models: true do
end end
describe "execute" do describe "execute" do
let(:project) { create(:project) } let(:project) { create(:empty_project) }
let(:project_hook) { create(:project_hook) } let(:project_hook) { create(:project_hook) }
before(:each) do before(:each) do
......
require 'spec_helper' require 'spec_helper'
describe Issue::Metrics, models: true do describe Issue::Metrics, models: true do
let(:project) { create(:project) } let(:project) { create(:empty_project) }
subject { create(:issue, project: project) } subject { create(:issue, project: project) }
......
...@@ -2,7 +2,7 @@ require 'spec_helper' ...@@ -2,7 +2,7 @@ require 'spec_helper'
describe IssueCollection do describe IssueCollection do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project) } let(:project) { create(:empty_project) }
let(:issue1) { create(:issue, project: project) } let(:issue1) { create(:issue, project: project) }
let(:issue2) { create(:issue, project: project) } let(:issue2) { create(:issue, project: project) }
let(:collection) { described_class.new([issue1, issue2]) } let(:collection) { described_class.new([issue1, issue2]) }
......
...@@ -35,7 +35,7 @@ describe Issue, models: true do ...@@ -35,7 +35,7 @@ describe Issue, models: true do
end end
it 'supports a cross-project reference' do it 'supports a cross-project reference' do
another_project = build(:project, name: 'another-project', namespace: project.namespace) another_project = build(:empty_project, name: 'another-project', namespace: project.namespace)
expect(issue.to_reference(another_project)).to eq "sample-project#1" expect(issue.to_reference(another_project)).to eq "sample-project#1"
end end
end end
...@@ -60,9 +60,9 @@ describe Issue, models: true do ...@@ -60,9 +60,9 @@ describe Issue, models: true do
end end
describe '#closed_by_merge_requests' do describe '#closed_by_merge_requests' do
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
let(:issue) { create(:issue, project: project, state: "opened")} let(:issue) { create(:issue, project: project)}
let(:closed_issue) { build(:issue, project: project, state: "closed")} let(:closed_issue) { build(:issue, :closed, project: project)}
let(:mr) do let(:mr) do
opts = { opts = {
...@@ -104,7 +104,7 @@ describe Issue, models: true do ...@@ -104,7 +104,7 @@ describe Issue, models: true do
describe '#referenced_merge_requests' do describe '#referenced_merge_requests' do
it 'returns the referenced merge requests' do it 'returns the referenced merge requests' do
project = create(:project, :public) project = create(:empty_project, :public)
mr1 = create(:merge_request, mr1 = create(:merge_request,
source_project: project, source_project: project,
...@@ -137,7 +137,7 @@ describe Issue, models: true do ...@@ -137,7 +137,7 @@ describe Issue, models: true do
end end
context 'user is reporter in project issue belongs to' do context 'user is reporter in project issue belongs to' do
let(:project) { create(:project) } let(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) } let(:issue) { create(:issue, project: project) }
before { project.team << [user, :reporter] } before { project.team << [user, :reporter] }
...@@ -151,7 +151,7 @@ describe Issue, models: true do ...@@ -151,7 +151,7 @@ describe Issue, models: true do
context 'checking destination project also' do context 'checking destination project also' do
subject { issue.can_move?(user, to_project) } subject { issue.can_move?(user, to_project) }
let(:to_project) { create(:project) } let(:to_project) { create(:empty_project) }
context 'destination project allowed' do context 'destination project allowed' do
before { to_project.team << [user, :reporter] } before { to_project.team << [user, :reporter] }
...@@ -246,7 +246,7 @@ describe Issue, models: true do ...@@ -246,7 +246,7 @@ describe Issue, models: true do
describe '#participants' do describe '#participants' do
context 'using a public project' do context 'using a public project' do
let(:project) { create(:project, :public) } let(:project) { create(:empty_project, :public) }
let(:issue) { create(:issue, project: project) } let(:issue) { create(:issue, project: project) }
let!(:note1) do let!(:note1) do
...@@ -268,7 +268,7 @@ describe Issue, models: true do ...@@ -268,7 +268,7 @@ describe Issue, models: true do
context 'using a private project' do context 'using a private project' do
it 'does not include mentioned users that do not have access to the project' do it 'does not include mentioned users that do not have access to the project' do
project = create(:project) project = create(:empty_project)
user = create(:user) user = create(:user)
issue = create(:issue, project: project) issue = create(:issue, project: project)
......
...@@ -481,7 +481,7 @@ describe Member, models: true do ...@@ -481,7 +481,7 @@ describe Member, models: true do
describe "destroying a record", truncate: true do describe "destroying a record", truncate: true do
it "refreshes user's authorized projects" do it "refreshes user's authorized projects" do
project = create(:project, :private) project = create(:empty_project, :private)
user = create(:user) user = create(:user)
member = project.team << [user, :reporter] member = project.team << [user, :reporter]
......
...@@ -83,8 +83,8 @@ describe ProjectMember, models: true do ...@@ -83,8 +83,8 @@ describe ProjectMember, models: true do
describe '.import_team' do describe '.import_team' do
before do before do
@project_1 = create :project @project_1 = create(:empty_project)
@project_2 = create :project @project_2 = create(:empty_project)
@user_1 = create :user @user_1 = create :user
@user_2 = create :user @user_2 = create :user
...@@ -131,8 +131,8 @@ describe ProjectMember, models: true do ...@@ -131,8 +131,8 @@ describe ProjectMember, models: true do
describe '.truncate_teams' do describe '.truncate_teams' do
before do before do
@project_1 = create :project @project_1 = create(:empty_project)
@project_2 = create :project @project_2 = create(:empty_project)
@user_1 = create :user @user_1 = create :user
@user_2 = create :user @user_2 = create :user
......
require 'spec_helper' require 'spec_helper'
describe MergeRequest::Metrics, models: true do describe MergeRequest::Metrics, models: true do
let(:project) { create(:project) } subject { create(:merge_request) }
subject { create(:merge_request, source_project: project) }
describe "when recording the default set of metrics on merge request save" do describe "when recording the default set of metrics on merge request save" do
it "records the merge time" do it "records the merge time" do
......
...@@ -24,7 +24,7 @@ describe Milestone, models: true do ...@@ -24,7 +24,7 @@ describe Milestone, models: true do
it { is_expected.to have_many(:issues) } it { is_expected.to have_many(:issues) }
end end
let(:project) { create(:project, :public) } let(:project) { create(:empty_project, :public) }
let(:milestone) { create(:milestone, project: project) } let(:milestone) { create(:milestone, project: project) }
let(:issue) { create(:issue, project: project) } let(:issue) { create(:issue, project: project) }
let(:user) { create(:user) } let(:user) { create(:user) }
...@@ -44,7 +44,7 @@ describe Milestone, models: true do ...@@ -44,7 +44,7 @@ describe Milestone, models: true do
end end
it "accepts the same title in another project" do it "accepts the same title in another project" do
project = build(:project) project = build(:empty_project)
new_milestone = Milestone.new(project: project, title: milestone.title) new_milestone = Milestone.new(project: project, title: milestone.title)
expect(new_milestone).to be_valid expect(new_milestone).to be_valid
...@@ -257,7 +257,7 @@ describe Milestone, models: true do ...@@ -257,7 +257,7 @@ describe Milestone, models: true do
end end
it 'supports a cross-project reference' do it 'supports a cross-project reference' do
another_project = build(:project, name: 'another-project', namespace: project.namespace) another_project = build(:empty_project, name: 'another-project', namespace: project.namespace)
expect(milestone.to_reference(another_project)).to eq "sample-project%1" expect(milestone.to_reference(another_project)).to eq "sample-project%1"
end end
end end
......
...@@ -107,7 +107,7 @@ describe Namespace, models: true do ...@@ -107,7 +107,7 @@ describe Namespace, models: true do
describe '#move_dir' do describe '#move_dir' do
before do before do
@namespace = create :namespace @namespace = create :namespace
@project = create :project, namespace: @namespace @project = create(:empty_project, namespace: @namespace)
allow(@namespace).to receive(:path_changed?).and_return(true) allow(@namespace).to receive(:path_changed?).and_return(true)
end end
...@@ -151,7 +151,7 @@ describe Namespace, models: true do ...@@ -151,7 +151,7 @@ describe Namespace, models: true do
end end
describe :rm_dir do describe :rm_dir do
let!(:project) { create(:project, namespace: namespace) } let!(:project) { create(:empty_project, namespace: namespace) }
let!(:path) { File.join(Gitlab.config.repositories.storages.default, namespace.path) } let!(:path) { File.join(Gitlab.config.repositories.storages.default, namespace.path) }
it "removes its dirs when deleted" do it "removes its dirs when deleted" do
......
require 'spec_helper' require 'spec_helper'
describe Network::Graph, models: true do describe Network::Graph, models: true do
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
let!(:note_on_commit) { create(:note_on_commit, project: project) } let!(:note_on_commit) { create(:note_on_commit, project: project) }
it '#initialize' do it '#initialize' do
......
...@@ -42,7 +42,7 @@ describe Note, models: true do ...@@ -42,7 +42,7 @@ describe Note, models: true do
context 'when noteable and note project differ' do context 'when noteable and note project differ' do
subject do subject do
build(:note, noteable: build_stubbed(:issue), build(:note, noteable: build_stubbed(:issue),
project: build_stubbed(:project)) project: build_stubbed(:empty_project))
end end
it { is_expected.to be_invalid } it { is_expected.to be_invalid }
...@@ -93,8 +93,8 @@ describe Note, models: true do ...@@ -93,8 +93,8 @@ describe Note, models: true do
describe 'authorization' do describe 'authorization' do
before do before do
@p1 = create(:project) @p1 = create(:empty_project)
@p2 = create(:project) @p2 = create(:empty_project)
@u1 = create(:user) @u1 = create(:user)
@u2 = create(:user) @u2 = create(:user)
@u3 = create(:user) @u3 = create(:user)
...@@ -191,10 +191,10 @@ describe Note, models: true do ...@@ -191,10 +191,10 @@ describe Note, models: true do
describe "cross_reference_not_visible_for?" do describe "cross_reference_not_visible_for?" do
let(:private_user) { create(:user) } let(:private_user) { create(:user) }
let(:private_project) { create(:project, namespace: private_user.namespace).tap { |p| p.team << [private_user, :master] } } let(:private_project) { create(:empty_project, namespace: private_user.namespace) { |p| p.team << [private_user, :master] } }
let(:private_issue) { create(:issue, project: private_project) } let(:private_issue) { create(:issue, project: private_project) }
let(:ext_proj) { create(:project, :public) } let(:ext_proj) { create(:empty_project, :public) }
let(:ext_issue) { create(:issue, project: ext_proj) } let(:ext_issue) { create(:issue, project: ext_proj) }
let(:note) do let(:note) do
...@@ -237,7 +237,7 @@ describe Note, models: true do ...@@ -237,7 +237,7 @@ describe Note, models: true do
describe '#participants' do describe '#participants' do
it 'includes the note author' do it 'includes the note author' do
project = create(:project, :public) project = create(:empty_project, :public)
issue = create(:issue, project: project) issue = create(:issue, project: project)
note = create(:note_on_issue, noteable: issue, project: project) note = create(:note_on_issue, noteable: issue, project: project)
......
require 'spec_helper' require 'spec_helper'
describe ProjectFeature do describe ProjectFeature do
let(:project) { create(:project) } let(:project) { create(:empty_project) }
let(:user) { create(:user) } let(:user) { create(:user) }
describe '#feature_available?' do describe '#feature_available?' do
...@@ -35,7 +35,7 @@ describe ProjectFeature do ...@@ -35,7 +35,7 @@ describe ProjectFeature do
it "returns true when user is a member of project group" do it "returns true when user is a member of project group" do
group = create(:group) group = create(:group)
project = create(:project, namespace: group) project = create(:empty_project, namespace: group)
group.add_developer(user) group.add_developer(user)
features.each do |feature| features.each do |feature|
......
...@@ -17,7 +17,7 @@ describe ProjectGroupLink do ...@@ -17,7 +17,7 @@ describe ProjectGroupLink do
describe "destroying a record", truncate: true do describe "destroying a record", truncate: true do
it "refreshes group users' authorized projects" do it "refreshes group users' authorized projects" do
project = create(:project, :private) project = create(:empty_project, :private)
group = create(:group) group = create(:group)
reporter = create(:user) reporter = create(:user)
group_users = group.users group_users = group.users
......
...@@ -100,7 +100,7 @@ describe ProjectLabel, models: true do ...@@ -100,7 +100,7 @@ describe ProjectLabel, models: true do
end end
context 'cross project reference' do context 'cross project reference' do
let(:project) { create(:project) } let(:project) { create(:empty_project) }
context 'using name' do context 'using name' do
it 'returns cross reference with label name' do it 'returns cross reference with label name' do
......
...@@ -18,7 +18,7 @@ describe AsanaService, models: true do ...@@ -18,7 +18,7 @@ describe AsanaService, models: true do
describe 'Execute' do describe 'Execute' do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project) } let(:project) { create(:empty_project) }
def create_data_for_commits(*messages) def create_data_for_commits(*messages)
{ {
......
...@@ -8,7 +8,7 @@ describe AssemblaService, models: true do ...@@ -8,7 +8,7 @@ describe AssemblaService, models: true do
describe "Execute" do describe "Execute" do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
before do before do
@assembla_service = AssemblaService.new @assembla_service = AssemblaService.new
......
...@@ -22,7 +22,7 @@ describe CampfireService, models: true do ...@@ -22,7 +22,7 @@ describe CampfireService, models: true do
describe "#execute" do describe "#execute" do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project) } let(:project) { create(:project, :repository) }
before do before do
@campfire_service = CampfireService.new @campfire_service = CampfireService.new
......
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.
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