Commit 19246b14 authored by Nick Thomas's avatar Nick Thomas

Branch merge

parents 5f47d815 a5cd9c9a
...@@ -20,6 +20,8 @@ variables: ...@@ -20,6 +20,8 @@ variables:
before_script: before_script:
- source ./scripts/prepare_build.sh - source ./scripts/prepare_build.sh
- cp config/gitlab.yml.example config/gitlab.yml - cp config/gitlab.yml.example config/gitlab.yml
- mkdir -p tmp/tests
- mount -t tmpfs tmpfs tmp/tests || echo "tmpfs mount failed, falling back to disc"
- bundle --version - bundle --version
- '[ "$USE_BUNDLE_INSTALL" != "true" ] || retry bundle install --without postgres production --jobs $(nproc) "${FLAGS[@]}"' - '[ "$USE_BUNDLE_INSTALL" != "true" ] || retry bundle install --without postgres production --jobs $(nproc) "${FLAGS[@]}"'
- retry gem install knapsack - retry gem install knapsack
......
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
v 8.13.0 (unreleased) v 8.13.0 (unreleased)
- Truncate long labels with ellipsis in labels page
- Update runner version only when updating contacted_at - Update runner version only when updating contacted_at
- Add link from system note to compare with previous version - Add link from system note to compare with previous version
- Improve issue load time performance by avoiding ORDER BY in find_by call - Improve issue load time performance by avoiding ORDER BY in find_by call
- Use gitlab-shell v3.6.2 (GIT TRACE logging) - Use gitlab-shell v3.6.2 (GIT TRACE logging)
- Add `/projects/visible` API endpoint (Ben Boeckel)
- Fix centering of custom header logos (Ashley Dumaine) - Fix centering of custom header logos (Ashley Dumaine)
- ExpireBuildArtifactsWorker query builds table without ordering enqueuing one job per build to cleanup
- AbstractReferenceFilter caches project_refs on RequestStore when active - AbstractReferenceFilter caches project_refs on RequestStore when active
- Replaced the check sign to arrow in the show build view. !6501 - Replaced the check sign to arrow in the show build view. !6501
- Add a /wip slash command to toggle the Work In Progress status of a merge request. !6259 (tbalthazar) - Add a /wip slash command to toggle the Work In Progress status of a merge request. !6259 (tbalthazar)
...@@ -15,6 +18,7 @@ v 8.13.0 (unreleased) ...@@ -15,6 +18,7 @@ v 8.13.0 (unreleased)
- Keep refs for each deployment - Keep refs for each deployment
- Log LDAP lookup errors and don't swallow unrelated exceptions. !6103 (Markus Koller) - Log LDAP lookup errors and don't swallow unrelated exceptions. !6103 (Markus Koller)
- Add more tests for calendar contribution (ClemMakesApps) - Add more tests for calendar contribution (ClemMakesApps)
- Update Gitlab Shell to fix some problems with moving projects between storages
- Cache rendered markdown in the database, rather than Redis - Cache rendered markdown in the database, rather than Redis
- Avoid database queries on Banzai::ReferenceParser::BaseParser for nodes without references - Avoid database queries on Banzai::ReferenceParser::BaseParser for nodes without references
- Simplify Mentionable concern instance methods - Simplify Mentionable concern instance methods
...@@ -28,6 +32,7 @@ v 8.13.0 (unreleased) ...@@ -28,6 +32,7 @@ v 8.13.0 (unreleased)
- Allow the Koding integration to be configured through the API - Allow the Koding integration to be configured through the API
- Add new issue button to each list on Issues Board - Add new issue button to each list on Issues Board
- Added soft wrap button to repository file/blob editor - Added soft wrap button to repository file/blob editor
- Update namespace validation to forbid reserved names (.git and .atom) (Will Starms)
- Add word-wrap to issue title on issue and milestone boards (ClemMakesApps) - Add word-wrap to issue title on issue and milestone boards (ClemMakesApps)
- Fix todos page mobile viewport layout (ClemMakesApps) - Fix todos page mobile viewport layout (ClemMakesApps)
- Fix inconsistent highlighting of already selected activity nav-links (ClemMakesApps) - Fix inconsistent highlighting of already selected activity nav-links (ClemMakesApps)
...@@ -35,6 +40,7 @@ v 8.13.0 (unreleased) ...@@ -35,6 +40,7 @@ v 8.13.0 (unreleased)
- Close open merge request without source project (Katarzyna Kobierska Ula Budziszewska) - Close open merge request without source project (Katarzyna Kobierska Ula Budziszewska)
- Fix that manual jobs would no longer block jobs in the next stage. !6604 - Fix that manual jobs would no longer block jobs in the next stage. !6604
- Add configurable email subject suffix (Fu Xu) - Add configurable email subject suffix (Fu Xu)
- Added tooltip to fork count on project show page. (Justin DiPierro)
- Use a ConnectionPool for Rails.cache on Sidekiq servers - Use a ConnectionPool for Rails.cache on Sidekiq servers
- Replace `alias_method_chain` with `Module#prepend` - Replace `alias_method_chain` with `Module#prepend`
- Enable GitLab Import/Export for non-admin users. - Enable GitLab Import/Export for non-admin users.
...@@ -46,6 +52,7 @@ v 8.13.0 (unreleased) ...@@ -46,6 +52,7 @@ v 8.13.0 (unreleased)
- Prevent flash alert text from being obscured when container is fluid - Prevent flash alert text from being obscured when container is fluid
- Append issue template to existing description !6149 (Joseph Frazier) - Append issue template to existing description !6149 (Joseph Frazier)
- Trending projects now only show public projects and the list of projects is cached for a day - Trending projects now only show public projects and the list of projects is cached for a day
- Memoize Gitlab Shell's secret token (!6599, Justin DiPierro)
- Revoke button in Applications Settings underlines on hover. - Revoke button in Applications Settings underlines on hover.
- Use higher size on Gitlab::Redis connection pool on Sidekiq servers - Use higher size on Gitlab::Redis connection pool on Sidekiq servers
- Add missing values to linter !6276 (Katarzyna Kobierska Ula Budziszewska) - Add missing values to linter !6276 (Katarzyna Kobierska Ula Budziszewska)
...@@ -58,19 +65,25 @@ v 8.13.0 (unreleased) ...@@ -58,19 +65,25 @@ v 8.13.0 (unreleased)
- Replace bootstrap caret with fontawesome caret (ClemMakesApps) - Replace bootstrap caret with fontawesome caret (ClemMakesApps)
- Fix unnecessary escaping of reserved HTML characters in milestone title. !6533 - Fix unnecessary escaping of reserved HTML characters in milestone title. !6533
- Add organization field to user profile - Add organization field to user profile
- Fix enter key when navigating search site search dropdown. !6643 (Brennan Roberts)
- Fix deploy status responsiveness error !6633 - Fix deploy status responsiveness error !6633
- Make searching for commits case insensitive
- Fix resolved discussion display in side-by-side diff view !6575 - Fix resolved discussion display in side-by-side diff view !6575
- Optimize GitHub importing for speed and memory - Optimize GitHub importing for speed and memory
- API: expose pipeline data in builds API (!6502, Guilherme Salazar) - API: expose pipeline data in builds API (!6502, Guilherme Salazar)
- Notify the Merger about merge after successful build (Dimitris Karakasilis) - Notify the Merger about merge after successful build (Dimitris Karakasilis)
- Reorder issue and merge request titles to show IDs first. !6503 (Greg Laubenstein)
- Reduce queries needed to find users using their SSH keys when pushing commits - Reduce queries needed to find users using their SSH keys when pushing commits
- Prevent rendering the link to all when the author has no access (Katarzyna Kobierska Ula Budziszewska) - Prevent rendering the link to all when the author has no access (Katarzyna Kobierska Ula Budziszewska)
- Fix broken repository 500 errors in project list - Fix broken repository 500 errors in project list
- Fix Pipeline list commit column width should be adjusted - Fix Pipeline list commit column width should be adjusted
- Close todos when accepting merge requests via the API !6486 (tonygambone) - Close todos when accepting merge requests via the API !6486 (tonygambone)
- Changed Slack service user referencing from full name to username (Sebastian Poxhofer) - Changed Slack service user referencing from full name to username (Sebastian Poxhofer)
- Retouch environments list and deployments list
- Add Container Registry on/off status to Admin Area !6638 (the-undefined) - Add Container Registry on/off status to Admin Area !6638 (the-undefined)
- Grouped pipeline dropdown is a scrollable container - Grouped pipeline dropdown is a scrollable container
- Cleanup Ci::ApplicationController. !6757 (Takuya Noguchi)
- Fix a typo in doc/api/labels.md
v 8.12.5 (unreleased) v 8.12.5 (unreleased)
...@@ -108,6 +121,7 @@ v 8.12.2 ...@@ -108,6 +121,7 @@ v 8.12.2
- Fix bug where 'Search results' repeated many times when a search in the emoji search form is cleared (Xavier Bick) (@zeiv) - Fix bug where 'Search results' repeated many times when a search in the emoji search form is cleared (Xavier Bick) (@zeiv)
- Fix resolve discussion buttons endpoint path - Fix resolve discussion buttons endpoint path
- Refactor remnants of CoffeeScript destructured opts and super !6261 - Refactor remnants of CoffeeScript destructured opts and super !6261
- Prevent running GfmAutocomplete setup for each diff note !6569
v 8.12.1 v 8.12.1
- Fix a memory leak in HTML::Pipeline::SanitizationFilter::WHITELIST - Fix a memory leak in HTML::Pipeline::SanitizationFilter::WHITELIST
...@@ -311,6 +325,7 @@ v 8.11.7 ...@@ -311,6 +325,7 @@ v 8.11.7
- Avoid conflict with admin labels when importing GitHub labels. !6158 - Avoid conflict with admin labels when importing GitHub labels. !6158
- Restores `fieldName` to allow only string values in `gl_dropdown.js`. !6234 - Restores `fieldName` to allow only string values in `gl_dropdown.js`. !6234
- Allow the Rails cookie to be used for API authentication. - Allow the Rails cookie to be used for API authentication.
- Updating verbiage on git basics to be more intuitive
v 8.11.6 v 8.11.6
- Fix unnecessary horizontal scroll area in pipeline visualizations. !6005 - Fix unnecessary horizontal scroll area in pipeline visualizations. !6005
...@@ -471,6 +486,7 @@ v 8.11.0 ...@@ -471,6 +486,7 @@ v 8.11.0
- Add pipeline events hook - Add pipeline events hook
- Bump gitlab_git to speedup DiffCollection iterations - Bump gitlab_git to speedup DiffCollection iterations
- Rewrite description of a blocked user in admin settings. (Elias Werberich) - Rewrite description of a blocked user in admin settings. (Elias Werberich)
- Clarify documentation for Runners API (Gennady Trafimenkov)
- Make branches sortable without push permission !5462 (winniehell) - Make branches sortable without push permission !5462 (winniehell)
- Check for Ci::Build artifacts at database level on pipeline partial - Check for Ci::Build artifacts at database level on pipeline partial
- Convert image diff background image to CSS (ClemMakesApps) - Convert image diff background image to CSS (ClemMakesApps)
......
...@@ -226,8 +226,7 @@ a feedback issue (if there isn't one already) and leave a comment asking for it ...@@ -226,8 +226,7 @@ a feedback issue (if there isn't one already) and leave a comment asking for it
to be marked as `Accepting merge requests`. Please include screenshots or to be marked as `Accepting merge requests`. Please include screenshots or
wireframes if the feature will also change the UI. wireframes if the feature will also change the UI.
Merge requests can be filed either at [GitLab.com][gitlab-mr-tracker] or at Merge requests should be opened at [GitLab.com][gitlab-mr-tracker].
[github.com][github-mr-tracker].
If you are new to GitLab development (or web development in general), see the If you are new to GitLab development (or web development in general), see the
[I want to contribute!](#i-want-to-contribute) section to get you started with [I want to contribute!](#i-want-to-contribute) section to get you started with
...@@ -246,10 +245,17 @@ tests are least likely to receive timely feedback. The workflow to make a merge ...@@ -246,10 +245,17 @@ tests are least likely to receive timely feedback. The workflow to make a merge
request is as follows: request is as follows:
1. Fork the project into your personal space on GitLab.com 1. Fork the project into your personal space on GitLab.com
1. Create a feature branch, branch away from `master`. 1. Create a feature branch, branch away from `master`
1. Write [tests](https://gitlab.com/gitlab-org/gitlab-development-kit#running-the-tests) and code 1. Write [tests](https://gitlab.com/gitlab-org/gitlab-development-kit#running-the-tests) and code
1. Add your changes to the [CHANGELOG](CHANGELOG) 1. Add your changes to the [CHANGELOG](CHANGELOG):
1. If you are writing documentation, make sure to read the [documentation styleguide][doc-styleguide] 1. If you are fixing a ~regression issue, you can add your entry to the next
patch release (e.g. `8.12.5` if current version is `8.12.4`)
1. Otherwise, add your entry to the next minor release (e.g. `8.13.0` if
current version is `8.12.4`
1. Please add your entry at a random place among the entries of the targeted
release
1. If you are writing documentation, make sure to follow the
[documentation styleguide][doc-styleguide]
1. If you have multiple commits please combine them into one commit by 1. If you have multiple commits please combine them into one commit by
[squashing them][git-squash] [squashing them][git-squash]
1. Push the commit(s) to your fork 1. Push the commit(s) to your fork
...@@ -258,7 +264,7 @@ request is as follows: ...@@ -258,7 +264,7 @@ request is as follows:
1. The MR description should give a motive for your change and the method you 1. The MR description should give a motive for your change and the method you
used to achieve it, see the [merge request description format] used to achieve it, see the [merge request description format]
(#merge-request-description-format) (#merge-request-description-format)
1. If the MR changes the UI it should include before and after screenshots 1. If the MR changes the UI it should include *Before* and *After* screenshots
1. If the MR changes CSS classes please include the list of affected pages, 1. If the MR changes CSS classes please include the list of affected pages,
`grep css-class ./app -R` `grep css-class ./app -R`
1. Link any relevant [issues][ce-tracker] in the merge request description and 1. Link any relevant [issues][ce-tracker] in the merge request description and
...@@ -270,7 +276,9 @@ request is as follows: ...@@ -270,7 +276,9 @@ request is as follows:
[shell command guidelines](doc/development/shell_commands.md) [shell command guidelines](doc/development/shell_commands.md)
1. If your code creates new files on disk please read the 1. If your code creates new files on disk please read the
[shared files guidelines](doc/development/shared_files.md). [shared files guidelines](doc/development/shared_files.md).
1. When writing commit messages please follow [these](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) [guidelines](http://chris.beams.io/posts/git-commit/). 1. When writing commit messages please follow
[these](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
[guidelines](http://chris.beams.io/posts/git-commit/).
1. If your merge request adds one or more migrations, make sure to execute all 1. If your merge request adds one or more migrations, make sure to execute all
migrations on a fresh database before the MR is reviewed. If the review leads migrations on a fresh database before the MR is reviewed. If the review leads
to large changes in the MR, do this again once the review is complete. to large changes in the MR, do this again once the review is complete.
...@@ -305,23 +313,6 @@ Please ensure that your merge request meets the contribution acceptance criteria ...@@ -305,23 +313,6 @@ Please ensure that your merge request meets the contribution acceptance criteria
When having your code reviewed and when reviewing merge requests please take the When having your code reviewed and when reviewing merge requests please take the
[code review guidelines](doc/development/code_review.md) into account. [code review guidelines](doc/development/code_review.md) into account.
### Merge request description format
Please submit merge requests using the following template in the merge request
description area. Copy-paste it to retain the markdown format.
```
## What does this MR do?
## Are there points in the code the reviewer needs to double check?
## Why was this MR needed?
## What are the relevant issue numbers?
## Screenshots (if relevant)
```
### Contribution acceptance criteria ### Contribution acceptance criteria
1. The change is as small as possible 1. The change is as small as possible
...@@ -333,8 +324,8 @@ description area. Copy-paste it to retain the markdown format. ...@@ -333,8 +324,8 @@ description area. Copy-paste it to retain the markdown format.
aforementioned failing test aforementioned failing test
1. Your MR initially contains a single commit (please use `git rebase -i` to 1. Your MR initially contains a single commit (please use `git rebase -i` to
squash commits) squash commits)
1. Your changes can merge without problems (if not please merge `master`, never 1. Your changes can merge without problems (if not please rebase if you're the
rebase commits pushed to the remote server) only one working on your feature branch, otherwise, merge `master`)
1. Does not break any existing functionality 1. Does not break any existing functionality
1. Fixes one specific issue or implements one specific feature (do not combine 1. Fixes one specific issue or implements one specific feature (do not combine
things, send separate merge requests if needed) things, send separate merge requests if needed)
...@@ -352,7 +343,10 @@ description area. Copy-paste it to retain the markdown format. ...@@ -352,7 +343,10 @@ description area. Copy-paste it to retain the markdown format.
entire line to follow it. This prevents linting tools from generating warnings. entire line to follow it. This prevents linting tools from generating warnings.
- Don't touch neighbouring lines. As an exception, automatic mass - Don't touch neighbouring lines. As an exception, automatic mass
refactoring modifications may leave style non-compliant. refactoring modifications may leave style non-compliant.
1. If the merge request adds any new libraries (gems, JavaScript libraries, etc.), they should conform to our [Licensing guidelines][license-finder-doc]. See the instructions in that document for help if your MR fails the "license-finder" test with a "Dependencies that need approval" error. 1. If the merge request adds any new libraries (gems, JavaScript libraries,
etc.), they should conform to our [Licensing guidelines][license-finder-doc].
See the instructions in that document for help if your MR fails the
"license-finder" test with a "Dependencies that need approval" error.
## Changes for Stable Releases ## Changes for Stable Releases
...@@ -468,7 +462,6 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor ...@@ -468,7 +462,6 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[accepting-mrs-ce]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=Accepting+Merge+Requests [accepting-mrs-ce]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=Accepting+Merge+Requests
[accepting-mrs-ee]: https://gitlab.com/gitlab-org/gitlab-ee/issues?label_name=Accepting+Merge+Requests [accepting-mrs-ee]: https://gitlab.com/gitlab-org/gitlab-ee/issues?label_name=Accepting+Merge+Requests
[gitlab-mr-tracker]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests [gitlab-mr-tracker]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests
[github-mr-tracker]: https://github.com/gitlabhq/gitlabhq/pulls
[gdk]: https://gitlab.com/gitlab-org/gitlab-development-kit [gdk]: https://gitlab.com/gitlab-org/gitlab-development-kit
[git-squash]: https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits [git-squash]: https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits
[closed-merge-requests]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests?assignee_id=&label_name=&milestone_id=&scope=&sort=&state=closed [closed-merge-requests]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests?assignee_id=&label_name=&milestone_id=&scope=&sort=&state=closed
......
# GitLab # GitLab
[![build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master) [![Build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master)
[![coverage report](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/coverage.svg?job=coverage)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master) [![CE coverage report](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/coverage.svg?job=coverage)](http://gitlab-org.gitlab.io/gitlab-ce/coverage-ruby)
[![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq) [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq)
[![Core Infrastructure Initiative Best Practices](https://bestpractices.coreinfrastructure.org/projects/42/badge)](https://bestpractices.coreinfrastructure.org/projects/42) [![Core Infrastructure Initiative Best Practices](https://bestpractices.coreinfrastructure.org/projects/42/badge)](https://bestpractices.coreinfrastructure.org/projects/42)
......
...@@ -52,37 +52,27 @@ ...@@ -52,37 +52,27 @@
} }
} }
}, },
setup: function(input) { setup: _.debounce(function(input) {
// Add GFM auto-completion to all input fields, that accept GFM input. // Add GFM auto-completion to all input fields, that accept GFM input.
this.input = input || $('.js-gfm-input'); this.input = input || $('.js-gfm-input');
// destroy previous instances // destroy previous instances
this.destroyAtWho(); this.destroyAtWho();
// set up instances // set up instances
this.setupAtWho(); this.setupAtWho();
if (this.dataSource) {
if (!this.dataLoading && !this.cachedData) { if (this.dataSource && !this.dataLoading && !this.cachedData) {
this.dataLoading = true; this.dataLoading = true;
setTimeout((function(_this) { return this.fetchData(this.dataSource)
return function() { .done((data) => {
var fetch; this.dataLoading = false;
fetch = _this.fetchData(_this.dataSource); this.loadData(data);
return fetch.done(function(data) { });
_this.dataLoading = false; };
return _this.loadData(data);
}); if (this.cachedData != null) {
}; return this.loadData(this.cachedData);
// We should wait until initializations are done
// and only trigger the last .setup since
// The previous .dataSource belongs to the previous issuable
// and the last one will have the **proper** .dataSource property
// TODO: Make this a singleton and turn off events when moving to another page
})(this), 1000);
}
if (this.cachedData != null) {
return this.loadData(this.cachedData);
}
} }
}, }, 1000),
setupAtWho: function() { setupAtWho: function() {
// Emoji // Emoji
this.input.atwho({ this.input.atwho({
......
...@@ -738,6 +738,7 @@ ...@@ -738,6 +738,7 @@
return false; return false;
} }
if (currentKeyCode === 13 && currentIndex !== -1) { if (currentKeyCode === 13 && currentIndex !== -1) {
e.preventDefault();
_this.selectRowAtIndex(); _this.selectRowAtIndex();
} }
}; };
......
.environments-container,
.deployments-container {
width: 100%;
overflow: auto;
}
.environments { .environments {
.deployment-column {
.avatar {
float: none;
}
}
.commit-title { .commit-title {
margin: 0; margin: 0;
...@@ -9,6 +20,7 @@ ...@@ -9,6 +20,7 @@
width: 12px; width: 12px;
} }
.external-url,
.dropdown-new { .dropdown-new {
color: $table-text-gray; color: $table-text-gray;
} }
...@@ -21,16 +33,35 @@ ...@@ -21,16 +33,35 @@
} }
} }
.build-link,
.branch-name { .branch-name {
color: $gl-dark-link-color; color: $gl-dark-link-color;
} }
.deployment {
.build-column {
.build-link {
color: $gl-dark-link-color;
}
.avatar {
float: none;
}
}
}
} }
.table.builds.environments { .table.builds.environments {
min-width: 500px;
.icon-container { .icon-container {
width: 20px; width: 20px;
text-align: center; text-align: center;
} }
.branch-commit {
.commit-id {
margin-right: 0;
}
}
} }
...@@ -59,6 +59,13 @@ ...@@ -59,6 +59,13 @@
width: 200px; width: 200px;
margin-bottom: 0; margin-bottom: 0;
} }
.label {
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
max-width: 100%;
}
} }
.label-description { .label-description {
......
module Ci
class ApplicationController < ::ApplicationController
def self.railtie_helpers_paths
"app/helpers/ci"
end
end
end
module Ci module Ci
class LintsController < ApplicationController class LintsController < ::ApplicationController
before_action :authenticate_user! before_action :authenticate_user!
def show def show
......
module Ci module Ci
class ProjectsController < Ci::ApplicationController class ProjectsController < ::ApplicationController
before_action :project before_action :project
before_action :no_cache, only: [:badge] before_action :no_cache, only: [:badge]
before_action :authorize_read_project!, except: [:badge, :index] before_action :authorize_read_project!, except: [:badge, :index]
......
...@@ -4,15 +4,18 @@ module AvatarsHelper ...@@ -4,15 +4,18 @@ module AvatarsHelper
user: commit_or_event.author, user: commit_or_event.author,
user_name: commit_or_event.author_name, user_name: commit_or_event.author_name,
user_email: commit_or_event.author_email, user_email: commit_or_event.author_email,
css_class: 'hidden-xs'
})) }))
end end
def user_avatar(options = {}) def user_avatar(options = {})
avatar_size = options[:size] || 16 avatar_size = options[:size] || 16
user_name = options[:user].try(:name) || options[:user_name] user_name = options[:user].try(:name) || options[:user_name]
css_class = options[:css_class] || ''
avatar = image_tag( avatar = image_tag(
avatar_icon(options[:user] || options[:user_email], avatar_size), avatar_icon(options[:user] || options[:user_email], avatar_size),
class: "avatar has-tooltip hidden-xs s#{avatar_size}", class: "avatar has-tooltip s#{avatar_size} #{css_class}",
alt: "#{user_name}'s avatar", alt: "#{user_name}'s avatar",
title: user_name, title: user_name,
data: { container: 'body' } data: { container: 'body' }
......
...@@ -113,14 +113,13 @@ module IssuesHelper ...@@ -113,14 +113,13 @@ module IssuesHelper
end end
end end
def award_user_list(awards, current_user) def award_user_list(awards, current_user, limit: 10)
names = awards.map do |award| names = awards.map do |award|
award.user == current_user ? 'You' : award.user.name award.user == current_user ? 'You' : award.user.name
end end
# Take first 9 OR current user + first 9
current_user_name = names.delete('You') current_user_name = names.delete('You')
names = names.first(9).insert(0, current_user_name).compact names = names.insert(0, current_user_name).compact.first(limit)
names << "#{awards.size - names.size} more." if awards.size > names.size names << "#{awards.size - names.size} more." if awards.size > names.size
......
class CommitStatus < ActiveRecord::Base class CommitStatus < ActiveRecord::Base
include HasStatus include HasStatus
include Importable include Importable
include AfterCommitQueue
self.table_name = 'ci_builds' self.table_name = 'ci_builds'
...@@ -85,25 +86,34 @@ class CommitStatus < ActiveRecord::Base ...@@ -85,25 +86,34 @@ class CommitStatus < ActiveRecord::Base
end end
after_transition do |commit_status, transition| after_transition do |commit_status, transition|
commit_status.pipeline.try do |pipeline| return if transition.loopback?
break if transition.loopback?
commit_status.run_after_commit do
if commit_status.complete? pipeline.try do |pipeline|
ProcessPipelineWorker.perform_async(pipeline.id) if complete?
ProcessPipelineWorker.perform_async(pipeline.id)
else
UpdatePipelineWorker.perform_async(pipeline.id)
end
end end
UpdatePipelineWorker.perform_async(pipeline.id)
end end
true
end end
after_transition [:created, :pending, :running] => :success do |commit_status| after_transition [:created, :pending, :running] => :success do |commit_status|
MergeRequests::MergeWhenBuildSucceedsService.new(commit_status.pipeline.project, nil).trigger(commit_status) commit_status.run_after_commit do
# TODO, temporary fix for race condition
UpdatePipelineWorker.new.perform(pipeline.id)
MergeRequests::MergeWhenBuildSucceedsService
.new(pipeline.project, nil).trigger(self)
end
end end
after_transition any => :failed do |commit_status| after_transition any => :failed do |commit_status|
MergeRequests::AddTodoWhenBuildFailsService.new(commit_status.pipeline.project, nil).execute(commit_status) commit_status.run_after_commit do
MergeRequests::AddTodoWhenBuildFailsService
.new(pipeline.project, nil).execute(self)
end
end end
end end
......
...@@ -340,7 +340,7 @@ class Event < ActiveRecord::Base ...@@ -340,7 +340,7 @@ class Event < ActiveRecord::Base
# update the project. Only one query should actually perform the update, # update the project. Only one query should actually perform the update,
# hence we add the extra WHERE clause for last_activity_at. # hence we add the extra WHERE clause for last_activity_at.
Project.unscoped.where(id: project_id). Project.unscoped.where(id: project_id).
where('last_activity_at > ?', RESET_PROJECT_ACTIVITY_INTERVAL.ago). where('last_activity_at <= ?', RESET_PROJECT_ACTIVITY_INTERVAL.ago).
update_all(last_activity_at: created_at) update_all(last_activity_at: created_at)
end end
......
...@@ -61,15 +61,13 @@ class Namespace < ActiveRecord::Base ...@@ -61,15 +61,13 @@ class Namespace < ActiveRecord::Base
def clean_path(path) def clean_path(path)
path = path.dup path = path.dup
# Get the email username by removing everything after an `@` sign. # Get the email username by removing everything after an `@` sign.
path.gsub!(/@.*\z/, "") path.gsub!(/@.*\z/, "")
# Usernames can't end in .git, so remove it.
path.gsub!(/\.git\z/, "")
# Remove dashes at the start of the username.
path.gsub!(/\A-+/, "")
# Remove periods at the end of the username.
path.gsub!(/\.+\z/, "")
# Remove everything that's not in the list of allowed characters. # Remove everything that's not in the list of allowed characters.
path.gsub!(/[^a-zA-Z0-9_\-\.]/, "") path.gsub!(/[^a-zA-Z0-9_\-\.]/, "")
# Remove trailing violations ('.atom', '.git', or '.')
path.gsub!(/(\.atom|\.git|\.)*\z/, "")
# Remove leading violations ('-')
path.gsub!(/\A\-+/, "")
# Users with the great usernames of "." or ".." would end up with a blank username. # Users with the great usernames of "." or ".." would end up with a blank username.
# Work around that by setting their username to "blank", followed by a counter. # Work around that by setting their username to "blank", followed by a counter.
......
...@@ -122,8 +122,10 @@ class Repository ...@@ -122,8 +122,10 @@ class Repository
def find_commits_by_message(query, ref = nil, path = nil, limit = 1000, offset = 0) def find_commits_by_message(query, ref = nil, path = nil, limit = 1000, offset = 0)
ref ||= root_ref ref ||= root_ref
# Limited to 1000 commits for now, could be parameterized? args = %W(
args = %W(#{Gitlab.config.git.bin_path} log #{ref} --pretty=%H --skip #{offset} --max-count #{limit} --grep=#{query}) #{Gitlab.config.git.bin_path} log #{ref} --pretty=%H --skip #{offset}
--max-count #{limit} --grep=#{query} --regexp-ignore-case
)
args = args.concat(%W(-- #{path})) if path.present? args = args.concat(%W(-- #{path})) if path.present?
git_log_results = Gitlab::Popen.popen(args, path_to_repo).first.lines.map(&:chomp) git_log_results = Gitlab::Popen.popen(args, path_to_repo).first.lines.map(&:chomp)
......
...@@ -943,7 +943,7 @@ class User < ActiveRecord::Base ...@@ -943,7 +943,7 @@ class User < ActiveRecord::Base
if domain_matches?(allowed_domains, self.email) if domain_matches?(allowed_domains, self.email)
valid = true valid = true
else else
error = "is not whitelisted. Email domains valid for registration are: #{allowed_domains.join(', ')}" error = "domain is not authorized for sign-up"
valid = false valid = false
end end
end end
......
...@@ -101,7 +101,6 @@ class ProjectPolicy < BasePolicy ...@@ -101,7 +101,6 @@ class ProjectPolicy < BasePolicy
can! :admin_milestone can! :admin_milestone
can! :admin_project_snippet can! :admin_project_snippet
can! :admin_project_member can! :admin_project_member
can! :admin_merge_request
can! :admin_note can! :admin_note
can! :admin_wiki can! :admin_wiki
can! :admin_project can! :admin_project
...@@ -151,11 +150,18 @@ class ProjectPolicy < BasePolicy ...@@ -151,11 +150,18 @@ class ProjectPolicy < BasePolicy
def team_access!(user) def team_access!(user)
access = project.team.max_member_access(user.id) access = project.team.max_member_access(user.id)
guest_access! if access >= Gitlab::Access::GUEST return if access < Gitlab::Access::GUEST
reporter_access! if access >= Gitlab::Access::REPORTER guest_access!
team_member_reporter_access! if access >= Gitlab::Access::REPORTER
developer_access! if access >= Gitlab::Access::DEVELOPER return if access < Gitlab::Access::REPORTER
master_access! if access >= Gitlab::Access::MASTER reporter_access!
team_member_reporter_access!
return if access < Gitlab::Access::DEVELOPER
developer_access!
return if access < Gitlab::Access::MASTER
master_access!
end end
def archived_access! def archived_access!
......
...@@ -16,6 +16,8 @@ module Ci ...@@ -16,6 +16,8 @@ module Ci
process_stage(index) process_stage(index)
end end
@pipeline.update_status
# Return a flag if a when builds got enqueued # Return a flag if a when builds got enqueued
new_builds.flatten.any? new_builds.flatten.any?
end end
......
...@@ -128,7 +128,7 @@ ...@@ -128,7 +128,7 @@
- builds.select{|build| build.status == build_status}.each do |build| - builds.select{|build| build.status == build_status}.each do |build|
.build-job{class: ('active' if build == @build), data: {stage: build.stage}} .build-job{class: ('active' if build == @build), data: {stage: build.stage}}
= link_to namespace_project_build_path(@project.namespace, @project, build) do = link_to namespace_project_build_path(@project.namespace, @project, build) do
= icon('right-arrow') = icon('arrow-right')
= ci_icon_for_status(build.status) = ci_icon_for_status(build.status)
%span %span
- if build.name - if build.name
......
...@@ -5,10 +5,10 @@ ...@@ -5,10 +5,10 @@
= custom_icon('icon_fork') = custom_icon('icon_fork')
%span Fork %span Fork
- else - else
= link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork project", class: 'btn has-tooltip' do = link_to new_namespace_project_fork_path(@project.namespace, @project), title: 'Fork project', class: 'btn has-tooltip' do
= custom_icon('icon_fork') = custom_icon('icon_fork')
%span Fork %span Fork
%div.count-with-arrow %div.count-with-arrow
%span.arrow %span.arrow
= link_to namespace_project_forks_path(@project.namespace, @project), class: "count" do = link_to namespace_project_forks_path(@project.namespace, @project), title: 'Forks', class: 'count has-tooltip' do
= @project.forks_count = @project.forks_count
- if can?(current_user, :create_deployment, deployment) && deployment.deployable - if can?(current_user, :create_deployment, deployment) && deployment.deployable
.pull-right .pull-right
- external_url = deployment.environment.external_url
- if external_url
= link_to external_url, target: '_blank', class: 'btn external-url' do
= icon('external-link')
- actions = deployment.manual_actions - actions = deployment.manual_actions
- if actions.present? - if actions.present?
.inline .inline
......
...@@ -5,14 +5,16 @@ ...@@ -5,14 +5,16 @@
%td %td
= render 'projects/deployments/commit', deployment: deployment = render 'projects/deployments/commit', deployment: deployment
%td %td.build-column
- if deployment.deployable - if deployment.deployable
= link_to [@project.namespace.becomes(Namespace), @project, deployment.deployable] do = link_to [@project.namespace.becomes(Namespace), @project, deployment.deployable], class: 'build-link' do
= user_avatar(user: deployment.user, size: 20)
= "#{deployment.deployable.name} (##{deployment.deployable.id})" = "#{deployment.deployable.name} (##{deployment.deployable.id})"
- if deployment.user
by
= user_avatar(user: deployment.user, size: 20)
%td %td
#{time_ago_with_tooltip(deployment.created_at)} #{time_ago_with_tooltip(deployment.created_at)}
%td %td.hidden-xs
= render 'projects/deployments/actions', deployment: deployment, allow_rollback: true = render 'projects/deployments/actions', deployment: deployment, allow_rollback: true
...@@ -4,10 +4,17 @@ ...@@ -4,10 +4,17 @@
%td %td
= link_to environment.name, namespace_project_environment_path(@project.namespace, @project, environment) = link_to environment.name, namespace_project_environment_path(@project.namespace, @project, environment)
%td %td.deployment-column
- if last_deployment - if last_deployment
= user_avatar(user: last_deployment.user, size: 20) %span ##{last_deployment.iid}
%strong ##{last_deployment.id} - if last_deployment.user
by
= user_avatar(user: last_deployment.user, size: 20)
%td
- if last_deployment && last_deployment.deployable
= link_to [@project.namespace.becomes(Namespace), @project, last_deployment.deployable], class: 'build-link' do
= "#{last_deployment.deployable.name} (##{last_deployment.deployable.id})"
%td %td
- if last_deployment - if last_deployment
...@@ -20,5 +27,5 @@ ...@@ -20,5 +27,5 @@
- if last_deployment - if last_deployment
#{time_ago_with_tooltip(last_deployment.created_at)} #{time_ago_with_tooltip(last_deployment.created_at)}
%td %td.hidden-xs
= render 'projects/deployments/actions', deployment: last_deployment = render 'projects/deployments/actions', deployment: last_deployment
...@@ -9,25 +9,27 @@ ...@@ -9,25 +9,27 @@
= link_to new_namespace_project_environment_path(@project.namespace, @project), class: 'btn btn-create' do = link_to new_namespace_project_environment_path(@project.namespace, @project), class: 'btn btn-create' do
New environment New environment
- if @environments.blank? .environments-container
.blank-state.blank-state-no-icon - if @environments.blank?
%h2.blank-state-title .blank-state.blank-state-no-icon
You don't have any environments right now. %h2.blank-state-title
%p.blank-state-text You don't have any environments right now.
Environments are places where code gets deployed, such as staging or production. %p.blank-state-text
%br Environments are places where code gets deployed, such as staging or production.
= succeed "." do %br
= link_to "Read more about environments", help_page_path("ci/environments") = succeed "." do
- if can?(current_user, :create_environment, @project) = link_to "Read more about environments", help_page_path("ci/environments")
= link_to new_namespace_project_environment_path(@project.namespace, @project), class: 'btn btn-create' do - if can?(current_user, :create_environment, @project)
New environment = link_to new_namespace_project_environment_path(@project.namespace, @project), class: 'btn btn-create' do
- else New environment
.table-holder - else
%table.table.builds.environments .table-holder
%tbody %table.table.builds.environments
%th Environment %tbody
%th Last Deployment %th Environment
%th Commit %th Last Deployment
%th %th Build
%th %th Commit
= render @environments %th
%th.hidden-xs
= render @environments
...@@ -12,26 +12,27 @@ ...@@ -12,26 +12,27 @@
= link_to 'Edit', edit_namespace_project_environment_path(@project.namespace, @project, @environment), class: 'btn' = link_to 'Edit', edit_namespace_project_environment_path(@project.namespace, @project, @environment), class: 'btn'
= link_to 'Destroy', namespace_project_environment_path(@project.namespace, @project, @environment), data: { confirm: 'Are you sure you want to delete this environment?' }, class: 'btn btn-danger', method: :delete = link_to 'Destroy', namespace_project_environment_path(@project.namespace, @project, @environment), data: { confirm: 'Are you sure you want to delete this environment?' }, class: 'btn btn-danger', method: :delete
- if @deployments.blank? .deployments-container
.blank-state.blank-state-no-icon - if @deployments.blank?
%h2.blank-state-title .blank-state.blank-state-no-icon
You don't have any deployments right now. %h2.blank-state-title
%p.blank-state-text You don't have any deployments right now.
Define environments in the deploy stage(s) in %p.blank-state-text
%code .gitlab-ci.yml Define environments in the deploy stage(s) in
to track deployments here. %code .gitlab-ci.yml
= link_to "Read more", help_page_path("ci/environments"), class: "btn btn-success" to track deployments here.
- else = link_to "Read more", help_page_path("ci/environments"), class: "btn btn-success"
.table-holder - else
%table.table.builds.environments .table-holder
%thead %table.table.builds.environments
%tr %thead
%th ID %tr
%th Commit %th ID
%th Build %th Commit
%th %th Build
%th %th
%th.hidden-xs
= render @deployments = render @deployments
= paginate @deployments, theme: 'gitlab' = paginate @deployments, theme: 'gitlab'
- page_title "Edit", "#{@issue.title} (##{@issue.iid})", "Issues" - page_title "Edit", "#{@issue.to_reference} #{@issue.title}", "Issues"
%h3.page-title %h3.page-title
Edit Issue ##{@issue.iid} Edit Issue ##{@issue.iid}
......
- page_title "#{@issue.title} (##{@issue.iid})", "Issues" - page_title "#{@issue.to_reference} #{@issue.title}", "Issues"
- page_description @issue.description - page_description @issue.description
- page_card_attributes @issue.card_attributes - page_card_attributes @issue.card_attributes
......
- page_title "#{@merge_request.title} (#{@merge_request.to_reference})", "Merge Requests" - page_title "#{@merge_request.to_reference} #{@merge_request.title}", "Merge Requests"
- page_description @merge_request.description - page_description @merge_request.description
- page_card_attributes @merge_request.card_attributes - page_card_attributes @merge_request.card_attributes
- content_for :page_specific_javascripts do - content_for :page_specific_javascripts do
......
- page_title "Edit", "#{@merge_request.title} (#{@merge_request.to_reference}", "Merge Requests" - page_title "Edit", "#{@merge_request.to_reference} #{@merge_request.title}", "Merge Requests"
%h3.page-title %h3.page-title
Edit Merge Request #{@merge_request.to_reference} Edit Merge Request #{@merge_request.to_reference}
......
...@@ -2,12 +2,11 @@ class ExpireBuildArtifactsWorker ...@@ -2,12 +2,11 @@ class ExpireBuildArtifactsWorker
include Sidekiq::Worker include Sidekiq::Worker
def perform def perform
Rails.logger.info 'Cleaning old build artifacts' Rails.logger.info 'Scheduling removal of build artifacts'
builds = Ci::Build.with_expired_artifacts build_ids = Ci::Build.with_expired_artifacts.pluck(:id)
builds.find_each(batch_size: 50).each do |build| build_ids = build_ids.map { |build_id| [build_id] }
Rails.logger.debug "Removing artifacts build #{build.id}..."
build.erase_artifacts! Sidekiq::Client.push_bulk('class' => ExpireBuildInstanceArtifactsWorker, 'args' => build_ids )
end
end end
end end
class ExpireBuildInstanceArtifactsWorker
include Sidekiq::Worker
def perform(build_id)
build = Ci::Build.with_expired_artifacts.reorder(nil).find_by(id: build_id)
return unless build
Rails.logger.info "Removing artifacts build #{build.id}..."
build.erase_artifacts!
end
end
Gitlab::Shell.new.generate_and_link_secret_token Gitlab::Shell.ensure_secret_token!
...@@ -24,7 +24,10 @@ devise_scope :user do ...@@ -24,7 +24,10 @@ devise_scope :user do
end end
constraints(UserUrlConstrainer.new) do constraints(UserUrlConstrainer.new) do
scope(path: ':username', as: :user, controller: :users) do scope(path: ':username',
as: :user,
constraints: { username: /[a-zA-Z.0-9_\-]+(?<!\.atom)/ },
controller: :users) do
get '/', action: :show get '/', action: :show
end end
end end
......
...@@ -12,7 +12,9 @@ communication channel. For the consumer API see the ...@@ -12,7 +12,9 @@ communication channel. For the consumer API see the
This API uses two types of authentication: This API uses two types of authentication:
1. Unique Runner's token, which is the token assigned to the Runner after it 1. Unique Runner's token, which is the token assigned to the Runner after it
has been registered. has been registered. This token can be found on the Runner's edit page (go to
**Project > Runners**, select one of the Runners listed under **Runners activated for
this project**).
2. Using Runners' registration token. 2. Using Runners' registration token.
This is a token that can be found in project's settings. This is a token that can be found in project's settings.
...@@ -48,7 +50,7 @@ DELETE /ci/api/v1/runners/delete ...@@ -48,7 +50,7 @@ DELETE /ci/api/v1/runners/delete
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
| --------- | ------- | --------- | ----------- | | --------- | ------- | --------- | ----------- |
| `token` | string | yes | Runner's registration token | | `token` | string | yes | Unique Runner's token |
Example request: Example request:
......
...@@ -148,7 +148,7 @@ PUT /projects/:id/labels ...@@ -148,7 +148,7 @@ PUT /projects/:id/labels
| --------------- | ------- | --------------------------------- | ------------------------------- | | --------------- | ------- | --------------------------------- | ------------------------------- |
| `id` | integer | yes | The ID of the project | | `id` | integer | yes | The ID of the project |
| `name` | string | yes | The name of the existing label | | `name` | string | yes | The name of the existing label |
| `new_name` | string | yes if `color` if not provided | The new name of the label | | `new_name` | string | yes if `color` is not provided | The new name of the label |
| `color` | string | yes if `new_name` is not provided | The new color of the label in 6-digit hex notation with leading `#` sign | | `color` | string | yes if `new_name` is not provided | The new color of the label in 6-digit hex notation with leading `#` sign |
| `description` | string | no | The new description of the label | | `description` | string | no | The new description of the label |
......
This diff is collapsed.
...@@ -34,6 +34,10 @@ request is up to one of our merge request "endbosses", denoted on the ...@@ -34,6 +34,10 @@ request is up to one of our merge request "endbosses", denoted on the
## Having your code reviewed ## Having your code reviewed
Please keep in mind that code review is a process that can take multiple
iterations, and reviewers may spot things later that they may not have seen the
first time.
- The first reviewer of your code is _you_. Before you perform that first push - The first reviewer of your code is _you_. Before you perform that first push
of your shiny new branch, read through the entire diff. Does it make sense? of your shiny new branch, read through the entire diff. Does it make sense?
Did you include something unrelated to the overall purpose of the changes? Did Did you include something unrelated to the overall purpose of the changes? Did
...@@ -55,6 +59,7 @@ request is up to one of our merge request "endbosses", denoted on the ...@@ -55,6 +59,7 @@ request is up to one of our merge request "endbosses", denoted on the
Understand why the change is necessary (fixes a bug, improves the user Understand why the change is necessary (fixes a bug, improves the user
experience, refactors the existing code). Then: experience, refactors the existing code). Then:
- Try to be thorough in your reviews to reduce the number of iterations.
- Communicate which ideas you feel strongly about and those you don't. - Communicate which ideas you feel strongly about and those you don't.
- Identify ways to simplify the code while still solving the problem. - Identify ways to simplify the code while still solving the problem.
- Offer alternative implementations, but assume the author already considered - Offer alternative implementations, but assume the author already considered
...@@ -64,8 +69,10 @@ experience, refactors the existing code). Then: ...@@ -64,8 +69,10 @@ experience, refactors the existing code). Then:
someone else would be confused by it as well. someone else would be confused by it as well.
- After a round of line notes, it can be helpful to post a summary note such as - After a round of line notes, it can be helpful to post a summary note such as
"LGTM :thumbsup:", or "Just a couple things to address." "LGTM :thumbsup:", or "Just a couple things to address."
- Avoid accepting a merge request before the build succeeds ("Merge when build - Avoid accepting a merge request before the build succeeds. Of course, "Merge
succeeds" is fine). When Build Succeeds" (MWBS) is fine.
- If you set the MR to "Merge When Build Succeeds", you should take over
subsequent revisions for anything that would be spotted after that.
## Credits ## Credits
......
# Start using Git on the command line # Start using Git on the command line
If you want to start using a Git and GitLab, make sure that you have created an If you want to start using Git and GitLab, make sure that you have created and/or signed into an account on GitLab.
account on GitLab.
## Open a shell ## Open a shell
Depending on your operating system, find the shell of your preference. Here are some suggestions. Depending on your operating system, you will need to use a shell of your preference. Here are some suggestions:
- [Terminal](http://blog.teamtreehouse.com/introduction-to-the-mac-os-x-command-line) on Mac OSX - [Terminal](http://blog.teamtreehouse.com/introduction-to-the-mac-os-x-command-line) on Mac OSX
...@@ -22,19 +21,19 @@ Type the following command and then press enter: ...@@ -22,19 +21,19 @@ Type the following command and then press enter:
git --version git --version
``` ```
You should receive a message that will tell you which Git version you have in your computer. If you don’t receive a "Git version" message, it means that you need to [download Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git). You should receive a message that will tell you which Git version you have on your computer. If you don’t receive a "Git version" message, it means that you need to [download Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git).
If Git doesn't automatically download, there's an option on the website to [download manually](https://git-scm.com/downloads). Then follow the steps on the installation window. If Git doesn't automatically download, there's an option on the website to [download manually](https://git-scm.com/downloads). Then follow the steps on the installation window.
After you finished installing, open a new shell and type "git --version" again to verify that it was correctly installed. After you are finished installing, open a new shell and type "git --version" again to verify that it was correctly installed.
## Add your Git username and set your email ## Add your Git username and set your email
It is important because every Git commit that you create will use this information. It is important to configure your Git username and email address as every Git commit will use this information to identify you as the author.
On your shell, type the following command to add your username: On your shell, type the following command to add your username:
``` ```
git config --global user.name ADD YOUR USERNAME git config --global user.name "YOUR_USERNAME"
``` ```
Then verify that you have the correct username: Then verify that you have the correct username:
...@@ -44,7 +43,7 @@ git config --global user.name ...@@ -44,7 +43,7 @@ git config --global user.name
To set your email address, type the following command: To set your email address, type the following command:
``` ```
git config --global user.email ADD YOUR EMAIL git config --global user.email "your_email_address@example.com"
``` ```
To verify that you entered your email correctly, type: To verify that you entered your email correctly, type:
...@@ -52,7 +51,7 @@ To verify that you entered your email correctly, type: ...@@ -52,7 +51,7 @@ To verify that you entered your email correctly, type:
git config --global user.email git config --global user.email
``` ```
You'll need to do this only once because you are using the "--global" option. It tells Git to always use this information for anything you do on that system. If you want to override this with a different username or email address for specific projects, you can run the command without the "--global" option when you’re in that project. You'll need to do this only once as you are using the `--global` option. It tells Git to always use this information for anything you do on that system. If you want to override this with a different username or email address for specific projects, you can run the command without the `--global` option when you’re in that project.
## Check your information ## Check your information
...@@ -76,7 +75,7 @@ git pull REMOTE NAME-OF-BRANCH -u ...@@ -76,7 +75,7 @@ git pull REMOTE NAME-OF-BRANCH -u
(REMOTE: origin) (NAME-OF-BRANCH: could be "master" or an existing branch) (REMOTE: origin) (NAME-OF-BRANCH: could be "master" or an existing branch)
### Create a branch ### Create a branch
Spaces won't be recognized, so you need to use a hyphen or underscore. Spaces won't be recognized, so you will need to use a hyphen or underscore.
``` ```
git checkout -b NAME-OF-BRANCH git checkout -b NAME-OF-BRANCH
``` ```
...@@ -127,4 +126,3 @@ You need to be in the master branch. ...@@ -127,4 +126,3 @@ You need to be in the master branch.
git checkout master git checkout master
git merge NAME-OF-BRANCH git merge NAME-OF-BRANCH
``` ```
...@@ -2,30 +2,52 @@ ...@@ -2,30 +2,52 @@
![backup banner](backup_hrz.png) ![backup banner](backup_hrz.png)
## Create a backup of the GitLab system An application data backup creates an archive file that contains the database,
all repositories and all attachments.
A backup creates an archive file that contains the database, all repositories and all attachments. This archive will be saved in `backup_path`, which is specified in the
This archive will be saved in backup_path (see `config/gitlab.yml`). `config/gitlab.yml` file.
The filename will be `[TIMESTAMP]_gitlab_backup.tar`. This timestamp can be used to restore an specific backup. The filename will be `[TIMESTAMP]_gitlab_backup.tar`, where `TIMESTAMP`
You can only restore a backup to exactly the same version of GitLab that you created it identifies the time at which each backup was created.
on, for example 7.2.1. The best way to migrate your repositories from one server to
You can only restore a backup to exactly the same version of GitLab on which it
was created. The best way to migrate your repositories from one server to
another is through backup restore. another is through backup restore.
You need to keep separate copies of `/etc/gitlab/gitlab-secrets.json` and To restore a backup, you will also need to restore `/etc/gitlab/gitlab-secrets.json`
`/etc/gitlab/gitlab.rb` (for omnibus packages) or (for omnibus packages) or `/home/git/gitlab/.secret` (for installations
`/home/git/gitlab/config/secrets.yml` (for installations from source). This file from source). This file contains the database encryption key and CI secret
contains the database encryption keys used for two-factor authentication and CI variables used for two-factor authentication. If you fail to restore this
secret variables, among other things. If you restore a GitLab backup without encryption key file along with the application data backup, users with two-factor
restoring the database encryption key, users who have two-factor authentication authentication enabled will lose access to your GitLab server.
enabled will lose access to your GitLab server.
## Create a backup of the GitLab system
Use this command if you've installed GitLab with the Omnibus package:
``` ```
# use this command if you've installed GitLab with the Omnibus package
sudo gitlab-rake gitlab:backup:create sudo gitlab-rake gitlab:backup:create
```
# if you've installed GitLab from source Use this if you've installed GitLab from source:
```
sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
``` ```
You can specify that portions of the application data be skipped using the
environment variable `SKIP`. You can skip:
- `db` (database)
- `uploads` (attachments)
- `repositories` (Git repositories data)
- `builds` (CI build output logs)
- `artifacts` (CI build artifacts)
- `lfs` (LFS objects)
- `registry` (Container Registry images)
Separate multiple data types to skip using a comma. For example:
```
sudo gitlab-rake gitlab:backup:create SKIP=db,uploads
```
Example output: Example output:
``` ```
...@@ -55,35 +77,12 @@ Deleting tmp directories...[DONE] ...@@ -55,35 +77,12 @@ Deleting tmp directories...[DONE]
Deleting old backups... [SKIPPING] Deleting old backups... [SKIPPING]
``` ```
## Exclude specific directories from the backup
You can choose what should be backed up by adding the environment variable `SKIP`.
The available options are:
* `db`
* `uploads` (attachments)
* `repositories`
* `builds` (CI build output logs)
* `artifacts` (CI build artifacts)
* `lfs` (LFS objects)
* `pages` (pages content)
Use a comma to specify several options at the same time:
```
# use this command if you've installed GitLab with the Omnibus package
sudo gitlab-rake gitlab:backup:create SKIP=db,uploads
# if you've installed GitLab from source
sudo -u git -H bundle exec rake gitlab:backup:create SKIP=db,uploads RAILS_ENV=production
```
## Upload backups to remote (cloud) storage ## Upload backups to remote (cloud) storage
Starting with GitLab 7.4 you can let the backup script upload the '.tar' file it creates. Starting with GitLab 7.4 you can let the backup script upload the '.tar' file it creates.
It uses the [Fog library](http://fog.io/) to perform the upload. It uses the [Fog library](http://fog.io/) to perform the upload.
In the example below we use Amazon S3 for storage. In the example below we use Amazon S3 for storage.
But Fog also lets you use [other storage providers](http://fog.io/storage/). Fog also supports [other storage providers](http://fog.io/storage/).
For omnibus packages: For omnibus packages:
...@@ -175,7 +174,7 @@ with the name of your bucket: ...@@ -175,7 +174,7 @@ with the name of your bucket:
### Uploading to locally mounted shares ### Uploading to locally mounted shares
You may also send backups to a mounted share (`NFS` / `CIFS` / `SMB` / etc.) by You may also send backups to a mounted share (`NFS` / `CIFS` / `SMB` / etc.) by
using the [`Local`](https://github.com/fog/fog-local#usage) storage provider. using the Fog [`Local`](https://github.com/fog/fog-local#usage) storage provider.
The directory pointed to by the `local_root` key **must** be owned by the `git` The directory pointed to by the `local_root` key **must** be owned by the `git`
user **when mounted** (mounting with the `uid=` of the `git` user for `CIFS` and user **when mounted** (mounting with the `uid=` of the `git` user for `CIFS` and
`SMB`) or the user that you are executing the backup tasks under (for omnibus `SMB`) or the user that you are executing the backup tasks under (for omnibus
...@@ -242,7 +241,7 @@ of using encryption in the first place! ...@@ -242,7 +241,7 @@ of using encryption in the first place!
If you use an Omnibus package please see the [instructions in the readme to backup your configuration](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md#backup-and-restore-omnibus-gitlab-configuration). If you use an Omnibus package please see the [instructions in the readme to backup your configuration](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md#backup-and-restore-omnibus-gitlab-configuration).
If you have a cookbook installation there should be a copy of your configuration in Chef. If you have a cookbook installation there should be a copy of your configuration in Chef.
If you have an installation from source, please consider backing up your `config/secrets.yml` file, `gitlab.yml` file, any SSL keys and certificates, and your [SSH host keys](https://superuser.com/questions/532040/copy-ssh-keys-from-one-server-to-another-server/532079#532079). If you installed from source, please consider backing up your `config/secrets.yml` file, `gitlab.yml` file, any SSL keys and certificates, and your [SSH host keys](https://superuser.com/questions/532040/copy-ssh-keys-from-one-server-to-another-server/532079#532079).
At the very **minimum** you should backup `/etc/gitlab/gitlab.rb` and At the very **minimum** you should backup `/etc/gitlab/gitlab.rb` and
`/etc/gitlab/gitlab-secrets.json` (Omnibus), or `/etc/gitlab/gitlab-secrets.json` (Omnibus), or
......
This diff is collapsed.
...@@ -99,6 +99,10 @@ sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS ...@@ -99,6 +99,10 @@ sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS
# Update init.d script # Update init.d script
sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
``` ```
For Ubuntu 16.04.1 LTS:
sudo systemctl daemon-reload
### 7. Update configuration files ### 7. Update configuration files
......
...@@ -116,6 +116,10 @@ sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS ...@@ -116,6 +116,10 @@ sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS
# Update init.d script # Update init.d script
sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
``` ```
For Ubuntu 16.04.1 LTS:
sudo systemctl daemon-reload
### 7. Update configuration files ### 7. Update configuration files
......
...@@ -158,6 +158,10 @@ See [smtp_settings.rb.sample] as an example. ...@@ -158,6 +158,10 @@ See [smtp_settings.rb.sample] as an example.
Ensure you're still up-to-date with the latest init script changes: Ensure you're still up-to-date with the latest init script changes:
sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
For Ubuntu 16.04.1 LTS:
sudo systemctl daemon-reload
### 9. Start application ### 9. Start application
......
...@@ -166,6 +166,10 @@ See [smtp_settings.rb.sample] as an example. ...@@ -166,6 +166,10 @@ See [smtp_settings.rb.sample] as an example.
Ensure you're still up-to-date with the latest init script changes: Ensure you're still up-to-date with the latest init script changes:
sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
For Ubuntu 16.04.1 LTS:
sudo systemctl daemon-reload
### 9. Start application ### 9. Start application
......
...@@ -166,6 +166,10 @@ See [smtp_settings.rb.sample] as an example. ...@@ -166,6 +166,10 @@ See [smtp_settings.rb.sample] as an example.
Ensure you're still up-to-date with the latest init script changes: Ensure you're still up-to-date with the latest init script changes:
sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
For Ubuntu 16.04.1 LTS:
sudo systemctl daemon-reload
### 9. Start application ### 9. Start application
......
...@@ -158,6 +158,10 @@ it where the 'public' directory of GitLab is. ...@@ -158,6 +158,10 @@ it where the 'public' directory of GitLab is.
cd /home/git/gitlab cd /home/git/gitlab
sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
``` ```
For Ubuntu 16.04.1 LTS:
sudo systemctl daemon-reload
### 8. Use Redis v2.8.0+ ### 8. Use Redis v2.8.0+
......
...@@ -98,6 +98,10 @@ We updated the init script for GitLab in order to set a specific PATH for gitlab ...@@ -98,6 +98,10 @@ We updated the init script for GitLab in order to set a specific PATH for gitlab
cd /home/git/gitlab cd /home/git/gitlab
sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
``` ```
For Ubuntu 16.04.1 LTS:
sudo systemctl daemon-reload
### 8. Start application ### 8. Start application
......
...@@ -119,6 +119,10 @@ via [/etc/default/gitlab]. ...@@ -119,6 +119,10 @@ via [/etc/default/gitlab].
Ensure you're still up-to-date with the latest init script changes: Ensure you're still up-to-date with the latest init script changes:
sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
For Ubuntu 16.04.1 LTS:
sudo systemctl daemon-reload
### 8. Start application ### 8. Start application
......
...@@ -138,6 +138,10 @@ via [/etc/default/gitlab]. ...@@ -138,6 +138,10 @@ via [/etc/default/gitlab].
Ensure you're still up-to-date with the latest init script changes: Ensure you're still up-to-date with the latest init script changes:
sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
For Ubuntu 16.04.1 LTS:
sudo systemctl daemon-reload
### 9. Start application ### 9. Start application
......
...@@ -127,6 +127,10 @@ via [/etc/default/gitlab]. ...@@ -127,6 +127,10 @@ via [/etc/default/gitlab].
Ensure you're still up-to-date with the latest init script changes: Ensure you're still up-to-date with the latest init script changes:
sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
For Ubuntu 16.04.1 LTS:
sudo systemctl daemon-reload
### 8. Start application ### 8. Start application
......
...@@ -127,6 +127,10 @@ via [/etc/default/gitlab]. ...@@ -127,6 +127,10 @@ via [/etc/default/gitlab].
Ensure you're still up-to-date with the latest init script changes: Ensure you're still up-to-date with the latest init script changes:
sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
For Ubuntu 16.04.1 LTS:
sudo systemctl daemon-reload
### 8. Start application ### 8. Start application
......
...@@ -156,6 +156,10 @@ See [smtp_settings.rb.sample] as an example. ...@@ -156,6 +156,10 @@ See [smtp_settings.rb.sample] as an example.
Ensure you're still up-to-date with the latest init script changes: Ensure you're still up-to-date with the latest init script changes:
sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
For Ubuntu 16.04.1 LTS:
sudo systemctl daemon-reload
### 9. Start application ### 9. Start application
......
...@@ -156,6 +156,10 @@ See [smtp_settings.rb.sample] as an example. ...@@ -156,6 +156,10 @@ See [smtp_settings.rb.sample] as an example.
Ensure you're still up-to-date with the latest init script changes: Ensure you're still up-to-date with the latest init script changes:
sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
For Ubuntu 16.04.1 LTS:
sudo systemctl daemon-reload
### 9. Start application ### 9. Start application
......
...@@ -98,6 +98,9 @@ As an Administrator, you can verify that the user is a member of the group or ...@@ -98,6 +98,9 @@ As an Administrator, you can verify that the user is a member of the group or
project they're trying to have access to, and you can impersonate the user to project they're trying to have access to, and you can impersonate the user to
retry the failing build in order to verify that everything is correct. retry the failing build in order to verify that everything is correct.
You need to make sure that your installation has HTTPS cloning enabled.
HTTPS support is required by GitLab CI to clone all sources.
## Build triggers ## Build triggers
[Build triggers][triggers] do not support the new permission model. [Build triggers][triggers] do not support the new permission model.
......
...@@ -25,7 +25,7 @@ module API ...@@ -25,7 +25,7 @@ module API
# Until CSRF protection is added to the API, disallow this method for # Until CSRF protection is added to the API, disallow this method for
# state-changing endpoints # state-changing endpoints
def find_user_from_warden def find_user_from_warden
warden.try(:authenticate) if request.get? || request.head? warden.try(:authenticate) if %w[GET HEAD].include?(env['REQUEST_METHOD'])
end end
def find_user_by_private_token def find_user_by_private_token
...@@ -444,7 +444,7 @@ module API ...@@ -444,7 +444,7 @@ module API
end end
def secret_token def secret_token
File.read(Gitlab.config.gitlab_shell.secret_file).chomp Gitlab::Shell.secret_token
end end
def geo_token def geo_token
......
...@@ -22,14 +22,25 @@ module API ...@@ -22,14 +22,25 @@ module API
# Example Request: # Example Request:
# GET /projects # GET /projects
get do get do
@projects = current_user.authorized_projects projects = current_user.authorized_projects
@projects = filter_projects(@projects) projects = filter_projects(projects)
@projects = paginate @projects projects = paginate projects
if params[:simple] entity = params[:simple] ? Entities::BasicProjectDetails : Entities::ProjectWithAccess
present @projects, with: Entities::BasicProjectDetails, user: current_user
else present projects, with: entity, user: current_user
present @projects, with: Entities::ProjectWithAccess, user: current_user end
end
# Get a list of visible projects for authenticated user
#
# Example Request:
# GET /projects/visible
get '/visible' do
projects = ProjectsFinder.new.execute(current_user)
projects = filter_projects(projects)
projects = paginate projects
entity = params[:simple] ? Entities::BasicProjectDetails : Entities::ProjectWithAccess
present projects, with: entity, user: current_user
end end
# Get an owned projects list for authenticated user # Get an owned projects list for authenticated user
...@@ -37,10 +48,10 @@ module API ...@@ -37,10 +48,10 @@ module API
# Example Request: # Example Request:
# GET /projects/owned # GET /projects/owned
get '/owned' do get '/owned' do
@projects = current_user.owned_projects projects = current_user.owned_projects
@projects = filter_projects(@projects) projects = filter_projects(projects)
@projects = paginate @projects projects = paginate projects
present @projects, with: Entities::ProjectWithAccess, user: current_user present projects, with: Entities::ProjectWithAccess, user: current_user
end end
# Gets starred project for the authenticated user # Gets starred project for the authenticated user
...@@ -48,10 +59,10 @@ module API ...@@ -48,10 +59,10 @@ module API
# Example Request: # Example Request:
# GET /projects/starred # GET /projects/starred
get '/starred' do get '/starred' do
@projects = current_user.viewable_starred_projects projects = current_user.viewable_starred_projects
@projects = filter_projects(@projects) projects = filter_projects(projects)
@projects = paginate @projects projects = paginate projects
present @projects, with: Entities::Project, user: current_user present projects, with: Entities::Project, user: current_user
end end
# Get all projects for admin user # Get all projects for admin user
...@@ -60,10 +71,10 @@ module API ...@@ -60,10 +71,10 @@ module API
# GET /projects/all # GET /projects/all
get '/all' do get '/all' do
authenticated_as_admin! authenticated_as_admin!
@projects = Project.all projects = Project.all
@projects = filter_projects(@projects) projects = filter_projects(projects)
@projects = paginate @projects projects = paginate projects
present @projects, with: Entities::ProjectWithAccess, user: current_user present projects, with: Entities::ProjectWithAccess, user: current_user
end end
# Get a single project # Get a single project
......
...@@ -3,7 +3,7 @@ require 'erb' ...@@ -3,7 +3,7 @@ require 'erb'
module Banzai module Banzai
module Filter module Filter
# Text filter that escapes these HTML entities: & " < > # Text filter that escapes these HTML entities: & " < >
class HTMLEntityFilter < HTML::Pipeline::TextFilter class HtmlEntityFilter < HTML::Pipeline::TextFilter
def call def call
ERB::Util.html_escape(text) ERB::Util.html_escape(text)
end end
......
...@@ -3,7 +3,7 @@ module Banzai ...@@ -3,7 +3,7 @@ module Banzai
class SingleLinePipeline < GfmPipeline class SingleLinePipeline < GfmPipeline
def self.filters def self.filters
@filters ||= FilterArray[ @filters ||= FilterArray[
Filter::HTMLEntityFilter, Filter::HtmlEntityFilter,
Filter::SanitizationFilter, Filter::SanitizationFilter,
Filter::EmojiFilter, Filter::EmojiFilter,
......
...@@ -17,6 +17,18 @@ module Gitlab ...@@ -17,6 +17,18 @@ module Gitlab
end end
class << self class << self
def secret_token
@secret_token ||= begin
File.read(Gitlab.config.gitlab_shell.secret_file).chomp
end
end
def ensure_secret_token!
return if File.exist?(File.join(Gitlab.config.gitlab_shell.path, '.gitlab_shell_secret'))
generate_and_link_secret_token
end
def version_required def version_required
@version_required ||= File.read(Rails.root. @version_required ||= File.read(Rails.root.
join('GITLAB_SHELL_VERSION')).strip join('GITLAB_SHELL_VERSION')).strip
...@@ -25,6 +37,25 @@ module Gitlab ...@@ -25,6 +37,25 @@ module Gitlab
def strip_key(key) def strip_key(key)
key.split(/ /)[0, 2].join(' ') key.split(/ /)[0, 2].join(' ')
end end
private
# Create (if necessary) and link the secret token file
def generate_and_link_secret_token
secret_file = Gitlab.config.gitlab_shell.secret_file
shell_path = Gitlab.config.gitlab_shell.path
unless File.size?(secret_file)
# Generate a new token of 16 random hexadecimal characters and store it in secret_file.
token = SecureRandom.hex(16)
File.write(secret_file, token)
end
link_path = File.join(shell_path, '.gitlab_shell_secret')
if File.exist?(shell_path) && !File.exist?(link_path)
FileUtils.symlink(secret_file, link_path)
end
end
end end
# Init new repository # Init new repository
......
...@@ -2,7 +2,7 @@ module Gitlab ...@@ -2,7 +2,7 @@ module Gitlab
module Regex module Regex
extend self extend self
NAMESPACE_REGEX_STR = '(?:[a-zA-Z0-9_\.][a-zA-Z0-9_\-\.]*[a-zA-Z0-9_\-]|[a-zA-Z0-9_])'.freeze NAMESPACE_REGEX_STR = '(?:[a-zA-Z0-9_\.][a-zA-Z0-9_\-\.]*[a-zA-Z0-9_\-]|[a-zA-Z0-9_])(?<!\.git|\.atom)'.freeze
def namespace_regex def namespace_regex
@namespace_regex ||= /\A#{NAMESPACE_REGEX_STR}\z/.freeze @namespace_regex ||= /\A#{NAMESPACE_REGEX_STR}\z/.freeze
...@@ -10,7 +10,7 @@ module Gitlab ...@@ -10,7 +10,7 @@ module Gitlab
def namespace_regex_message def namespace_regex_message
"can contain only letters, digits, '_', '-' and '.'. " \ "can contain only letters, digits, '_', '-' and '.'. " \
"Cannot start with '-' or end in '.'." \ "Cannot start with '-' or end in '.', '.git' or '.atom'." \
end end
def namespace_name_regex def namespace_name_regex
......
...@@ -111,7 +111,7 @@ module Gitlab ...@@ -111,7 +111,7 @@ module Gitlab
def write_secret def write_secret
bytes = SecureRandom.random_bytes(SECRET_LENGTH) bytes = SecureRandom.random_bytes(SECRET_LENGTH)
File.open(secret_path, 'w:BINARY', 0600) do |f| File.open(secret_path, 'w:BINARY', 0600) do |f|
f.chmod(0600) f.chmod(0600) # If the file already existed, the '0600' passed to 'open' above was a no-op.
f.write(Base64.strict_encode64(bytes)) f.write(Base64.strict_encode64(bytes))
end end
end end
......
...@@ -78,7 +78,7 @@ namespace :gitlab do ...@@ -78,7 +78,7 @@ namespace :gitlab do
f.puts "PATH=#{ENV['PATH']}" f.puts "PATH=#{ENV['PATH']}"
end end
Gitlab::Shell.new.generate_and_link_secret_token Gitlab::Shell.ensure_secret_token!
end end
desc "GitLab | Setup gitlab-shell" desc "GitLab | Setup gitlab-shell"
......
...@@ -5,7 +5,6 @@ describe Projects::BlobController do ...@@ -5,7 +5,6 @@ describe Projects::BlobController do
let(:user) { create(:user) } let(:user) { create(:user) }
before do before do
user = create(:user)
project.team << [user, :master] project.team << [user, :master]
sign_in(user) sign_in(user)
......
...@@ -44,6 +44,10 @@ feature 'Environments', feature: true do ...@@ -44,6 +44,10 @@ feature 'Environments', feature: true do
scenario 'does show deployment SHA' do scenario 'does show deployment SHA' do
expect(page).to have_link(deployment.short_sha) expect(page).to have_link(deployment.short_sha)
end end
scenario 'does show deployment internal id' do
expect(page).to have_content(deployment.iid)
end
context 'with build and manual actions' do context 'with build and manual actions' do
given(:pipeline) { create(:ci_pipeline, project: project) } given(:pipeline) { create(:ci_pipeline, project: project) }
...@@ -61,6 +65,20 @@ feature 'Environments', feature: true do ...@@ -61,6 +65,20 @@ feature 'Environments', feature: true do
expect(page).to have_content(manual.name) expect(page).to have_content(manual.name)
expect(manual.reload).to be_pending expect(manual.reload).to be_pending
end end
scenario 'does show build name and id' do
expect(page).to have_link("#{build.name} (##{build.id})")
end
context 'with external_url' do
given(:environment) { create(:environment, project: project, external_url: 'https://git.gitlab.com') }
given(:build) { create(:ci_build, pipeline: pipeline) }
given(:deployment) { create(:deployment, environment: environment, deployable: build) }
scenario 'does show an external link button' do
expect(page).to have_link(nil, href: environment.external_url)
end
end
end end
end end
end end
...@@ -122,6 +140,16 @@ feature 'Environments', feature: true do ...@@ -122,6 +140,16 @@ feature 'Environments', feature: true do
expect(page).to have_content(manual.name) expect(page).to have_content(manual.name)
expect(manual.reload).to be_pending expect(manual.reload).to be_pending
end end
context 'with external_url' do
given(:environment) { create(:environment, project: project, external_url: 'https://git.gitlab.com') }
given(:build) { create(:ci_build, pipeline: pipeline) }
given(:deployment) { create(:deployment, environment: environment, deployable: build) }
scenario 'does show an external link button' do
expect(page).to have_link(nil, href: environment.external_url)
end
end
end end
end end
end end
......
...@@ -5,6 +5,12 @@ feature 'Group', feature: true do ...@@ -5,6 +5,12 @@ feature 'Group', feature: true do
login_as(:admin) login_as(:admin)
end end
matcher :have_namespace_error_message do
match do |page|
page.has_content?("Path can contain only letters, digits, '_', '-' and '.'. Cannot start with '-' or end in '.', '.git' or '.atom'.")
end
end
describe 'creating a group with space in group path' do describe 'creating a group with space in group path' do
it 'renders new group form with validation errors' do it 'renders new group form with validation errors' do
visit new_group_path visit new_group_path
...@@ -13,7 +19,31 @@ feature 'Group', feature: true do ...@@ -13,7 +19,31 @@ feature 'Group', feature: true do
click_button 'Create group' click_button 'Create group'
expect(current_path).to eq(groups_path) expect(current_path).to eq(groups_path)
expect(page).to have_content("Path can contain only letters, digits, '_', '-' and '.'. Cannot start with '-' or end in '.'.") expect(page).to have_namespace_error_message
end
end
describe 'creating a group with .atom at end of group path' do
it 'renders new group form with validation errors' do
visit new_group_path
fill_in 'Group path', with: 'atom_group.atom'
click_button 'Create group'
expect(current_path).to eq(groups_path)
expect(page).to have_namespace_error_message
end
end
describe 'creating a group with .git at end of group path' do
it 'renders new group form with validation errors' do
visit new_group_path
fill_in 'Group path', with: 'git_group.git'
click_button 'Create group'
expect(current_path).to eq(groups_path)
expect(page).to have_namespace_error_message
end end
end end
......
...@@ -63,28 +63,38 @@ describe IssuesHelper do ...@@ -63,28 +63,38 @@ describe IssuesHelper do
end end
describe '#award_user_list' do describe '#award_user_list' do
let!(:awards) { build_list(:award_emoji, 15) } it "returns a comma-separated list of the first X users" do
user = build_stubbed(:user, name: 'Joe')
awards = Array.new(3, build_stubbed(:award_emoji, user: user))
it "returns a comma seperated list of 1-9 users" do expect(award_user_list(awards, nil, limit: 3))
expect(award_user_list(awards.first(9), nil)).to eq(awards.first(9).map { |a| a.user.name }.to_sentence) .to eq('Joe, Joe, and Joe')
end end
it "displays the current user's name as 'You'" do it "displays the current user's name as 'You'" do
expect(award_user_list(awards.first(1), awards[0].user)).to eq('You') user = build_stubbed(:user, name: 'Joe')
end award = build_stubbed(:award_emoji, user: user)
it "truncates lists of larger than 9 users" do expect(award_user_list([award], user)).to eq('You')
expect(award_user_list(awards, nil)).to eq(awards.first(9).map { |a| a.user.name }.join(', ') + ", and 6 more.") expect(award_user_list([award], nil)).to eq 'Joe'
end end
it "displays the current user in front of 0-9 other users" do it "truncates lists" do
expect(award_user_list(awards, awards[0].user)). user = build_stubbed(:user, name: 'Jane')
to eq("You, " + awards[1..9].map { |a| a.user.name }.join(', ') + ", and 5 more.") awards = Array.new(5, build_stubbed(:award_emoji, user: user))
expect(award_user_list(awards, nil, limit: 3))
.to eq('Jane, Jane, Jane, and 2 more.')
end end
it "displays the current user in front regardless of position in the list" do it "displays the current user in front of other users" do
expect(award_user_list(awards, awards[12].user)). current_user = build_stubbed(:user)
to eq("You, " + awards[0..8].map { |a| a.user.name }.join(', ') + ", and 5 more.") my_award = build_stubbed(:award_emoji, user: current_user)
award = build_stubbed(:award_emoji, user: build_stubbed(:user, name: 'Jane'))
awards = Array.new(5, award).push(my_award)
expect(award_user_list(awards, current_user, limit: 2)).
to eq("You, Jane, and 4 more.")
end end
end end
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
/*= require lib/utils/common_utils */ /*= require lib/utils/common_utils */
/*= require lib/utils/type_utility */ /*= require lib/utils/type_utility */
/*= require fuzzaldrin-plus */ /*= require fuzzaldrin-plus */
/*= require turbolinks */
/*= require jquery.turbolinks */
(function() { (function() {
var addBodyAttributes, assertLinks, dashboardIssuesPath, dashboardMRsPath, groupIssuesPath, groupMRsPath, groupName, mockDashboardOptions, mockGroupOptions, mockProjectOptions, projectIssuesPath, projectMRsPath, projectName, userId, widget; var addBodyAttributes, assertLinks, dashboardIssuesPath, dashboardMRsPath, groupIssuesPath, groupMRsPath, groupName, mockDashboardOptions, mockGroupOptions, mockProjectOptions, projectIssuesPath, projectMRsPath, projectName, userId, widget;
...@@ -138,7 +140,7 @@ ...@@ -138,7 +140,7 @@
list = widget.wrap.find('.dropdown-menu').find('ul'); list = widget.wrap.find('.dropdown-menu').find('ul');
return assertLinks(list, projectIssuesPath, projectMRsPath); return assertLinks(list, projectIssuesPath, projectMRsPath);
}); });
return it('should not show category related menu if there is text in the input', function() { it('should not show category related menu if there is text in the input', function() {
var link, list; var link, list;
addBodyAttributes('project'); addBodyAttributes('project');
mockProjectOptions(); mockProjectOptions();
...@@ -148,6 +150,23 @@ ...@@ -148,6 +150,23 @@
link = "a[href='" + projectIssuesPath + "/?assignee_id=" + userId + "']"; link = "a[href='" + projectIssuesPath + "/?assignee_id=" + userId + "']";
return expect(list.find(link).length).toBe(0); return expect(list.find(link).length).toBe(0);
}); });
return it('should not submit the search form when selecting an autocomplete row with the keyboard', function() {
var ENTER = 13;
var DOWN = 40;
addBodyAttributes();
mockDashboardOptions(true);
var submitSpy = spyOnEvent('form', 'submit');
widget.searchInput.focus();
widget.wrap.trigger($.Event('keydown', { which: DOWN }));
var enterKeyEvent = $.Event('keydown', { which: ENTER });
widget.searchInput.trigger(enterKeyEvent);
// This does not currently catch failing behavior. For security reasons,
// browsers will not trigger default behavior (form submit, in this
// example) on JavaScript-created keypresses.
expect(submitSpy).not.toHaveBeenTriggered();
// Does a worse job at capturing the intent of the test, but works.
expect(enterKeyEvent.isDefaultPrevented()).toBe(true);
});
}); });
}).call(this); }).call(this);
require 'spec_helper' require 'spec_helper'
describe Banzai::Filter::HTMLEntityFilter, lib: true do describe Banzai::Filter::HtmlEntityFilter, lib: true do
include FilterSpecHelper include FilterSpecHelper
let(:unescaped) { 'foo <strike attr="foo">&&&</strike>' } let(:unescaped) { 'foo <strike attr="foo">&&&</strike>' }
......
...@@ -5,7 +5,7 @@ describe Banzai::ObjectRenderer do ...@@ -5,7 +5,7 @@ describe Banzai::ObjectRenderer do
let(:user) { project.owner } let(:user) { project.owner }
def fake_object(attrs = {}) def fake_object(attrs = {})
object = double(attrs.merge("new_record?": true, "destroyed?": true)) object = double(attrs.merge("new_record?" => true, "destroyed?" => true))
allow(object).to receive(:markdown_cache_field_for).with(:note).and_return(:note_html) allow(object).to receive(:markdown_cache_field_for).with(:note).and_return(:note_html)
allow(object).to receive(:banzai_render_context).with(:note).and_return(project: nil, author: nil) allow(object).to receive(:banzai_render_context).with(:note).and_return(project: nil, author: nil)
allow(object).to receive(:update_column).with(:note_html, anything).and_return(true) allow(object).to receive(:update_column).with(:note_html, anything).and_return(true)
......
...@@ -22,15 +22,15 @@ describe Gitlab::Shell, lib: true do ...@@ -22,15 +22,15 @@ describe Gitlab::Shell, lib: true do
it { expect(gitlab_shell.url_to_repo('diaspora')).to eq(Gitlab.config.gitlab_shell.ssh_path_prefix + "diaspora.git") } it { expect(gitlab_shell.url_to_repo('diaspora')).to eq(Gitlab.config.gitlab_shell.ssh_path_prefix + "diaspora.git") }
describe 'generate_and_link_secret_token' do describe 'memoized secret_token' do
let(:secret_file) { 'tmp/tests/.secret_shell_test' } let(:secret_file) { 'tmp/tests/.secret_shell_test' }
let(:link_file) { 'tmp/tests/shell-secret-test/.gitlab_shell_secret' } let(:link_file) { 'tmp/tests/shell-secret-test/.gitlab_shell_secret' }
before do before do
allow(Gitlab.config.gitlab_shell).to receive(:path).and_return('tmp/tests/shell-secret-test')
allow(Gitlab.config.gitlab_shell).to receive(:secret_file).and_return(secret_file) allow(Gitlab.config.gitlab_shell).to receive(:secret_file).and_return(secret_file)
allow(Gitlab.config.gitlab_shell).to receive(:path).and_return('tmp/tests/shell-secret-test')
FileUtils.mkdir('tmp/tests/shell-secret-test') FileUtils.mkdir('tmp/tests/shell-secret-test')
gitlab_shell.generate_and_link_secret_token Gitlab::Shell.ensure_secret_token!
end end
after do after do
...@@ -39,7 +39,10 @@ describe Gitlab::Shell, lib: true do ...@@ -39,7 +39,10 @@ describe Gitlab::Shell, lib: true do
end end
it 'creates and links the secret token file' do it 'creates and links the secret token file' do
secret_token = Gitlab::Shell.secret_token
expect(File.exist?(secret_file)).to be(true) expect(File.exist?(secret_file)).to be(true)
expect(File.read(secret_file).chomp).to eq(secret_token)
expect(File.symlink?(link_file)).to be(true) expect(File.symlink?(link_file)).to be(true)
expect(File.readlink(link_file)).to eq(secret_file) expect(File.readlink(link_file)).to eq(secret_file)
end end
......
...@@ -126,6 +126,7 @@ describe Namespace, models: true do ...@@ -126,6 +126,7 @@ describe Namespace, models: true do
it "cleans the path and makes sure it's available" do it "cleans the path and makes sure it's available" do
expect(Namespace.clean_path("-john+gitlab-ETC%.git@gmail.com")).to eq("johngitlab-ETC2") expect(Namespace.clean_path("-john+gitlab-ETC%.git@gmail.com")).to eq("johngitlab-ETC2")
expect(Namespace.clean_path("--%+--valid_*&%name=.git.%.atom.atom.@email.com")).to eq("valid_name")
end end
end end
end end
...@@ -325,7 +325,9 @@ describe Project, models: true do ...@@ -325,7 +325,9 @@ describe Project, models: true do
end end
describe 'last_activity methods' do describe 'last_activity methods' do
let(:project) { create(:project, last_activity_at: 2.hours.ago) } let(:timestamp) { 2.hours.ago }
# last_activity_at gets set to created_at upon creation
let(:project) { create(:project, created_at: timestamp, updated_at: timestamp) }
describe 'last_activity' do describe 'last_activity' do
it 'alias last_activity to last_event' do it 'alias last_activity to last_event' do
...@@ -339,6 +341,7 @@ describe Project, models: true do ...@@ -339,6 +341,7 @@ describe Project, models: true do
it 'returns the creation date of the project\'s last event if present' do it 'returns the creation date of the project\'s last event if present' do
new_event = create(:event, project: project, created_at: Time.now) new_event = create(:event, project: project, created_at: Time.now)
project.reload
expect(project.last_activity_at.to_i).to eq(new_event.created_at.to_i) expect(project.last_activity_at.to_i).to eq(new_event.created_at.to_i)
end end
......
...@@ -97,12 +97,20 @@ describe Repository, models: true do ...@@ -97,12 +97,20 @@ describe Repository, models: true do
end end
describe '#find_commits_by_message' do describe '#find_commits_by_message' do
subject { repository.find_commits_by_message('submodule').map{ |k| k.id } } it 'returns commits with messages containing a given string' do
commit_ids = repository.find_commits_by_message('submodule').map(&:id)
it { is_expected.to include('5937ac0a7beb003549fc5fd26fc247adbce4a52e') } expect(commit_ids).to include('5937ac0a7beb003549fc5fd26fc247adbce4a52e')
it { is_expected.to include('6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') } expect(commit_ids).to include('6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9')
it { is_expected.to include('cfe32cf61b73a0d5e9f13e774abde7ff789b1660') } expect(commit_ids).to include('cfe32cf61b73a0d5e9f13e774abde7ff789b1660')
it { is_expected.not_to include('913c66a37b4a45b9769037c55c2d238bd0942d2e') } expect(commit_ids).not_to include('913c66a37b4a45b9769037c55c2d238bd0942d2e')
end
it 'is case insensitive' do
commit_ids = repository.find_commits_by_message('SUBMODULE').map(&:id)
expect(commit_ids).to include('5937ac0a7beb003549fc5fd26fc247adbce4a52e')
end
end end
describe '#blob_at' do describe '#blob_at' do
......
require 'spec_helper' require 'spec_helper'
describe ProjectPolicy, models: true do describe ProjectPolicy, models: true do
let(:project) { create(:empty_project, :public) }
let(:guest) { create(:user) } let(:guest) { create(:user) }
let(:reporter) { create(:user) } let(:reporter) { create(:user) }
let(:dev) { create(:user) } let(:dev) { create(:user) }
let(:master) { create(:user) } let(:master) { create(:user) }
let(:owner) { create(:user) } let(:owner) { create(:user) }
let(:admin) { create(:admin) } let(:project) { create(:empty_project, :public, namespace: owner.namespace) }
let(:users_ordered_by_permissions) do let(:guest_permissions) do
[nil, guest, reporter, dev, master, owner, admin] [
:read_project, :read_board, :read_list, :read_wiki, :read_issue, :read_label,
:read_milestone, :read_project_snippet, :read_project_member,
:read_merge_request, :read_note, :create_project, :create_issue, :create_note,
:upload_file
]
end end
let(:users_permissions) do let(:reporter_permissions) do
users_ordered_by_permissions.map { |u| Ability.allowed(u, project).size } [
:download_code, :fork_project, :create_project_snippet, :update_issue,
:admin_issue, :admin_label, :admin_list, :read_commit_status, :read_build,
:read_container_image, :read_pipeline, :read_environment, :read_deployment
]
end
let(:team_member_reporter_permissions) do
[
:build_download_code, :build_read_container_image
]
end
let(:developer_permissions) do
[
:admin_merge_request, :update_merge_request, :create_commit_status,
:update_commit_status, :create_build, :update_build, :create_pipeline,
:update_pipeline, :create_merge_request, :create_wiki, :push_code,
:resolve_note, :create_container_image, :update_container_image,
:create_environment, :create_deployment
]
end
let(:master_permissions) do
[
:push_code_to_protected_branches, :update_project_snippet, :update_environment,
:update_deployment, :admin_milestone, :admin_project_snippet,
:admin_project_member, :admin_note, :admin_wiki, :admin_project,
:admin_commit_status, :admin_build, :admin_container_image,
:admin_pipeline, :admin_environment, :admin_deployment
]
end
let(:public_permissions) do
[
:download_code, :fork_project, :read_commit_status, :read_pipeline,
:read_container_image, :build_download_code, :build_read_container_image
]
end
let(:owner_permissions) do
[
:change_namespace, :change_visibility_level, :rename_project, :remove_project,
:archive_project, :remove_fork_project, :destroy_merge_request, :destroy_issue
]
end end
before do before do
...@@ -22,16 +70,6 @@ describe ProjectPolicy, models: true do ...@@ -22,16 +70,6 @@ describe ProjectPolicy, models: true do
project.team << [master, :master] project.team << [master, :master]
project.team << [dev, :developer] project.team << [dev, :developer]
project.team << [reporter, :reporter] project.team << [reporter, :reporter]
group = create(:group)
project.project_group_links.create(
group: group,
group_access: Gitlab::Access::MASTER)
group.add_owner(owner)
end
it 'returns increasing permissions for each level' do
expect(users_permissions).to eq(users_permissions.sort.uniq)
end end
it 'does not include the read_issue permission when the issue author is not a member of the private project' do it 'does not include the read_issue permission when the issue author is not a member of the private project' do
...@@ -46,4 +84,81 @@ describe ProjectPolicy, models: true do ...@@ -46,4 +84,81 @@ describe ProjectPolicy, models: true do
expect(Ability.allowed?(user, :read_issue, project)).to be_falsy expect(Ability.allowed?(user, :read_issue, project)).to be_falsy
end end
context 'abilities for non-public projects' do
let(:project) { create(:empty_project, namespace: owner.namespace) }
subject { described_class.abilities(current_user, project).to_set }
context 'with no user' do
let(:current_user) { nil }
it { is_expected.to be_empty }
end
context 'guests' do
let(:current_user) { guest }
it do
is_expected.to include(*guest_permissions)
is_expected.not_to include(*reporter_permissions)
is_expected.not_to include(*team_member_reporter_permissions)
is_expected.not_to include(*developer_permissions)
is_expected.not_to include(*master_permissions)
is_expected.not_to include(*owner_permissions)
end
end
context 'reporter' do
let(:current_user) { reporter }
it do
is_expected.to include(*guest_permissions)
is_expected.to include(*reporter_permissions)
is_expected.to include(*team_member_reporter_permissions)
is_expected.not_to include(*developer_permissions)
is_expected.not_to include(*master_permissions)
is_expected.not_to include(*owner_permissions)
end
end
context 'developer' do
let(:current_user) { dev }
it do
is_expected.to include(*guest_permissions)
is_expected.to include(*reporter_permissions)
is_expected.to include(*team_member_reporter_permissions)
is_expected.to include(*developer_permissions)
is_expected.not_to include(*master_permissions)
is_expected.not_to include(*owner_permissions)
end
end
context 'master' do
let(:current_user) { master }
it do
is_expected.to include(*guest_permissions)
is_expected.to include(*reporter_permissions)
is_expected.to include(*team_member_reporter_permissions)
is_expected.to include(*developer_permissions)
is_expected.to include(*master_permissions)
is_expected.not_to include(*owner_permissions)
end
end
context 'owner' do
let(:current_user) { owner }
it do
is_expected.to include(*guest_permissions)
is_expected.to include(*reporter_permissions)
is_expected.not_to include(*team_member_reporter_permissions)
is_expected.to include(*developer_permissions)
is_expected.to include(*master_permissions)
is_expected.to include(*owner_permissions)
end
end
end
end end
...@@ -175,6 +175,36 @@ describe API::API, api: true do ...@@ -175,6 +175,36 @@ describe API::API, api: true do
end end
end end
describe 'GET /projects/visible' do
let(:public_project) { create(:project, :public) }
before do
public_project
project
project2
project3
project4
end
it 'returns the projects viewable by the user' do
get api('/projects/visible', user)
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
expect(json_response.map { |project| project['id'] }).
to contain_exactly(public_project.id, project.id, project2.id, project3.id)
end
it 'shows only public projects when the user only has access to those' do
get api('/projects/visible', user2)
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
expect(json_response.map { |project| project['id'] }).
to contain_exactly(public_project.id)
end
end
describe 'GET /projects/starred' do describe 'GET /projects/starred' do
let(:public_project) { create(:project, :public) } let(:public_project) { create(:project, :public) }
......
...@@ -110,9 +110,21 @@ describe MergeRequests::MergeWhenBuildSucceedsService do ...@@ -110,9 +110,21 @@ describe MergeRequests::MergeWhenBuildSucceedsService do
context 'properly handles multiple stages' do context 'properly handles multiple stages' do
let(:ref) { mr_merge_if_green_enabled.source_branch } let(:ref) { mr_merge_if_green_enabled.source_branch }
let!(:build) { create(:ci_build, :created, pipeline: pipeline, ref: ref, name: 'build', stage: 'build') } let(:sha) { project.commit(ref).id }
let!(:test) { create(:ci_build, :created, pipeline: pipeline, ref: ref, name: 'test', stage: 'test') }
let(:pipeline) { create(:ci_empty_pipeline, ref: mr_merge_if_green_enabled.source_branch, project: project) } let(:pipeline) do
create(:ci_empty_pipeline, ref: ref, sha: sha, project: project)
end
let!(:build) do
create(:ci_build, :created, pipeline: pipeline, ref: ref,
name: 'build', stage: 'build')
end
let!(:test) do
create(:ci_build, :created, pipeline: pipeline, ref: ref,
name: 'test', stage: 'test')
end
before do before do
# This behavior of MergeRequest: we instantiate a new object # This behavior of MergeRequest: we instantiate a new object
...@@ -121,14 +133,16 @@ describe MergeRequests::MergeWhenBuildSucceedsService do ...@@ -121,14 +133,16 @@ describe MergeRequests::MergeWhenBuildSucceedsService do
end end
end end
it "doesn't merge if some stages failed" do it "doesn't merge if any of stages failed" do
expect(MergeWorker).not_to receive(:perform_async) expect(MergeWorker).not_to receive(:perform_async)
build.success build.success
test.drop test.drop
end end
it 'merge when all stages succeeded' do it 'merges when all stages succeeded' do
expect(MergeWorker).to receive(:perform_async) expect(MergeWorker).to receive(:perform_async)
build.success build.success
test.success test.success
end end
......
...@@ -57,6 +57,11 @@ RSpec.configure do |config| ...@@ -57,6 +57,11 @@ RSpec.configure do |config|
example.run example.run
Rails.cache = caching_store Rails.cache = caching_store
end end
config.after(:each) do
FileUtils.rm_rf("tmp/tests/repositories")
FileUtils.mkdir_p("tmp/tests/repositories")
end
end end
FactoryGirl::SyntaxRunner.class_eval do FactoryGirl::SyntaxRunner.class_eval do
......
...@@ -5,65 +5,42 @@ describe ExpireBuildArtifactsWorker do ...@@ -5,65 +5,42 @@ describe ExpireBuildArtifactsWorker do
let(:worker) { described_class.new } let(:worker) { described_class.new }
before { Sidekiq::Worker.clear_all }
describe '#perform' do describe '#perform' do
before { build } before { build }
subject! { worker.perform } subject! do
Sidekiq::Testing.fake! { worker.perform }
end
context 'with expired artifacts' do context 'with expired artifacts' do
let(:build) { create(:ci_build, :artifacts, artifacts_expire_at: Time.now - 7.days) } let(:build) { create(:ci_build, :artifacts, artifacts_expire_at: Time.now - 7.days) }
it 'does expire' do it 'enqueues that build' do
expect(build.reload.artifacts_expired?).to be_truthy expect(jobs_enqueued.size).to eq(1)
end expect(jobs_enqueued[0]["args"]).to eq([build.id])
it 'does remove files' do
expect(build.reload.artifacts_file.exists?).to be_falsey
end
it 'does nullify artifacts_file column' do
expect(build.reload.artifacts_file_identifier).to be_nil
end end
end end
context 'with not yet expired artifacts' do context 'with not yet expired artifacts' do
let(:build) { create(:ci_build, :artifacts, artifacts_expire_at: Time.now + 7.days) } let(:build) { create(:ci_build, :artifacts, artifacts_expire_at: Time.now + 7.days) }
it 'does not expire' do it 'does not enqueue that build' do
expect(build.reload.artifacts_expired?).to be_falsey expect(jobs_enqueued.size).to eq(0)
end
it 'does not remove files' do
expect(build.reload.artifacts_file.exists?).to be_truthy
end
it 'does not nullify artifacts_file column' do
expect(build.reload.artifacts_file_identifier).not_to be_nil
end end
end end
context 'without expire date' do context 'without expire date' do
let(:build) { create(:ci_build, :artifacts) } let(:build) { create(:ci_build, :artifacts) }
it 'does not expire' do it 'does not enqueue that build' do
expect(build.reload.artifacts_expired?).to be_falsey expect(jobs_enqueued.size).to eq(0)
end
it 'does not remove files' do
expect(build.reload.artifacts_file.exists?).to be_truthy
end
it 'does not nullify artifacts_file column' do
expect(build.reload.artifacts_file_identifier).not_to be_nil
end end
end end
context 'for expired artifacts' do def jobs_enqueued
let(:build) { create(:ci_build, artifacts_expire_at: Time.now - 7.days) } Sidekiq::Queues.jobs_by_worker['ExpireBuildInstanceArtifactsWorker']
it 'is still expired' do
expect(build.reload.artifacts_expired?).to be_truthy
end
end end
end end
end end
require 'spec_helper'
describe ExpireBuildInstanceArtifactsWorker do
include RepoHelpers
let(:worker) { described_class.new }
describe '#perform' do
before { build }
subject! { worker.perform(build.id) }
context 'with expired artifacts' do
let(:build) { create(:ci_build, :artifacts, artifacts_expire_at: Time.now - 7.days) }
it 'does expire' do
expect(build.reload.artifacts_expired?).to be_truthy
end
it 'does remove files' do
expect(build.reload.artifacts_file.exists?).to be_falsey
end
it 'does nullify artifacts_file column' do
expect(build.reload.artifacts_file_identifier).to be_nil
end
end
context 'with not yet expired artifacts' do
let(:build) { create(:ci_build, :artifacts, artifacts_expire_at: Time.now + 7.days) }
it 'does not expire' do
expect(build.reload.artifacts_expired?).to be_falsey
end
it 'does not remove files' do
expect(build.reload.artifacts_file.exists?).to be_truthy
end
it 'does not nullify artifacts_file column' do
expect(build.reload.artifacts_file_identifier).not_to be_nil
end
end
context 'without expire date' do
let(:build) { create(:ci_build, :artifacts) }
it 'does not expire' do
expect(build.reload.artifacts_expired?).to be_falsey
end
it 'does not remove files' do
expect(build.reload.artifacts_file.exists?).to be_truthy
end
it 'does not nullify artifacts_file column' do
expect(build.reload.artifacts_file_identifier).not_to be_nil
end
end
context 'for expired artifacts' do
let(:build) { create(:ci_build, artifacts_expire_at: Time.now - 7.days) }
it 'is still expired' do
expect(build.reload.artifacts_expired?).to be_truthy
end
end
end
end
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