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:
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).
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
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
......
/* eslint-disable class-methods-use-this */
//= require lib/utils/url_utility */
(() => {
const UNFOLD_COUNT = 20;
......@@ -104,11 +106,11 @@
}
highlighSelectedLine() {
const hash = gl.utils.getLocationHash();
const $diffFiles = $('.diff-file');
$diffFiles.find('.hll').removeClass('hll');
if (window.location.hash !== '') {
const hash = window.location.hash.replace('#', '');
if (hash) {
$diffFiles
.find(`tr#${hash}:not(.match) td, td#${hash}, td[data-line-code="${hash}"]`)
.addClass('hll');
......
......@@ -9,6 +9,7 @@ require('../window')(function(w){
w.droplabAjax = {
_loadUrlData: function _loadUrlData(url) {
var self = this;
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest;
xhr.open('GET', url, true);
......@@ -16,6 +17,7 @@ require('../window')(function(w){
if(xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
var data = JSON.parse(xhr.responseText);
self.cache[url] = data;
return resolve(data);
} else {
return reject([xhr.responseText, xhr.status]);
......@@ -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) {
var self = this;
self.cache = self.cache || {};
var config = hook.config.droplabAjax;
this.hook = hook;
......@@ -50,22 +65,16 @@ require('../window')(function(w){
dynamicList.outerHTML = loadingTemplate.outerHTML;
}
if (self.cache[config.endpoint]) {
self._loadData(self.cache[config.endpoint], config, self);
} else {
this._loadUrlData(config.endpoint)
.then(function(d) {
if (config.loadingTemplate) {
var dataLoadingTemplate = self.hook.list.list.querySelector('[data-loading-template]');
if (dataLoadingTemplate) {
dataLoadingTemplate.outerHTML = self.listTemplate;
}
}
if (!self.hook.list.hidden) {
self.hook.list[config.method].call(self.hook.list, d);
}
self._loadData(d, config, self);
}).catch(function(e) {
throw new droplabAjaxException(e.message || e);
});
}
},
destroy: function() {
......
......@@ -72,7 +72,41 @@ require('../window')(function(w){
var params = config.params || {};
params[config.searchKey] = searchValue;
var self = this;
this._loadUrlData(config.endpoint + this.buildParams(params)).then(function(data) {
self.cache = self.cache || {};
var url = config.endpoint + this.buildParams(params);
var urlCachedData = self.cache[url];
if (urlCachedData) {
self._loadData(urlCachedData, config, self);
} else {
this._loadUrlData(url)
.then(function(data) {
self._loadData(data, config, self);
});
}
},
_loadUrlData: function _loadUrlData(url) {
var self = this;
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest;
xhr.open('GET', url, true);
xhr.onreadystatechange = function () {
if(xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
var data = JSON.parse(xhr.responseText);
self.cache[url] = data;
return resolve(data);
} else {
return reject([xhr.responseText, xhr.status]);
}
}
};
xhr.send();
});
},
_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]');
......@@ -94,25 +128,6 @@ require('../window')(function(w){
}
self.notLoading();
self.hook.list.currentIndex = 0;
});
},
_loadUrlData: function _loadUrlData(url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest;
xhr.open('GET', url, true);
xhr.onreadystatechange = function () {
if(xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
var data = JSON.parse(xhr.responseText);
return resolve(data);
} else {
return reject([xhr.responseText, xhr.status]);
}
}
};
xhr.send();
});
},
buildParams: function(params) {
......
......@@ -26,6 +26,15 @@
symbol: '',
}];
const alternativeTokenKeys = [{
key: 'label',
type: 'string',
param: 'name',
symbol: '~',
}];
const tokenKeysWithAlternative = tokenKeys.concat(alternativeTokenKeys);
const conditions = [{
url: 'assignee_id=0',
tokenKey: 'assignee',
......@@ -57,6 +66,10 @@
return tokenKeys;
}
static getAlternatives() {
return alternativeTokenKeys;
}
static getConditions() {
return conditions;
}
......@@ -70,7 +83,7 @@
}
static searchByKeyParam(keyParam) {
return tokenKeys.find((tokenKey) => {
return tokenKeysWithAlternative.find((tokenKey) => {
let tokenKeyParam = tokenKey.key;
if (tokenKey.param) {
......
......@@ -74,8 +74,9 @@
// 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
// around the link and/or a persisted underline text decoration.
return $('#blob-content-holder').on('click', 'a[data-line-number]', function(event) {
return event.preventDefault();
$('#blob-content-holder').on('click', 'a[data-line-number]', function(event) {
event.preventDefault();
event.stopPropagation();
});
};
......
......@@ -36,6 +36,7 @@
}
onSubmitForm(e) {
e.preventDefault();
return this.saveForm();
}
......
......@@ -37,6 +37,8 @@
display: inline-block;
margin-left: 4px;
margin-bottom: 2px;
flex-shrink: 0;
-webkit-flex-shrink: 0;
&.s16 { margin-right: 4px; }
&.s24 { margin-right: 4px; }
......
......@@ -125,7 +125,8 @@
top: 100%;
left: 0;
z-index: 9;
width: 240px;
max-width: 280px;
min-width: 240px;
margin-top: 2px;
margin-bottom: 0;
font-size: 14px;
......
......@@ -132,6 +132,11 @@
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
&> span {
white-space: normal;
word-break: break-all;
}
}
}
......@@ -141,10 +146,6 @@
}
}
.hint-dropdown {
width: 250px;
}
.filter-dropdown-loading {
padding: 8px 16px;
}
......@@ -214,9 +214,9 @@
&:not(:last-child) {
&::after {
content: '';
width: 8px;
width: 7px;
position: absolute;
right: -8px;
right: -7px;
top: 10px;
border-bottom: 2px solid $border-color;
}
......
......@@ -22,6 +22,7 @@ class Explore::ProjectsController < Explore::ApplicationController
def trending
@projects = filter_projects(Project.trending)
@projects = @projects.sort(@sort = params[:sort])
@projects = @projects.page(params[:page])
respond_to do |format|
......
......@@ -94,7 +94,7 @@ class Projects::BuildsController < Projects::ApplicationController
private
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
def build_path(build)
......
......@@ -33,12 +33,6 @@ class Projects::RefsController < Projects::ApplicationController
redirect_to new_path
end
format.js do
@ref = params[:ref]
define_tree_vars
tree
render "tree"
end
end
end
......
......@@ -1337,7 +1337,18 @@ class Repository
end
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
def keep_around_ref_name(sha)
......
......@@ -113,7 +113,7 @@ detects the presenter based on the presented subject's class.
class Projects::LabelsController < Projects::ApplicationController
def edit
@label = Gitlab::View::Presenter::Factory
.new(@label, user: current_user)
.new(@label, current_user: current_user)
.fabricate!
end
end
......@@ -132,7 +132,7 @@ and then in the controller:
```ruby
class Projects::LabelsController < Projects::ApplicationController
def edit
@label = @label.present(user: current_user)
@label = @label.present(current_user: current_user)
end
end
```
......@@ -147,7 +147,7 @@ end
You can also present the model in the view:
```ruby
- label = @label.present(current_user)
- label = @label.present(current_user: current_user)
%div{ class: label.text_color }
= render partial: label, label: label
......
......@@ -33,6 +33,8 @@ module Projects
if project.update_attributes(params)
if project.previous_changes.include?('path')
project.rename_repo
else
system_hook_service.execute_hooks_for(project, :update)
end
success
......
......@@ -17,6 +17,13 @@
%pre.dark
:preserve
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
%pre.dark
......
......@@ -47,10 +47,6 @@
%li.filter-dropdown-item{ 'data-value' => 'none' }
%button.btn.btn-link
No Assignee
- if current_user
%li.filter-dropdown-item{ 'data-value' => current_user.to_reference }
%button.btn.btn-link
Assigned to me
%li.divider
%ul.filter-dropdown{ 'data-dynamic' => true, 'data-dropdown' => true }
%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 @@
#
production:
adapter: mysql2
encoding: utf8mb4
collation: utf8mb4_general_ci
encoding: utf8
collation: utf8_general_ci
reconnect: false
database: gitlabhq_production
pool: 10
......@@ -18,8 +18,8 @@ production:
#
development:
adapter: mysql2
encoding: utf8mb4
collation: utf8mb4_general_ci
encoding: utf8
collation: utf8_general_ci
reconnect: false
database: gitlabhq_development
pool: 5
......
......@@ -80,10 +80,14 @@ main: # 'main' is the GitLab 'provider ID' of this LDAP server
# Example: 'Paris' or 'Acme, Ltd.'
label: 'LDAP'
# Example: 'ldap.mydomain.com'
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
uid: 'sAMAccountName'
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'
password: '_the_password_of_the_bind_user'
......@@ -115,7 +119,7 @@ main: # 'main' is the GitLab 'provider ID' of this LDAP server
# 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: ''
......@@ -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.
#
# Below an example for get only specific users
# Example: '(&(objectclass=user)(|(samaccountname=momo)(samaccountname=toto)))'
#
user_filter: ''
# 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
## Periodic checks
GitLab periodically runs a repository check on all project repositories and
wiki repositories in order to detect data corruption problems. A
project will be checked no more than once per week. If any projects
When enabled, GitLab periodically runs a repository check on all project
repositories and wiki repositories in order to detect data corruption problems.
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
notification of the situation. This notification is sent out no more
than once a day.
notification of the situation. This notification is sent out once a week on
Sunday, by default.
## Disabling periodic checks
......
......@@ -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)
- [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/)
- [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/)
- [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)
......
## 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
### before_script
`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
......
......@@ -18,6 +18,7 @@
- [Frontend guidelines](frontend.md)
- [SQL guidelines](sql.md) for working with SQL queries
- [Sidekiq guidelines](sidekiq_style_guide.md) for working with Sidekiq workers
- [`Gemfile` guidelines](gemfile.md)
## 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
The following are the steps to add images to your repository in
GitLab:
Using your standard tool for copying files (e.g. Finder in Mac OS, or Explorer
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:
```
git checkout -b NAME-OF-BRANCH
```
Check if your image is actually present in the directory (if you are in Windows,
use `dir` instead):
Check if your image was correctly added to the directory:
```
ls
```
You should see the name of the image in the list shown.
Move up the hierarchy through directories:
```
cd ../
```
Check the status:
Check the status and you should see your image’s name in red:
```
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
```
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
```
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
```
Your image will be added to your branch in your repository in GitLab. Create a [Merge Request](add-merge-request.md)
to integrate your changes to your project.
Your image will be added to your branch in your repository in GitLab.
This diff is collapsed.
# 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.
......@@ -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:**
```json
......
......@@ -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
```
**MySQL installations**: Run through the `MySQL strings limits` and `Tables and data conversion to utf8mb4` [tasks](../install/database_mysql.md).
### 6. Update gitlab-workhorse
Install and compile gitlab-workhorse. This requires
......
......@@ -140,75 +140,77 @@ into the password field.
## 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, you have several options.
To disable two-factor authentication on your account (for example, if you
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
When you enabled two-factor authentication for your account, a series of
recovery codes were generated. If you saved those codes somewhere safe, you
may use one to sign in.
Enabling two-factor authentication for your account generated several recovery
codes. If you saved these codes, you can use one of them to sign in.
First, enter your username/email and password on the GitLab sign in page. When
prompted for a two-factor code, enter one of the recovery codes you saved
previously.
To use a recovery code, enter your username/email and password on the GitLab
sign-in page. When prompted for a two-factor code, enter the recovery code.
> **Note:** Once a particular recovery code has been used, it cannot be used again.
You may still use the other saved recovery codes at a later time.
> **Note:** Once you use a recovery code, you cannot re-use it. You can still
use the other recovery codes you saved.
### Generate new recovery codes using SSH
It's not uncommon for users to forget to save the recovery codes when enabling
two-factor authentication. If you have an SSH key added to your GitLab account,
you can generate a new set of recovery codes using SSH.
Run `ssh git@gitlab.example.com 2fa_recovery_codes`. You will be prompted to
confirm that you wish to generate new codes. If you choose to continue, any
previously saved codes will be invalidated.
```bash
$ ssh git@gitlab.example.com 2fa_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)
yes
Your two-factor authentication recovery codes are:
119135e5a3ebce8e
11f6v2a498810dcd
3924c7ab2089c902
e79a3398bfe4f224
34bd7b74adbc8861
f061691d5107df1a
169bf32a18e63e7f
b510e7422e81c947
20dbed24c5e74663
df9d3b9403b9c9f0
During sign in, use one of the codes above when prompted for
your two-factor code. Then, visit your Profile Settings and add
a new device so you do not lose access to your account again.
```
Next, 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
from the command line output.
> **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 on your account
If the above two methods are not possible, you may ask a GitLab global
administrator to disable two-factor authentication for your account. Please
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.
Users often forget to save their recovery codes when enabling two-factor
authentication. If an SSH key is added to your GitLab account, you can generate
a new set of recovery codes with SSH.
1. Run `ssh git@gitlab.example.com 2fa_recovery_codes`.
2. You are prompted to confirm that you want to generate new codes. Continuing this process invalidates previously saved codes.
```
bash
$ ssh git@gitlab.example.com 2fa_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)
yes
Your two-factor authentication recovery codes are:
119135e5a3ebce8e
11f6v2a498810dcd
3924c7ab2089c902
e79a3398bfe4f224
34bd7b74adbc8861
f061691d5107df1a
169bf32a18e63e7f
b510e7422e81c947
20dbed24c5e74663
df9d3b9403b9c9f0
During sign in, use one of the codes above when prompted for your
two-factor code. Then, visit your Profile Settings and add a new device
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
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.
### Ask a GitLab administrator to disable two-factor authentication 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
account. This will temporarily leave your account in a less secure state.
Sign in and re-enable two-factor authentication as soon as possible.
## Note to GitLab administrators
You need to take special care to that 2FA keeps working after
[restoring a GitLab backup](../../../raketasks/backup_restore.md).
- You need to take special care to that 2FA keeps working after
[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
[FreeOTP]: https://fedorahosted.org/freeotp/
......
......@@ -42,6 +42,7 @@ module Gitlab
end
chunks.join.lines.last(max_lines).join
.force_encoding(Encoding.default_external)
end
end
end
......
module Gitlab
module View
module Presenter
CannotOverrideMethodError = Class.new(StandardError)
module Base
extend ActiveSupport::Concern
......
......@@ -8,6 +8,10 @@ module Gitlab
@subject = subject
attributes.each do |key, value|
if subject.respond_to?(key)
raise CannotOverrideMethodError.new("#{subject} already respond to #{key}!")
end
define_singleton_method(key) { value }
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
expect(page).to have_css(js_dropdown_assignee, visible: true)
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
find('body').click()
......@@ -129,14 +121,6 @@ describe 'Dropdown assignee', js: true, feature: true do
filtered_search.set('assignee:')
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
click_assignee(user_jacob.name)
......@@ -185,4 +169,22 @@ describe 'Dropdown assignee', js: true, feature: true do
expect(page).to have_css(js_dropdown_assignee, visible: true)
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
......@@ -157,4 +157,22 @@ describe 'Dropdown author', js: true, feature: true do
expect(page).to have_css(js_dropdown_author, visible: true)
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
......@@ -249,4 +249,21 @@ describe 'Dropdown label', js: true, feature: true do
expect(page).to have_css(js_dropdown_label, visible: true)
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
......@@ -219,4 +219,21 @@ describe 'Dropdown milestone', js: true, feature: true do
expect(page).to have_css(js_dropdown_milestone, visible: true)
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
......@@ -72,6 +72,12 @@
const result = gl.FilteredSearchTokenKeys.searchByKeyParam(`${tokenKeys[0].key}_${tokenKeys[0].param}`);
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', () => {
......
......@@ -11,13 +11,25 @@ describe Gitlab::Ci::TraceReader do
last_lines = random_lines
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
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
it 'raises an error if not passing an integer for last_lines' do
......
require 'spec_helper'
describe Gitlab::View::Presenter::Delegated do
let(:project) { double(:project, bar: 'baz') }
let(:project) { double(:project, user: 'John Doe') }
let(:presenter_class) do
Class.new(described_class)
end
......@@ -12,10 +12,14 @@ describe Gitlab::View::Presenter::Delegated do
describe '#initialize' 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.foo).to eq('bar')
expect(presenter.current_user).to eq('Jane Doe')
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
......@@ -23,7 +27,7 @@ describe Gitlab::View::Presenter::Delegated do
it 'forwards missing methods to subject' do
presenter = presenter_class.new(project)
expect(presenter.bar).to eq('baz')
expect(presenter.user).to eq('John Doe')
end
end
end
......@@ -22,13 +22,6 @@ describe Gitlab::View::Presenter::Factory do
end
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
presenter = described_class.new(build).fabricate!
......
require 'spec_helper'
describe Gitlab::View::Presenter::Simple do
let(:project) { double(:project) }
let(:project) { double(:project, user: 'John Doe') }
let(:presenter_class) do
Class.new(described_class)
end
......@@ -12,10 +12,15 @@ describe Gitlab::View::Presenter::Simple do
describe '#initialize' 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.foo).to eq('bar')
expect(presenter.current_user).to eq('Jane Doe')
end
it 'override the presentee attributes' do
presenter = presenter_class.new(project, user: 'Jane Doe')
expect(presenter.user).to eq('Jane Doe')
end
end
......@@ -23,7 +28,7 @@ describe Gitlab::View::Presenter::Simple do
it 'does not forward missing methods to subject' do
presenter = presenter_class.new(project)
expect { presenter.foo }.to raise_error(NoMethodError)
expect { presenter.user }.to raise_error(NoMethodError)
end
end
end
......@@ -3,7 +3,7 @@ require 'spec_helper'
describe Ability, lib: true do
describe '.can_edit_note?' do
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
it 'returns false' do
......@@ -60,7 +60,7 @@ describe Ability, lib: true do
describe '.users_that_can_read_project' do
context 'using a public project' do
it 'returns all the users' do
project = create(:project, :public)
project = create(:empty_project, :public)
user = build(:user)
expect(described_class.users_that_can_read_project([user], project)).
......@@ -69,7 +69,7 @@ describe Ability, lib: true do
end
context 'using an internal project' do
let(:project) { create(:project, :internal) }
let(:project) { create(:empty_project, :internal) }
it 'returns users that are administrators' do
user = build(:user, admin: true)
......@@ -120,7 +120,7 @@ describe Ability, lib: true do
end
context 'using a private project' do
let(:project) { create(:project, :private) }
let(:project) { create(:empty_project, :private) }
it 'returns users that are administrators' do
user = build(:user, admin: true)
......@@ -247,7 +247,7 @@ describe Ability, lib: true do
end
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) }
......
require 'spec_helper'
describe Ci::Build, :models do
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:build) { create(:ci_build, pipeline: pipeline) }
let(:test_trace) { 'This is a test' }
......
......@@ -284,7 +284,7 @@ describe Ci::Pipeline, models: true do
end
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!(:merge_request) { create(:merge_request, source_project: project, source_branch: pipeline.ref) }
......@@ -339,7 +339,7 @@ describe Ci::Pipeline, models: true do
end
context 'with non-empty project' do
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:pipeline) do
create(:ci_pipeline,
......@@ -890,7 +890,7 @@ describe Ci::Pipeline, models: true do
end
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) }
it "returns merge requests whose `diff_head_sha` matches the pipeline's SHA" do
......@@ -956,7 +956,7 @@ describe Ci::Pipeline, models: true do
end
describe 'notifications when pipeline success or failed' do
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:pipeline) do
create(:ci_pipeline,
......
......@@ -91,8 +91,7 @@ describe Ci::Runner, models: true do
end
describe '#can_pick?' do
let(:project) { create(:project) }
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:pipeline) { create(:ci_pipeline) }
let(:build) { create(:ci_build, pipeline: pipeline) }
let(:runner) { create(:ci_runner) }
......@@ -321,8 +320,8 @@ describe Ci::Runner, models: true do
describe '.assignable_for' do
let(:runner) { create(:ci_runner) }
let(:project) { create(:project) }
let(:another_project) { create(:project) }
let(:project) { create(:empty_project) }
let(:another_project) { create(:empty_project) }
before do
project.runners << runner
......
......@@ -7,7 +7,7 @@ describe CommitRange, models: true do
it { is_expected.to include_module(Referable) }
end
let!(:project) { create(:project, :public) }
let!(:project) { create(:project, :public, :repository) }
let!(:commit1) { project.commit("HEAD~2") }
let!(:commit2) { project.commit }
......
require 'spec_helper'
describe Commit, models: true do
let(:project) { create(:project, :public) }
let(:project) { create(:project, :public, :repository) }
let(:commit) { project.commit }
describe 'modules' do
......@@ -34,7 +34,7 @@ describe Commit, models: true do
end
describe '#to_reference' do
let(:project) { create(:project, path: 'sample-project') }
let(:project) { create(:project, :repository, path: 'sample-project') }
let(:commit) { project.commit }
it 'returns a String reference to the object' do
......@@ -42,13 +42,13 @@ describe Commit, models: true do
end
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}"
end
end
describe '#reference_link_text' do
let(:project) { create(:project, path: 'sample-project') }
let(:project) { create(:project, :repository, path: 'sample-project') }
let(:commit) { project.commit }
it 'returns a String reference to the object' do
......@@ -56,7 +56,7 @@ describe Commit, models: true do
end
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}"
end
end
......@@ -131,7 +131,7 @@ eos
describe '#closes_issues' do
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(:commiter) { create :user }
......@@ -154,7 +154,7 @@ eos
end
it_behaves_like 'a mentionable' do
subject { create(:project).commit }
subject { create(:project, :repository).commit }
let(:author) { create(:user, email: subject.author_email) }
let(:backref_text) { "commit #{subject.id}" }
......
require 'spec_helper'
describe CommitStatus, models: true do
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:pipeline) do
create(:ci_pipeline, project: project, sha: project.commit.id)
......
......@@ -3,7 +3,7 @@ require 'spec_helper'
describe Compare, models: true do
include RepoHelpers
let(:project) { create(:project, :public) }
let(:project) { create(:project, :public, :repository) }
let(:commit) { project.commit }
let(:start_commit) { sample_image_commit }
......
......@@ -318,7 +318,7 @@ describe Issue, "Issuable" do
end
describe '#labels_array' do
let(:project) { create(:project) }
let(:project) { create(:empty_project) }
let(:bug) { create(:label, project: project, title: 'bug') }
let(:issue) { create(:issue, project: project) }
......@@ -332,7 +332,7 @@ describe Issue, "Issuable" do
end
describe '#user_notes_count' do
let(:project) { create(:project) }
let(:project) { create(:empty_project) }
let(:issue1) { create(:issue, project: project) }
let(:issue2) { create(:issue, project: project) }
......@@ -376,7 +376,7 @@ describe Issue, "Issuable" do
end
describe ".with_label" do
let(:project) { create(:project, :public) }
let(:project) { create(:empty_project, :public) }
let(:bug) { create(:label, project: project, title: 'bug') }
let(:feature) { create(:label, project: project, title: 'feature') }
let(:enhancement) { create(:label, project: project, title: 'enhancement') }
......
......@@ -13,7 +13,7 @@ describe Mentionable do
end
describe 'references' do
let(:project) { create(:project) }
let(:project) { create(:empty_project) }
let(:mentionable) { Example.new }
it 'excludes JIRA references' do
......@@ -83,13 +83,13 @@ describe Issue, "Mentionable" do
end
describe '#create_cross_references!' do
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:author) { build(:user) }
let(:commit) { project.commit }
let(:commit2) { project.commit }
let!(:issue) do
create(:issue, project: project, description: commit.to_reference)
create(:issue, project: project, description: "See #{commit.to_reference}")
end
it 'correctly removes already-mentioned Commits' do
......@@ -100,7 +100,7 @@ describe Issue, "Mentionable" do
end
describe '#create_new_cross_references!' do
let(:project) { create(:project) }
let(:project) { create(:empty_project) }
let(:author) { create(:author) }
let(:issues) { create_list(:issue, 2, project: project, author: author) }
......
......@@ -7,7 +7,7 @@ describe Milestone, 'Milestoneish' do
let(:member) { create(:user) }
let(:guest) { create(:user) }
let(:admin) { create(:admin) }
let(:project) { create(:project, :public) }
let(:project) { create(:empty_project, :public) }
let(:milestone) { create(:milestone, project: project) }
let!(:issue) { create(:issue, project: project, milestone: milestone) }
let!(:security_issue_1) { create(:issue, :confidential, project: project, author: author, milestone: milestone) }
......
require 'spec_helper'
describe ProjectFeaturesCompatibility do
let(:project) { create(:project) }
let(:project) { create(:empty_project) }
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
......
......@@ -3,7 +3,7 @@ require 'spec_helper'
describe 'CycleAnalytics#code', feature: true do
extend CycleAnalyticsHelpers::TestGeneration
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:from_date) { 10.days.ago }
let(:user) { create(:user, :admin) }
subject { CycleAnalytics.new(project, from: from_date) }
......
......@@ -3,7 +3,7 @@ require 'spec_helper'
describe 'CycleAnalytics#issue', models: true do
extend CycleAnalyticsHelpers::TestGeneration
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:from_date) { 10.days.ago }
let(:user) { create(:user, :admin) }
subject { CycleAnalytics.new(project, from: from_date) }
......
......@@ -3,7 +3,7 @@ require 'spec_helper'
describe 'CycleAnalytics#plan', feature: true do
extend CycleAnalyticsHelpers::TestGeneration
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:from_date) { 10.days.ago }
let(:user) { create(:user, :admin) }
subject { CycleAnalytics.new(project, from: from_date) }
......
......@@ -3,7 +3,7 @@ require 'spec_helper'
describe 'CycleAnalytics#production', feature: true do
extend CycleAnalyticsHelpers::TestGeneration
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:from_date) { 10.days.ago }
let(:user) { create(:user, :admin) }
subject { CycleAnalytics.new(project, from: from_date) }
......
......@@ -3,7 +3,7 @@ require 'spec_helper'
describe 'CycleAnalytics#review', feature: true do
extend CycleAnalyticsHelpers::TestGeneration
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:from_date) { 10.days.ago }
let(:user) { create(:user, :admin) }
subject { CycleAnalytics.new(project, from: from_date) }
......
......@@ -3,9 +3,10 @@ require 'spec_helper'
describe 'CycleAnalytics#staging', feature: true do
extend CycleAnalyticsHelpers::TestGeneration
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:from_date) { 10.days.ago }
let(:user) { create(:user, :admin) }
subject { CycleAnalytics.new(project, from: from_date) }
generate_cycle_analytics_spec(
......
......@@ -3,7 +3,7 @@ require 'spec_helper'
describe 'CycleAnalytics#test', feature: true do
extend CycleAnalyticsHelpers::TestGeneration
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:from_date) { 10.days.ago }
let(:user) { create(:user, :admin) }
subject { CycleAnalytics.new(project, from: from_date) }
......
......@@ -12,7 +12,7 @@ describe DeployKeysProject, models: true do
end
describe "Destroying" do
let(:project) { create(:project) }
let(:project) { create(:empty_project) }
subject { create(:deploy_keys_project, project: project) }
let(:deploy_key) { subject.deploy_key }
......@@ -39,7 +39,7 @@ describe DeployKeysProject, models: true do
end
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
other_project.deploy_keys << deploy_key
......
......@@ -17,7 +17,7 @@ describe Deployment, models: true do
it { is_expected.to validate_presence_of(:sha) }
describe '#includes_commit?' do
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:environment) { create(:environment, project: project) }
let(:deployment) do
create(:deployment, environment: environment, sha: project.commit.id)
......
......@@ -3,8 +3,8 @@ require 'spec_helper'
describe DiffNote, models: true do
include RepoHelpers
let(:project) { create(:project) }
let(:merge_request) { create(:merge_request, source_project: project) }
let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.project }
let(:commit) { project.commit(sample_commit.id) }
let(:path) { "files/ruby/popen.rb" }
......
......@@ -32,7 +32,7 @@ describe Environment, models: true do
end
describe '#includes_commit?' do
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
context 'without a last deployment' do
it "returns false" do
......@@ -81,7 +81,7 @@ describe Environment, models: true do
end
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!(:deployment1) { create(:deployment, environment: environment, ref: commit.id) }
let(:head_commit) { project.commit }
......
......@@ -27,7 +27,7 @@ describe Event, models: true do
end
describe "Push event" do
let(:project) { create(:project, :private) }
let(:project) { create(:empty_project, :private) }
let(:user) { project.owner }
let(:event) { create_event(project, user) }
......@@ -187,7 +187,7 @@ describe Event, models: true do
end
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(:note_on_merge_request) { create(:legacy_diff_note_on_merge_request, noteable: merge_request, project: project) }
let(:target) { note_on_merge_request }
......@@ -202,7 +202,7 @@ describe Event, models: true do
end
context 'private project' do
let(:project) { create(:project, :private) }
let(:project) { create(:empty_project, :private) }
it do
expect(event.visible_to_user?(non_member)).to eq false
......
require 'spec_helper'
describe ForkedProjectLink, "add link on fork" do
let(:project_from) { create(:project) }
let(:project_from) { create(:project, :repository) }
let(:namespace) { create(:namespace) }
let(:user) { create(:user, namespace: namespace) }
......@@ -21,7 +21,7 @@ end
describe '#forked?' do
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) }
before :each do
......
......@@ -4,9 +4,9 @@ describe GlobalMilestone, models: true do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:group) { create(:group) }
let(:project1) { create(:project, group: group) }
let(:project2) { create(:project, path: 'gitlab-ci', group: group) }
let(:project3) { create(:project, path: 'cookbook-gitlab', group: group) }
let(:project1) { create(:empty_project, group: group) }
let(:project2) { create(:empty_project, path: 'gitlab-ci', group: group) }
let(:project3) { create(:empty_project, path: 'cookbook-gitlab', group: group) }
describe '.build_collection' do
let(:milestone1_due_date) { 2.weeks.from_now.to_date }
......
......@@ -2,7 +2,7 @@ require 'spec_helper'
describe GroupMilestone, models: true do
let(:group) { create(:group) }
let(:project) { create(:project, group: group) }
let(:project) { create(:empty_project, group: group) }
let(:project_milestone) do
create(:milestone, title: "Milestone v1.2", project: project)
end
......
require 'spec_helper'
describe Guest, lib: true do
let(:public_project) { create(:project, :public) }
let(:private_project) { create(:project, :private) }
let(:internal_project) { create(:project, :internal) }
let(:public_project) { build_stubbed(:empty_project, :public) }
let(:private_project) { build_stubbed(:empty_project, :private) }
let(:internal_project) { build_stubbed(:empty_project, :internal) }
describe '.can_pull?' do
context 'when project is private' do
......
......@@ -4,7 +4,7 @@ describe SystemHook, models: true do
describe "execute" do
let(:system_hook) { create(:system_hook) }
let(:user) { create(:user) }
let(:project) { create(:project, namespace: user.namespace) }
let(:project) { create(:empty_project, namespace: user.namespace) }
let(:group) { create(:group) }
before do
......
......@@ -25,7 +25,7 @@ describe WebHook, models: true do
end
describe "execute" do
let(:project) { create(:project) }
let(:project) { create(:empty_project) }
let(:project_hook) { create(:project_hook) }
before(:each) do
......
require 'spec_helper'
describe Issue::Metrics, models: true do
let(:project) { create(:project) }
let(:project) { create(:empty_project) }
subject { create(:issue, project: project) }
......
......@@ -2,7 +2,7 @@ require 'spec_helper'
describe IssueCollection do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:project) { create(:empty_project) }
let(:issue1) { create(:issue, project: project) }
let(:issue2) { create(:issue, project: project) }
let(:collection) { described_class.new([issue1, issue2]) }
......
......@@ -35,7 +35,7 @@ describe Issue, models: true do
end
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"
end
end
......@@ -60,9 +60,9 @@ describe Issue, models: true do
end
describe '#closed_by_merge_requests' do
let(:project) { create(:project) }
let(:issue) { create(:issue, project: project, state: "opened")}
let(:closed_issue) { build(:issue, project: project, state: "closed")}
let(:project) { create(:project, :repository) }
let(:issue) { create(:issue, project: project)}
let(:closed_issue) { build(:issue, :closed, project: project)}
let(:mr) do
opts = {
......@@ -104,7 +104,7 @@ describe Issue, models: true do
describe '#referenced_merge_requests' do
it 'returns the referenced merge requests' do
project = create(:project, :public)
project = create(:empty_project, :public)
mr1 = create(:merge_request,
source_project: project,
......@@ -137,7 +137,7 @@ describe Issue, models: true do
end
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) }
before { project.team << [user, :reporter] }
......@@ -151,7 +151,7 @@ describe Issue, models: true do
context 'checking destination project also' do
subject { issue.can_move?(user, to_project) }
let(:to_project) { create(:project) }
let(:to_project) { create(:empty_project) }
context 'destination project allowed' do
before { to_project.team << [user, :reporter] }
......@@ -246,7 +246,7 @@ describe Issue, models: true do
describe '#participants' 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!(:note1) do
......@@ -268,7 +268,7 @@ describe Issue, models: true do
context 'using a private 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)
issue = create(:issue, project: project)
......
......@@ -481,7 +481,7 @@ describe Member, models: true do
describe "destroying a record", truncate: true do
it "refreshes user's authorized projects" do
project = create(:project, :private)
project = create(:empty_project, :private)
user = create(:user)
member = project.team << [user, :reporter]
......
......@@ -83,8 +83,8 @@ describe ProjectMember, models: true do
describe '.import_team' do
before do
@project_1 = create :project
@project_2 = create :project
@project_1 = create(:empty_project)
@project_2 = create(:empty_project)
@user_1 = create :user
@user_2 = create :user
......@@ -131,8 +131,8 @@ describe ProjectMember, models: true do
describe '.truncate_teams' do
before do
@project_1 = create :project
@project_2 = create :project
@project_1 = create(:empty_project)
@project_2 = create(:empty_project)
@user_1 = create :user
@user_2 = create :user
......
require 'spec_helper'
describe MergeRequest::Metrics, models: true do
let(:project) { create(:project) }
subject { create(:merge_request, source_project: project) }
subject { create(:merge_request) }
describe "when recording the default set of metrics on merge request save" do
it "records the merge time" do
......
......@@ -24,7 +24,7 @@ describe Milestone, models: true do
it { is_expected.to have_many(:issues) }
end
let(:project) { create(:project, :public) }
let(:project) { create(:empty_project, :public) }
let(:milestone) { create(:milestone, project: project) }
let(:issue) { create(:issue, project: project) }
let(:user) { create(:user) }
......@@ -44,7 +44,7 @@ describe Milestone, models: true do
end
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)
expect(new_milestone).to be_valid
......@@ -257,7 +257,7 @@ describe Milestone, models: true do
end
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"
end
end
......
......@@ -107,7 +107,7 @@ describe Namespace, models: true do
describe '#move_dir' do
before do
@namespace = create :namespace
@project = create :project, namespace: @namespace
@project = create(:empty_project, namespace: @namespace)
allow(@namespace).to receive(:path_changed?).and_return(true)
end
......@@ -151,7 +151,7 @@ describe Namespace, models: true do
end
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) }
it "removes its dirs when deleted" do
......
require 'spec_helper'
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) }
it '#initialize' do
......
......@@ -42,7 +42,7 @@ describe Note, models: true do
context 'when noteable and note project differ' do
subject do
build(:note, noteable: build_stubbed(:issue),
project: build_stubbed(:project))
project: build_stubbed(:empty_project))
end
it { is_expected.to be_invalid }
......@@ -93,8 +93,8 @@ describe Note, models: true do
describe 'authorization' do
before do
@p1 = create(:project)
@p2 = create(:project)
@p1 = create(:empty_project)
@p2 = create(:empty_project)
@u1 = create(:user)
@u2 = create(:user)
@u3 = create(:user)
......@@ -191,10 +191,10 @@ describe Note, models: true do
describe "cross_reference_not_visible_for?" do
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(:ext_proj) { create(:project, :public) }
let(:ext_proj) { create(:empty_project, :public) }
let(:ext_issue) { create(:issue, project: ext_proj) }
let(:note) do
......@@ -237,7 +237,7 @@ describe Note, models: true do
describe '#participants' do
it 'includes the note author' do
project = create(:project, :public)
project = create(:empty_project, :public)
issue = create(:issue, project: project)
note = create(:note_on_issue, noteable: issue, project: project)
......
require 'spec_helper'
describe ProjectFeature do
let(:project) { create(:project) }
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
describe '#feature_available?' do
......@@ -35,7 +35,7 @@ describe ProjectFeature do
it "returns true when user is a member of project group" do
group = create(:group)
project = create(:project, namespace: group)
project = create(:empty_project, namespace: group)
group.add_developer(user)
features.each do |feature|
......
......@@ -17,7 +17,7 @@ describe ProjectGroupLink do
describe "destroying a record", truncate: true do
it "refreshes group users' authorized projects" do
project = create(:project, :private)
project = create(:empty_project, :private)
group = create(:group)
reporter = create(:user)
group_users = group.users
......
......@@ -100,7 +100,7 @@ describe ProjectLabel, models: true do
end
context 'cross project reference' do
let(:project) { create(:project) }
let(:project) { create(:empty_project) }
context 'using name' do
it 'returns cross reference with label name' do
......
......@@ -18,7 +18,7 @@ describe AsanaService, models: true do
describe 'Execute' do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:project) { create(:empty_project) }
def create_data_for_commits(*messages)
{
......
......@@ -8,7 +8,7 @@ describe AssemblaService, models: true do
describe "Execute" do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
before do
@assembla_service = AssemblaService.new
......
......@@ -22,7 +22,7 @@ describe CampfireService, models: true do
describe "#execute" do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
before do
@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