Merge branch 'master' into reference-pipeline-and-caching

This commit is contained in:
Douwe Maan 2015-11-19 15:46:04 +01:00
commit f5a630111f
571 changed files with 9843 additions and 3255 deletions

1
.flayignore Normal file
View file

@ -0,0 +1 @@
*.erb

2
.gitignore vendored
View file

@ -37,8 +37,10 @@ nohup.out
public/assets/ public/assets/
public/uploads.* public/uploads.*
public/uploads/ public/uploads/
shared/artifacts/
rails_best_practices_output.html rails_best_practices_output.html
/tags /tags
tmp/ tmp/
vendor/bundle/* vendor/bundle/*
builds/* builds/*
shared/*

View file

@ -73,3 +73,17 @@ brakeman:
tags: tags:
- ruby - ruby
- mysql - mysql
flog:
script:
- bundle exec rake flog
tags:
- ruby
- mysql
flay:
script:
- bundle exec rake flay
tags:
- ruby
- mysql

View file

@ -1,6 +1,21 @@
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.2.0 (unreleased) v 8.3.0 (unreleased)
v 8.2.0
- Improved performance of finding projects and groups in various places
- Improved performance of rendering user profile pages and Atom feeds
- Fix grouping of contributors by email in graph.
- Remove CSS property preventing hard tabs from rendering in Chromium 45 (Stan Hu)
- Fix Drone CI service template not saving properly (Stan Hu)
- Fix avatars not showing in Atom feeds and project issues when Gravatar disabled (Stan Hu)
- Added a GitLab specific profiling tool called "Sherlock" (see GitLab CE merge request #1749)
- Upgrade gitlab_git to 7.2.20 and rugged to 0.23.3 (Stan Hu)
- Improved performance of finding users by one of their Email addresses
- Add allow_failure field to commit status API (Stan Hu)
- Commits without .gitlab-ci.yml are marked as skipped
- Save detailed error when YAML syntax is invalid
- Added build artifacts
- Improved performance of replacing references in comments - Improved performance of replacing references in comments
- Show last project commit to default branch on project home page - Show last project commit to default branch on project home page
- Highlight comment based on anchor in URL - Highlight comment based on anchor in URL
@ -11,9 +26,49 @@ v 8.2.0 (unreleased)
- Fix: Inability to reply to code comments in the MR view, if the MR comes from a fork - Fix: Inability to reply to code comments in the MR view, if the MR comes from a fork
- Use git follow flag for commits page when retrieve history for file or directory - Use git follow flag for commits page when retrieve history for file or directory
- Show merge request CI status on merge requests index page - Show merge request CI status on merge requests index page
- Send build name and stage in CI notification e-mail
- Extend yml syntax for only and except to support specifying repository path
- Enable shared runners to all new projects
- Bump GitLab-Workhorse to 0.4.1
- Allow to define cache in `.gitlab-ci.yml`
- Fix: 500 error returned if destroy request without HTTP referer (Kazuki Shimizu) - Fix: 500 error returned if destroy request without HTTP referer (Kazuki Shimizu)
- Remove deprecated CI events from project settings page
- [API] Add ability to fetch the commit ID of the last commit that actually touched a file
- Fix omniauth documentation setting for omnibus configuration (Jon Cairns)
- Add "New file" link to dropdown on project page
- Include commit logs in project search
- Add "added", "modified" and "removed" properties to commit object in webhook
- Rename "Back to" links to "Go to" because its not always a case it point to place user come from
- Allow groups to appear in the search results if the group owner allows it
- Add email notification to former assignee upon unassignment (Adam Lieskovský)
- New design for project graphs page
- Remove deprecated dumped yaml file generated from previous job definitions
- Fix incoming email config defaults
- Show specific runners from projects where user is master or owner
- MR target branch is now visible on a list view when it is different from project's default one
- Improve Continuous Integration graphs page
- Make color of "Accept Merge Request" button consistent with current build status
- Add ignore white space option in merge request diff and commit and compare view
- Ability to add release notes (markdown text and attachments) to git tags (aka Releases)
- Relative links from a repositories README.md now link to the default branch
- Fix trailing whitespace issue in merge request/issue title
- Fix bug when milestone/label filter was empty for dashboard issues page
- Add ability to create milestone in group projects from single form
- Prevent the last owner of a group from being able to delete themselves by 'adding' themselves as a master (James Lopez)
v 8.1.1 v 8.1.4
- Fix bug where manually merged branches in a MR would end up with an empty diff (Stan Hu)
- Prevent redirect loop when home_page_url is set to the root URL
- Fix incoming email config defaults
- Remove CSS property preventing hard tabs from rendering in Chromium 45 (Stan Hu)
v 8.1.3
- Force update refs/merge-requests/X/head upon a push to the source branch of a merge request (Stan Hu)
- Spread out runner contacted_at updates
- Use issue editor as cross reference comment author when issue is edited with a new mention
- Add Facebook authentication
v 8.1.2
- Fix cloning Wiki repositories via HTTP (Stan Hu) - Fix cloning Wiki repositories via HTTP (Stan Hu)
- Add migration to remove satellites directory - Add migration to remove satellites directory
- Fix specific runners visibility - Fix specific runners visibility
@ -23,10 +78,15 @@ v 8.1.1
- Fix CI badge - Fix CI badge
- Allow developer to manage builds - Allow developer to manage builds
v 8.1.1
- Removed, see 8.1.2
v 8.1.0 v 8.1.0
- Ensure MySQL CI limits DB migrations occur after the fields have been created (Stan Hu) - Ensure MySQL CI limits DB migrations occur after the fields have been created (Stan Hu)
- Fix duplicate repositories in GitHub import page (Stan Hu) - Fix duplicate repositories in GitHub import page (Stan Hu)
- Redirect to a default path if HTTP_REFERER is not set (Stan Hu) - Redirect to a default path if HTTP_REFERER is not set (Stan Hu)
- Adds ability to create directories using the web editor (Ben Ford)
- Cleanup stuck CI builds
- Send an email to admin email when a user is reported for spam (Jonathan Rochkind) - Send an email to admin email when a user is reported for spam (Jonathan Rochkind)
- Show notifications button when user is member of group rather than project (Grzegorz Bizon) - Show notifications button when user is member of group rather than project (Grzegorz Bizon)
- Fix bug preventing mentioned issued from being closed when MR is merged using fast-forward merge. - Fix bug preventing mentioned issued from being closed when MR is merged using fast-forward merge.

View file

@ -10,7 +10,7 @@ By submitting code as an individual you agree to the [individual contributor lic
## Security vulnerability disclosure ## Security vulnerability disclosure
Please report suspected security vulnerabilities in private to support@gitlab.com, also see the [disclosure section on the GitLab.com website](http://about.gitlab.com/disclosure/). Please do NOT create publicly viewable issues for suspected security vulnerabilities. Please report suspected security vulnerabilities in private to support@gitlab.com, also see the [disclosure section on the GitLab.com website](https://about.gitlab.com/disclosure/). Please do NOT create publicly viewable issues for suspected security vulnerabilities.
## Closing policy for issues and merge requests ## Closing policy for issues and merge requests
@ -35,7 +35,7 @@ The [GitLab CE issue tracker on GitLab.com](https://gitlab.com/gitlab-org/gitlab
Do not use the issue tracker for feature requests. We have a specific [feature request forum](http://feedback.gitlab.com) for this purpose. Please keep feature requests as small and simple as possible, complex ones might be edited to make them small and simple. Do not use the issue tracker for feature requests. We have a specific [feature request forum](http://feedback.gitlab.com) for this purpose. Please keep feature requests as small and simple as possible, complex ones might be edited to make them small and simple.
Please send a merge request with a tested solution or a merge request with a failing test instead of opening an issue if you can. If you're unsure where to post, post to the [mailing list](https://groups.google.com/forum/#!forum/gitlabhq) or [Stack Overflow](http://stackoverflow.com/questions/tagged/gitlab) first. There are a lot of helpful GitLab users there who may be able to help you quickly. If your particular issue turns out to be a bug, it will find its way from there. Please send a merge request with a tested solution or a merge request with a failing test instead of opening an issue if you can. If you're unsure where to post, post to the [mailing list](https://groups.google.com/forum/#!forum/gitlabhq) or [Stack Overflow](https://stackoverflow.com/questions/tagged/gitlab) first. There are a lot of helpful GitLab users there who may be able to help you quickly. If your particular issue turns out to be a bug, it will find its way from there.
### Issue tracker guidelines ### Issue tracker guidelines
@ -72,7 +72,7 @@ If you can, please submit a merge request with the fix or improvements including
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 changing the README, some documentation or other things which have no effect on the tests, add `[ci skip]` somewhere in the commit message 1. If you are changing the README, some documentation or other things which have no effect on the tests, add `[ci skip]` somewhere in the commit message
1. If you have multiple commits please combine them into one commit by [squashing them](http://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits) 1. If you have multiple commits please combine them into one commit by [squashing them](https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)
1. Push the commit to your fork 1. Push the commit to your fork
1. Submit a merge request (MR) to the master branch 1. Submit a merge request (MR) to the master branch
1. The MR title should describe the change you want to make 1. The MR title should describe the change you want to make
@ -83,6 +83,7 @@ If you can, please submit a merge request with the fix or improvements including
1. Be prepared to answer questions and incorporate feedback even if requests for this arrive weeks or months after your MR submission 1. Be prepared to answer questions and incorporate feedback even if requests for this arrive weeks or months after your MR submission
1. If your MR touches code that executes shell commands, make sure it adheres to the [shell command guidelines]( doc/development/shell_commands.md). 1. If your MR touches code that executes shell commands, make sure it adheres to the [shell command guidelines]( doc/development/shell_commands.md).
1. Also have a look at the [shell command guidelines](doc/development/shell_commands.md) if your code reads or opens files, or handles paths to files on disk. 1. Also have a look at the [shell command guidelines](doc/development/shell_commands.md) if your code reads or opens files, or handles paths to files on disk.
1. If your code creates new files on disk please read the [shared files guidelines](doc/development/shared_files.md).
The **official merge window** is in the beginning of the month from the 1st to the 7th day of the month. The best time to submit a MR and get feedback fast. The **official merge window** is in the beginning of the month from the 1st to the 7th day of the month. The best time to submit a MR and get feedback fast.
Before this time the GitLab B.V. team is still dealing with work that is created by the monthly release such as regressions requiring patch releases. Before this time the GitLab B.V. team is still dealing with work that is created by the monthly release such as regressions requiring patch releases.
@ -180,4 +181,4 @@ This code of conduct applies both within project spaces and in public spaces whe
Instances of abusive, harassing, or otherwise unacceptable behavior can be reported by emailing contact@gitlab.com Instances of abusive, harassing, or otherwise unacceptable behavior can be reported by emailing contact@gitlab.com
This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.1.0, available at [http://contributor-covenant.org/version/1/1/0/](http://contributor-covenant.org/version/1/1/0/) This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.1.0, available at [http://contributor-covenant.org/version/1/1/0/](http://contributor-covenant.org/version/1/1/0/)

View file

@ -1 +0,0 @@
0.3.0

View file

@ -1 +1 @@
2.6.5 2.6.7

1
GITLAB_WORKHORSE Normal file
View file

@ -0,0 +1 @@
0.4.1

1
GITLAB_WORKHORSE_VERSION Normal file
View file

@ -0,0 +1 @@
0.3.1

25
Gemfile
View file

@ -19,6 +19,7 @@ gem 'devise-async', '~> 0.9.0'
gem 'doorkeeper', '~> 2.1.3' gem 'doorkeeper', '~> 2.1.3'
gem 'omniauth', '~> 1.2.2' gem 'omniauth', '~> 1.2.2'
gem 'omniauth-bitbucket', '~> 0.0.2' gem 'omniauth-bitbucket', '~> 0.0.2'
gem 'omniauth-facebook', '~> 3.0.0'
gem 'omniauth-github', '~> 1.1.1' gem 'omniauth-github', '~> 1.1.1'
gem 'omniauth-gitlab', '~> 1.0.0' gem 'omniauth-gitlab', '~> 1.0.0'
gem 'omniauth-google-oauth2', '~> 0.2.0' gem 'omniauth-google-oauth2', '~> 0.2.0'
@ -39,7 +40,7 @@ gem "browser", '~> 1.0.0'
# Extracting information from a git repository # Extracting information from a git repository
# Provide access to Gitlab::Git library # Provide access to Gitlab::Git library
gem "gitlab_git", '~> 7.2.19' gem "gitlab_git", '~> 7.2.20'
# LDAP Auth # LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes # GitLab fork with several improvements to original library. For full list of changes
@ -50,20 +51,16 @@ gem 'gitlab_omniauth-ldap', '~> 1.2.1', require: "omniauth-ldap"
gem 'gollum-lib', '~> 4.0.2' gem 'gollum-lib', '~> 4.0.2'
# Language detection # Language detection
# GitLab fork of linguist does not require pygments/python dependency. gem "github-linguist", "~> 4.7.0", require: "linguist"
# New version of original gem also dropped pygments support but it has strict
# dependency to unstable rugged version. We have internal issue for replacing
# fork with original gem when we meet on same rugged version - https://dev.gitlab.org/gitlab/gitlabhq/issues/2052.
gem "gitlab-linguist", "~> 3.0.1", require: "linguist"
# API # API
gem 'grape', '~> 0.6.1' gem 'grape', '~> 0.13.0'
gem 'grape-entity', '~> 0.4.2' gem 'grape-entity', '~> 0.4.2'
gem 'rack-cors', '~> 0.4.0', require: 'rack/cors' gem 'rack-cors', '~> 0.4.0', require: 'rack/cors'
# Format dates and times # Format dates and times
# based on human-friendly examples # based on human-friendly examples
gem "stamp", '~> 0.5.0' gem "stamp", '~> 0.6.0'
# Enumeration fields # Enumeration fields
gem 'enumerize', '~> 0.7.0' gem 'enumerize', '~> 0.7.0'
@ -112,7 +109,7 @@ group :unicorn do
end end
# State machine # State machine
gem "state_machine", '~> 1.2.0' gem "state_machines-activerecord", '~> 0.3.0'
# Run events after state machine commits # Run events after state machine commits
gem 'after_commit_queue' gem 'after_commit_queue'
@ -184,7 +181,7 @@ gem 'ace-rails-ap', '~> 2.0.1'
gem 'mousetrap-rails', '~> 1.4.6' gem 'mousetrap-rails', '~> 1.4.6'
# Detect and convert string character encoding # Detect and convert string character encoding
gem 'charlock_holmes', '~> 0.6.9.4' gem 'charlock_holmes', '~> 0.7.3'
gem "sass-rails", '~> 4.0.5' gem "sass-rails", '~> 4.0.5'
gem "coffee-rails", '~> 4.1.0' gem "coffee-rails", '~> 4.1.0'
@ -201,7 +198,7 @@ gem 'jquery-atwho-rails', '~> 1.3.2'
gem 'jquery-rails', '~> 3.1.3' gem 'jquery-rails', '~> 3.1.3'
gem 'jquery-scrollto-rails', '~> 1.4.3' gem 'jquery-scrollto-rails', '~> 1.4.3'
gem 'jquery-ui-rails', '~> 4.2.1' gem 'jquery-ui-rails', '~> 4.2.1'
gem 'nprogress-rails', '~> 0.1.2.3' gem 'nprogress-rails', '~> 0.1.6.7'
gem 'raphael-rails', '~> 2.1.2' gem 'raphael-rails', '~> 2.1.2'
gem 'request_store', '~> 1.2.0' gem 'request_store', '~> 1.2.0'
gem 'select2-rails', '~> 3.5.9' gem 'select2-rails', '~> 3.5.9'
@ -214,11 +211,9 @@ group :development do
gem "annotate", "~> 2.6.0" gem "annotate", "~> 2.6.0"
gem "letter_opener", '~> 1.1.2' gem "letter_opener", '~> 1.1.2'
gem 'quiet_assets', '~> 1.0.2' gem 'quiet_assets', '~> 1.0.2'
gem 'rack-mini-profiler', '~> 0.9.0', require: false
gem 'rerun', '~> 0.10.0' gem 'rerun', '~> 0.10.0'
gem 'bullet', require: false gem 'bullet', require: false
gem 'active_record_query_trace', require: false gem 'rblineprof', platform: :mri, require: false
gem 'rack-lineprof', platform: :mri
# Better errors handler # Better errors handler
gem 'better_errors', '~> 1.0.1' gem 'better_errors', '~> 1.0.1'
@ -264,6 +259,8 @@ group :development, :test do
gem 'rubocop', '~> 0.28.0', require: false gem 'rubocop', '~> 0.28.0', require: false
gem 'coveralls', '~> 0.8.2', require: false gem 'coveralls', '~> 0.8.2', require: false
gem 'simplecov', '~> 0.10.0', require: false gem 'simplecov', '~> 0.10.0', require: false
gem 'flog', require: false
gem 'flay', require: false
gem 'benchmark-ips', require: false gem 'benchmark-ips', require: false
end end

View file

@ -17,7 +17,6 @@ GEM
activesupport (= 4.1.12) activesupport (= 4.1.12)
builder (~> 3.1) builder (~> 3.1)
erubis (~> 2.7.0) erubis (~> 2.7.0)
active_record_query_trace (1.5)
activemodel (4.1.12) activemodel (4.1.12)
activesupport (= 4.1.12) activesupport (= 4.1.12)
builder (~> 3.1) builder (~> 3.1)
@ -108,7 +107,7 @@ GEM
json (>= 1.7) json (>= 1.7)
celluloid (0.16.0) celluloid (0.16.0)
timers (~> 4.0.0) timers (~> 4.0.0)
charlock_holmes (0.6.9.4) charlock_holmes (0.7.3)
chunky_png (1.3.4) chunky_png (1.3.4)
cliver (0.3.2) cliver (0.3.2)
coderay (1.1.0) coderay (1.1.0)
@ -176,7 +175,7 @@ GEM
activesupport (>= 3.2) activesupport (>= 3.2)
equalizer (0.0.11) equalizer (0.0.11)
erubis (2.7.0) erubis (2.7.0)
escape_utils (0.2.4) escape_utils (1.1.0)
eventmachine (1.0.8) eventmachine (1.0.8)
excon (0.45.4) excon (0.45.4)
execjs (2.6.0) execjs (2.6.0)
@ -195,6 +194,12 @@ GEM
ffi (1.9.10) ffi (1.9.10)
fission (0.5.0) fission (0.5.0)
CFPropertyList (~> 2.2) CFPropertyList (~> 2.2)
flay (2.6.1)
ruby_parser (~> 3.0)
sexp_processor (~> 4.0)
flog (4.3.2)
ruby_parser (~> 3.1, > 3.1.0)
sexp_processor (~> 4.4)
flowdock (0.7.0) flowdock (0.7.0)
httparty (~> 0.7) httparty (~> 0.7)
multi_json multi_json
@ -267,6 +272,11 @@ GEM
json json
get_process_mem (0.2.0) get_process_mem (0.2.0)
gherkin-ruby (0.3.2) gherkin-ruby (0.3.2)
github-linguist (4.7.0)
charlock_holmes (~> 0.7.3)
escape_utils (~> 1.1.0)
mime-types (>= 1.19)
rugged (>= 0.23.0b)
github-markup (1.3.3) github-markup (1.3.3)
gitlab-flowdock-git-hook (1.0.1) gitlab-flowdock-git-hook (1.0.1)
flowdock (~> 0.7) flowdock (~> 0.7)
@ -277,17 +287,13 @@ GEM
diff-lcs (~> 1.1) diff-lcs (~> 1.1)
mime-types (~> 1.15) mime-types (~> 1.15)
posix-spawn (~> 0.3) posix-spawn (~> 0.3)
gitlab-linguist (3.0.1)
charlock_holmes (~> 0.6.6)
escape_utils (~> 0.2.4)
mime-types (~> 1.19)
gitlab_emoji (0.1.1) gitlab_emoji (0.1.1)
gemojione (~> 2.0) gemojione (~> 2.0)
gitlab_git (7.2.19) gitlab_git (7.2.20)
activesupport (~> 4.0) activesupport (~> 4.0)
charlock_holmes (~> 0.6) charlock_holmes (~> 0.7.3)
gitlab-linguist (~> 3.0) github-linguist (~> 4.7.0)
rugged (~> 0.22.2) rugged (~> 0.23.3)
gitlab_meta (7.0) gitlab_meta (7.0)
gitlab_omniauth-ldap (1.2.1) gitlab_omniauth-ldap (1.2.1)
net-ldap (~> 0.9) net-ldap (~> 0.9)
@ -306,10 +312,10 @@ GEM
gon (5.0.4) gon (5.0.4)
actionpack (>= 2.3.0) actionpack (>= 2.3.0)
json json
grape (0.6.1) grape (0.13.0)
activesupport activesupport
builder builder
hashie (>= 1.2.0) hashie (>= 2.1.0)
multi_json (>= 1.3.2) multi_json (>= 1.3.2)
multi_xml (>= 0.5.2) multi_xml (>= 0.5.2)
rack (>= 1.3.0) rack (>= 1.3.0)
@ -406,7 +412,7 @@ GEM
newrelic_rpm (3.9.4.245) newrelic_rpm (3.9.4.245)
nokogiri (1.6.6.2) nokogiri (1.6.6.2)
mini_portile (~> 0.6.0) mini_portile (~> 0.6.0)
nprogress-rails (0.1.2.3) nprogress-rails (0.1.6.7)
oauth (0.4.7) oauth (0.4.7)
oauth2 (1.0.0) oauth2 (1.0.0)
faraday (>= 0.8, < 0.10) faraday (>= 0.8, < 0.10)
@ -423,6 +429,8 @@ GEM
multi_json (~> 1.7) multi_json (~> 1.7)
omniauth (~> 1.1) omniauth (~> 1.1)
omniauth-oauth (~> 1.0) omniauth-oauth (~> 1.0)
omniauth-facebook (3.0.0)
omniauth-oauth2 (~> 1.2)
omniauth-github (1.1.2) omniauth-github (1.1.2)
omniauth (~> 1.0) omniauth (~> 1.0)
omniauth-oauth2 (~> 1.1) omniauth-oauth2 (~> 1.1)
@ -489,12 +497,6 @@ GEM
rack-attack (4.3.0) rack-attack (4.3.0)
rack rack
rack-cors (0.4.0) rack-cors (0.4.0)
rack-lineprof (0.0.3)
rack (~> 1.5)
rblineprof (~> 0.3.6)
term-ansicolor (~> 1.3)
rack-mini-profiler (0.9.7)
rack (>= 1.1.3)
rack-mount (0.8.3) rack-mount (0.8.3)
rack (>= 1.0.0) rack (>= 1.0.0)
rack-oauth2 (1.0.10) rack-oauth2 (1.0.10)
@ -615,7 +617,7 @@ GEM
sexp_processor (~> 4.1) sexp_processor (~> 4.1)
rubyntlm (0.5.2) rubyntlm (0.5.2)
rubypants (0.2.0) rubypants (0.2.0)
rugged (0.22.2) rugged (0.23.3)
safe_yaml (1.0.4) safe_yaml (1.0.4)
sanitize (2.1.0) sanitize (2.1.0)
nokogiri (>= 1.4.4) nokogiri (>= 1.4.4)
@ -689,8 +691,14 @@ GEM
actionpack (>= 3.0) actionpack (>= 3.0)
activesupport (>= 3.0) activesupport (>= 3.0)
sprockets (>= 2.8, < 4.0) sprockets (>= 2.8, < 4.0)
stamp (0.5.0) stamp (0.6.0)
state_machine (1.2.0) state_machines (0.4.0)
state_machines-activemodel (0.3.0)
activemodel (~> 4.1)
state_machines (>= 0.4.0)
state_machines-activerecord (0.3.0)
activerecord (~> 4.1)
state_machines-activemodel (>= 0.3.0)
stringex (2.5.2) stringex (2.5.2)
systemu (2.6.5) systemu (2.6.5)
task_list (1.0.2) task_list (1.0.2)
@ -777,7 +785,6 @@ PLATFORMS
DEPENDENCIES DEPENDENCIES
RedCloth (~> 4.2.9) RedCloth (~> 4.2.9)
ace-rails-ap (~> 2.0.1) ace-rails-ap (~> 2.0.1)
active_record_query_trace
activerecord-deprecated_finders (~> 1.0.3) activerecord-deprecated_finders (~> 1.0.3)
activerecord-session_store (~> 0.1.0) activerecord-session_store (~> 0.1.0)
acts-as-taggable-on (~> 3.4) acts-as-taggable-on (~> 3.4)
@ -800,7 +807,7 @@ DEPENDENCIES
capybara (~> 2.4.0) capybara (~> 2.4.0)
capybara-screenshot (~> 1.0.0) capybara-screenshot (~> 1.0.0)
carrierwave (~> 0.9.0) carrierwave (~> 0.9.0)
charlock_holmes (~> 0.6.9.4) charlock_holmes (~> 0.7.3)
coffee-rails (~> 4.1.0) coffee-rails (~> 4.1.0)
colored (~> 1.2) colored (~> 1.2)
colorize (~> 0.5.8) colorize (~> 0.5.8)
@ -820,21 +827,23 @@ DEPENDENCIES
enumerize (~> 0.7.0) enumerize (~> 0.7.0)
factory_girl_rails (~> 4.3.0) factory_girl_rails (~> 4.3.0)
ffaker (~> 2.0.0) ffaker (~> 2.0.0)
flay
flog
fog (~> 1.25.0) fog (~> 1.25.0)
font-awesome-rails (~> 4.2) font-awesome-rails (~> 4.2)
foreman foreman
fuubar (~> 2.0.0) fuubar (~> 2.0.0)
gemnasium-gitlab-service (~> 0.2) gemnasium-gitlab-service (~> 0.2)
github-linguist (~> 4.7.0)
github-markup (~> 1.3.1) github-markup (~> 1.3.1)
gitlab-flowdock-git-hook (~> 1.0.1) gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-linguist (~> 3.0.1)
gitlab_emoji (~> 0.1) gitlab_emoji (~> 0.1)
gitlab_git (~> 7.2.19) gitlab_git (~> 7.2.20)
gitlab_meta (= 7.0) gitlab_meta (= 7.0)
gitlab_omniauth-ldap (~> 1.2.1) gitlab_omniauth-ldap (~> 1.2.1)
gollum-lib (~> 4.0.2) gollum-lib (~> 4.0.2)
gon (~> 5.0.0) gon (~> 5.0.0)
grape (~> 0.6.1) grape (~> 0.13.0)
grape-entity (~> 0.4.2) grape-entity (~> 0.4.2)
haml-rails (~> 0.9.0) haml-rails (~> 0.9.0)
hipchat (~> 1.5.0) hipchat (~> 1.5.0)
@ -854,11 +863,12 @@ DEPENDENCIES
nested_form (~> 0.3.2) nested_form (~> 0.3.2)
newrelic-grape newrelic-grape
newrelic_rpm (~> 3.9.4.245) newrelic_rpm (~> 3.9.4.245)
nprogress-rails (~> 0.1.2.3) nprogress-rails (~> 0.1.6.7)
oauth2 (~> 1.0.0) oauth2 (~> 1.0.0)
octokit (~> 3.7.0) octokit (~> 3.7.0)
omniauth (~> 1.2.2) omniauth (~> 1.2.2)
omniauth-bitbucket (~> 0.0.2) omniauth-bitbucket (~> 0.0.2)
omniauth-facebook (~> 3.0.0)
omniauth-github (~> 1.1.1) omniauth-github (~> 1.1.1)
omniauth-gitlab (~> 1.0.0) omniauth-gitlab (~> 1.0.0)
omniauth-google-oauth2 (~> 0.2.0) omniauth-google-oauth2 (~> 0.2.0)
@ -875,11 +885,10 @@ DEPENDENCIES
quiet_assets (~> 1.0.2) quiet_assets (~> 1.0.2)
rack-attack (~> 4.3.0) rack-attack (~> 4.3.0)
rack-cors (~> 0.4.0) rack-cors (~> 0.4.0)
rack-lineprof
rack-mini-profiler (~> 0.9.0)
rack-oauth2 (~> 1.0.5) rack-oauth2 (~> 1.0.5)
rails (= 4.1.12) rails (= 4.1.12)
raphael-rails (~> 2.1.2) raphael-rails (~> 2.1.2)
rblineprof
rdoc (~> 3.6) rdoc (~> 3.6)
redcarpet (~> 3.3.3) redcarpet (~> 3.3.3)
redis-rails (~> 4.0.0) redis-rails (~> 4.0.0)
@ -909,8 +918,8 @@ DEPENDENCIES
spring-commands-spinach (~> 1.0.0) spring-commands-spinach (~> 1.0.0)
spring-commands-teaspoon (~> 0.0.2) spring-commands-teaspoon (~> 0.0.2)
sprockets (~> 2.12.3) sprockets (~> 2.12.3)
stamp (~> 0.5.0) stamp (~> 0.6.0)
state_machine (~> 1.2.0) state_machines-activerecord (~> 0.3.0)
task_list (~> 1.0.2) task_list (~> 1.0.2)
teaspoon (~> 1.0.0) teaspoon (~> 1.0.0)
teaspoon-jasmine (~> 2.2.0) teaspoon-jasmine (~> 2.2.0)

View file

@ -34,13 +34,18 @@ The most important thing is making sure valid issues receive feedback from the d
## Workflow labels ## Workflow labels
Workflow labels are purposely not very detailed since that would be hard to keep updated as you would need to re-evaluate them after every comment. We optionally use functional labels on demand when want to group related issues to get an overview (for example all issues related to RVM, to tackle them in one go) and to add details to the issue. Workflow labels are purposely not very detailed since that would be hard to keep updated as you would need to re-evaluate them after every comment. We optionally use functional labels on demand when want to group related issues to get an overview (for example all issues related to RVM, to tackle them in one go) and to add details to the issue.
- *Awaiting feedback*: Feedback pending from the reporter - *Awaiting feedback*: Feedback pending from the reporter
- *Awaiting confirmation of fix*: The issue should already be solved in **master** (generally you can avoid this workflow item and just close the issue right away) - *Awaiting confirmation of fix*: The issue should already be solved in **master** (generally you can avoid this workflow item and just close the issue right away)
- *Attached MR*: There is a MR attached and the discussion should happen there - *Attached MR*: There is a MR attached and the discussion should happen there
- We need to let issues stay in sync with the MR's. We can do this with a "Closing #XXXX" or "Fixes #XXXX" comment in the MR. We can't close the issue when there is a merge request because sometimes a MR is not good and we just close the MR, then the issue must stay. - We need to let issues stay in sync with the MR's. We can do this with a "Closing #XXXX" or "Fixes #XXXX" comment in the MR. We can't close the issue when there is a merge request because sometimes a MR is not good and we just close the MR, then the issue must stay.
- *Awaiting developer action/feedback*: Issue needs to be fixed or clarified by a developer - *Developer*: needs help from a developer
- *UX* needs needs help from a UX designer
- *Frontend* needs help from a Front-end engineer
- *Graphics* needs help from a Graphics designer
Example workflow: when a UX designer provided a design but it needs frontend work they remove the UX label and add the frontend label.
## Functional labels ## Functional labels
@ -115,3 +120,10 @@ We can only accept a merge request if all the tests are green. I've just
restarted the build. When the tests are still not passing after this restart and restarted the build. When the tests are still not passing after this restart and
you're sure that is does not have anything to do with your code changes, please you're sure that is does not have anything to do with your code changes, please
rebase with master to see if that solves the issue. rebase with master to see if that solves the issue.
### Closing down the issue tracker on GitHub
We are currently in the process of closing down the issue tracker on GitHub, to
prevent duplication with the GitLab.com issue tracker.
Since this is an older issue I'll be closing this for now. If you think this is
still an issue I encourage you to open it on the \[GitLab.com issue tracker\](https://gitlab.com/gitlab-org/gitlab-ce/issues).

View file

@ -1 +1 @@
8.1.0.pre 8.3.0.pre

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

@ -11,10 +11,10 @@ class @EditBlob
if ace_mode if ace_mode
editor.getSession().setMode "ace/mode/" + ace_mode editor.getSession().setMode "ace/mode/" + ace_mode
$(".js-commit-button").click -> # Before a form submission, move the content from the Ace editor into the
$("#file-content").val editor.getValue() # submitted textarea
$(".file-editor form").submit() $('form').submit ->
return false $("#file-content").val(editor.getValue())
editModePanes = $(".js-edit-mode-pane") editModePanes = $(".js-edit-mode-pane")
editModeLinks = $(".js-edit-mode a") editModeLinks = $(".js-edit-mode a")

View file

@ -11,10 +11,10 @@ class @NewBlob
if ace_mode if ace_mode
editor.getSession().setMode "ace/mode/" + ace_mode editor.getSession().setMode "ace/mode/" + ace_mode
$(".js-commit-button").click -> # Before a form submission, move the content from the Ace editor into the
$("#file-content").val editor.getValue() # submitted textarea
$(".file-editor form").submit() $('form').submit ->
return false $("#file-content").val(editor.getValue())
editor: -> editor: ->
return @editor return @editor

View file

@ -25,7 +25,7 @@ class @Calendar
30 30
] ]
legendCellPadding: 3 legendCellPadding: 3
cellSize: $('.user-calendar').width() / 80 cellSize: $('.user-calendar').width() / 73
onClick: (date, count) -> onClick: (date, count) ->
formated_date = date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate() formated_date = date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate()
$.ajax $.ajax

View file

@ -28,6 +28,8 @@ class Dispatcher
when 'projects:milestones:new', 'projects:milestones:edit' when 'projects:milestones:new', 'projects:milestones:edit'
new ZenMode() new ZenMode()
new DropzoneInput($('.milestone-form')) new DropzoneInput($('.milestone-form'))
when 'groups:milestones:new'
new ZenMode()
when 'projects:compare:show' when 'projects:compare:show'
new Diff() new Diff()
when 'projects:issues:new','projects:issues:edit' when 'projects:issues:new','projects:issues:edit'
@ -39,6 +41,12 @@ class Dispatcher
shortcut_handler = new ShortcutsNavigation() shortcut_handler = new ShortcutsNavigation()
new DropzoneInput($('.merge-request-form')) new DropzoneInput($('.merge-request-form'))
new IssuableForm($('.merge-request-form')) new IssuableForm($('.merge-request-form'))
when 'projects:tags:new'
new ZenMode()
new DropzoneInput($('.tag-form'))
when 'projects:releases:edit'
new ZenMode()
new DropzoneInput($('.release-form'))
when 'projects:merge_requests:show' when 'projects:merge_requests:show'
new Diff() new Diff()
shortcut_handler = new ShortcutsIssuable() shortcut_handler = new ShortcutsIssuable()

View file

@ -6,7 +6,7 @@ window.ContributorsStatGraphUtil =
for entry in log for entry in log
@add_date(entry.date, total) unless total[entry.date]? @add_date(entry.date, total) unless total[entry.date]?
data = by_author[entry.author_name] #|| by_email[entry.author_email] data = by_author[entry.author_name] || by_email[entry.author_email]
data ?= @add_author(entry, by_author, by_email) data ?= @add_author(entry, by_author, by_email)
@add_date(entry.date, data) unless data[entry.date] @add_date(entry.date, data) unless data[entry.date]
@ -95,5 +95,4 @@ window.ContributorsStatGraphUtil =
if date_range is null || date_range[0] <= new Date(date) <= date_range[1] if date_range is null || date_range[0] <= new Date(date) <= date_range[1]
true true
else else
false false

View file

@ -28,6 +28,10 @@
border-bottom: 1px solid $border-color; border-bottom: 1px solid $border-color;
color: $gl-gray; color: $gl-gray;
&.oneline-block {
line-height: 42px;
}
&.white { &.white {
background-color: white; background-color: white;
} }
@ -100,7 +104,7 @@
} }
.cover-desc { .cover-desc {
padding: 0 $gl-padding; padding: 0 $gl-padding 3px;
color: $gl-text-color; color: $gl-text-color;
} }

View file

@ -180,3 +180,7 @@
} }
} }
} }
.btn-clipboard {
border: none;
}

View file

@ -9,9 +9,9 @@
.bs-callout { .bs-callout {
margin: 20px 0; margin: 20px 0;
padding: 20px; padding: 20px;
border-left: 3px solid #eee; border-left: 3px solid $border-color;
color: #666; color: $text-color;
background: #f9f9f9; background: $background-color;
} }
.bs-callout h4 { .bs-callout h4 {
margin-top: 0; margin-top: 0;

View file

@ -16,6 +16,7 @@
.append-bottom-10 { margin-bottom:10px } .append-bottom-10 { margin-bottom:10px }
.append-bottom-15 { margin-bottom:15px } .append-bottom-15 { margin-bottom:15px }
.append-bottom-20 { margin-bottom:20px } .append-bottom-20 { margin-bottom:20px }
.append-bottom-default { margin-bottom: $gl-padding; }
.inline { display: inline-block } .inline { display: inline-block }
.center { text-align: center } .center { text-align: center }
@ -327,6 +328,10 @@ table {
} }
} }
.well {
margin-bottom: 0;
}
.search_box { .search_box {
@extend .well; @extend .well;
text-align: center; text-align: center;
@ -387,6 +392,36 @@ table {
} }
} }
.center-middle-menu {
@include nav-menu;
padding: 0;
text-align: center;
margin: -$gl-padding;
margin-top: 0;
margin-bottom: 0;
height: 58px;
border-bottom: 1px solid $border-color;
li {
&:after {
content: "|";
color: $border-gray-light;
}
&:last-child {
&:after {
content: none;
}
}
> a {
display: inline-block;
text-transform: uppercase;
font-size: 13px;
}
}
}
.dropzone .dz-preview .dz-progress { .dropzone .dz-preview .dz-progress {
border-color: $border-color !important; border-color: $border-color !important;
} }

View file

@ -118,6 +118,10 @@ header {
} }
} }
} }
.impersonation i {
color: $red-normal;
}
} }
@mixin collapsed-header { @mixin collapsed-header {

View file

@ -5,7 +5,6 @@ html {
body { body {
padding-top: $header-height; padding-top: $header-height;
text-rendering: geometricPrecision;
} }
} }

View file

@ -117,7 +117,7 @@ ul.content-list {
} }
.controls { .controls {
padding-top: 4px; padding-top: 1px;
float: right; float: right;
.btn { .btn {

View file

@ -106,6 +106,7 @@
} }
.markdown-area { .markdown-area {
@include border-radius(0);
background: #FFF; background: #FFF;
border: 1px solid #ddd; border: 1px solid #ddd;
min-height: 140px; min-height: 140px;

View file

@ -72,9 +72,10 @@
list-style: none; list-style: none;
> li { > li {
@include clearfix;
padding: 10px 0; padding: 10px 0;
border-bottom: 1px solid #EEE; border-bottom: 1px solid #EEE;
overflow: hidden;
display: block; display: block;
margin: 0px; margin: 0px;
@ -137,6 +138,7 @@
&:hover, &:active, &:focus { &:hover, &:active, &:focus {
text-decoration: none; text-decoration: none;
outline: none;
} }
} }

View file

@ -64,6 +64,7 @@
text-decoration: none; text-decoration: none;
padding-left: 22px; padding-left: 22px;
font-weight: normal; font-weight: normal;
outline: none;
&:hover { &:hover {
text-decoration: none; text-decoration: none;
@ -176,6 +177,7 @@
text-align: center; text-align: center;
line-height: 40px; line-height: 40px;
transition-duration: .3s; transition-duration: .3s;
outline: none;
} }
.collapse-nav a:hover { .collapse-nav a:hover {
@ -238,6 +240,7 @@
width: 100%; width: 100%;
padding: 10px 22px; padding: 10px 22px;
overflow: hidden; overflow: hidden;
outline: none;
img { img {
width: 36px; width: 36px;

View file

@ -172,7 +172,7 @@
} }
.panel-body { .panel-body {
form { form, pre {
margin: 0; margin: 0;
} }

View file

@ -173,7 +173,6 @@
* *
*/ */
body { body {
text-rendering:optimizeLegibility;
-webkit-text-shadow: rgba(255,255,255,0.01) 0 0 1px; -webkit-text-shadow: rgba(255,255,255,0.01) 0 0 1px;
} }

View file

@ -21,7 +21,7 @@
.autoscroll-container { .autoscroll-container {
position: fixed; position: fixed;
bottom: 10px; bottom: 20px;
right: 20px; right: 20px;
z-index: 100; z-index: 100;
} }
@ -34,7 +34,7 @@
a { a {
display: block; display: block;
margin-bottom: 5px; margin-bottom: 10px;
} }
} }

View file

@ -56,6 +56,7 @@
li { li {
padding: 3px 0px; padding: 3px 0px;
line-height: 20px;
} }
} }
.new-file { .new-file {

View file

@ -33,6 +33,8 @@
} }
li.commit { li.commit {
list-style: none;
.commit-row-title { .commit-row-title {
font-size: $list-font-size; font-size: $list-font-size;
line-height: 20px; line-height: 20px;
@ -113,3 +115,10 @@ li.commit {
} }
} }
} }
.branch-commit {
color: $gl-gray;
.commit-id, .commit-row-message {
color: $gl-gray;
}
}

View file

@ -367,7 +367,6 @@
.inline-parallel-buttons { .inline-parallel-buttons {
float: right; float: right;
margin-top: -5px;
} }
// Mobile // Mobile

View file

@ -50,7 +50,7 @@
.editor-file-name { .editor-file-name {
.new-file-name { .new-file-name {
display: inline-block; display: inline-block;
width: 200px; width: 450px;
} }
.form-control { .form-control {

View file

@ -4,7 +4,7 @@
*/ */
.event-item { .event-item {
font-size: $gl-font-size; font-size: $gl-font-size;
padding: $gl-padding; padding: $gl-padding $gl-padding $gl-padding ($gl-padding + $gl-avatar-size + 15px);
margin-left: -$gl-padding; margin-left: -$gl-padding;
margin-right: -$gl-padding; margin-right: -$gl-padding;
border-bottom: 1px solid $table-border-color; border-bottom: 1px solid $table-border-color;
@ -16,10 +16,7 @@
top: -2px; top: -2px;
} }
.event-title { .event-title,
line-height: 44px;
}
.event-item-timestamp { .event-item-timestamp {
line-height: 44px; line-height: 44px;
} }
@ -30,7 +27,7 @@
} }
.avatar { .avatar {
margin-right: 15px; margin-left: -($gl-avatar-size + 15px);
} }
.event-title { .event-title {
@ -43,8 +40,7 @@
} }
.event-body { .event-body {
margin-left: 63px; margin-right: 174px;
margin-right: 80px;
.event-note { .event-note {
margin-top: 5px; margin-top: 5px;
@ -155,6 +151,8 @@
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
.event-item { .event-item {
padding-left: $gl-padding;
.event-title { .event-title {
white-space: normal; white-space: normal;
overflow: visible; overflow: visible;

View file

@ -19,6 +19,20 @@
.accept-merge-holder { .accept-merge-holder {
.accept-action { .accept-action {
display: inline-block; display: inline-block;
.accept_merge_request {
&.ci-pending,
&.ci-running {
@include btn-orange;
}
&.ci-skipped,
&.ci-failed,
&.ci-canceled,
&.ci-error {
@include btn-red;
}
}
} }
.accept-control { .accept-control {

View file

@ -56,6 +56,10 @@
.note_text { .note_text {
width: 100%; width: 100%;
} }
.comment-hints {
margin-top: -12px;
}
} }
/* loading indicator */ /* loading indicator */
@ -168,7 +172,7 @@
color: #999; color: #999;
background: #FFF; background: #FFF;
padding: 7px; padding: 7px;
margin-top: -11px; margin-top: -7px;
border: 1px solid $border-color; border: 1px solid $border-color;
font-size: 13px; font-size: 13px;
} }

View file

@ -53,3 +53,25 @@
float: right; float: right;
font-size: 12px; font-size: 12px;
} }
.profile-link-holder {
display: inline;
&:after {
content: "\00B7";
padding: 0px 6px;
font-weight: bold;
}
&:last-child {
&:after {
content: "";
padding: 0;
}
}
a {
color: $blue-dark;
text-decoration: none;
}
}

View file

@ -552,4 +552,4 @@ pre.light-well {
z-index: 100; z-index: 100;
position: relative; position: relative;
} }
} }

View file

@ -0,0 +1,33 @@
table .sherlock-code {
max-width: 700px;
}
.sherlock-code {
pre {
word-wrap: normal;
}
pre code {
white-space: pre;
}
}
.sherlock-line-samples-table {
margin-bottom: 0px !important;
thead tr th,
tbody tr td {
font-size: 13px !important;
text-align: right;
padding: 0px 10px !important;
}
}
.sherlock-file-sample pre {
padding-top: 28px !important;
}
.sherlock-line-samples-table .slow {
color: $red-light;
font-weight: bold;
}

View file

@ -8,4 +8,10 @@ class Admin::ApplicationController < ApplicationController
def authenticate_admin! def authenticate_admin!
return render_404 unless current_user.is_admin? return render_404 unless current_user.is_admin?
end end
def authorize_impersonator!
if session[:impersonator_id]
User.find_by!(username: session[:impersonator_id]).admin?
end
end
end end

View file

@ -57,6 +57,8 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:version_check_enabled, :version_check_enabled,
:admin_notification_email, :admin_notification_email,
:user_oauth_applications, :user_oauth_applications,
:shared_runners_enabled,
:max_artifacts_size,
restricted_visibility_levels: [], restricted_visibility_levels: [],
import_sources: [] import_sources: []
) )

View file

@ -0,0 +1,32 @@
class Admin::ImpersonationController < Admin::ApplicationController
skip_before_action :authenticate_admin!, only: :destroy
before_action :user
before_action :authorize_impersonator!
def create
session[:impersonator_id] = current_user.username
session[:impersonator_return_to] = request.env['HTTP_REFERER']
warden.set_user(user, scope: 'user')
flash[:alert] = "You are impersonating #{user.username}."
redirect_to root_path
end
def destroy
redirect = session[:impersonator_return_to]
warden.set_user(user, scope: 'user')
session[:impersonator_return_to] = nil
session[:impersonator_id] = nil
redirect_to redirect || root_path
end
def user
@user ||= User.find_by!(username: params[:id] || session[:impersonator_id])
end
end

View file

@ -63,12 +63,6 @@ class Admin::UsersController < Admin::ApplicationController
end end
end end
def login_as
sign_in(user)
flash[:alert] = "Logged in as #{user.username}"
redirect_to root_path
end
def disable_two_factor def disable_two_factor
user.disable_two_factor! user.disable_two_factor!
redirect_to admin_user_path(user), redirect_to admin_user_path(user),

View file

@ -59,13 +59,8 @@ class ApplicationController < ActionController::Base
end end
def authenticate_user!(*args) def authenticate_user!(*args)
# If user is not signed-in and tries to access root_path - redirect him to landing page if redirect_to_home_page_url?
# Don't redirect to the default URL to prevent endless redirections redirect_to current_application_settings.home_page_url and return
if current_application_settings.home_page_url.present? &&
current_application_settings.home_page_url.chomp('/') != Gitlab.config.gitlab['url'].chomp('/')
if current_user.nil? && root_path == request.path
redirect_to current_application_settings.home_page_url and return
end
end end
super(*args) super(*args)
@ -346,4 +341,17 @@ class ApplicationController < ActionController::Base
def git_import_enabled? def git_import_enabled?
current_application_settings.import_sources.include?('git') current_application_settings.import_sources.include?('git')
end end
def redirect_to_home_page_url?
# If user is not signed-in and tries to access root_path - redirect him to landing page
# Don't redirect to the default URL to prevent endless redirections
return false unless current_application_settings.home_page_url.present?
home_page_url = current_application_settings.home_page_url.chomp('/')
root_urls = [Gitlab.config.gitlab['url'].chomp('/'), root_url.chomp('/')]
return false if root_urls.include?(home_page_url)
current_user.nil? && root_path == request.path
end
end end

View file

@ -1,21 +0,0 @@
module Ci
class EventsController < Ci::ApplicationController
EVENTS_PER_PAGE = 50
before_action :authenticate_user!
before_action :project
before_action :authorize_manage_project!
layout 'ci/project'
def index
@events = project.events.order("created_at DESC").page(params[:page]).per(EVENTS_PER_PAGE)
end
private
def project
@project ||= Ci::Project.find(params[:project_id])
end
end
end

View file

@ -26,10 +26,6 @@ module Ci
redirect_to namespace_project_runners_path(project.gl_project.namespace, project.gl_project) redirect_to namespace_project_runners_path(project.gl_project.namespace, project.gl_project)
end end
def dumped_yaml
send_data @project.generated_yaml_config, filename: '.gitlab-ci.yml'
end
protected protected
def project def project

View file

@ -4,8 +4,6 @@ module Ci
before_action :project before_action :project
before_action :authorize_manage_project! before_action :authorize_manage_project!
layout 'ci/project'
def create def create
@runner = Ci::Runner.find(params[:runner_project][:runner_id]) @runner = Ci::Runner.find(params[:runner_project][:runner_id])

View file

@ -0,0 +1,19 @@
module GlobalMilestones
extend ActiveSupport::Concern
def milestones
@milestones = MilestonesFinder.new.execute(@projects, params)
@milestones = GlobalMilestone.build_collection(@milestones)
@milestones = Kaminari.paginate_array(@milestones).page(params[:page]).per(ApplicationController::PER_PAGE)
end
def milestone
milestones = Milestone.of_projects(@projects).where(title: params[:title])
if milestones.present?
@milestone = GlobalMilestone.new(params[:title], milestones)
else
render_404
end
end
end

View file

@ -0,0 +1,14 @@
module IssuesAction
extend ActiveSupport::Concern
def issues
@issues = get_issues_collection
@issues = @issues.page(params[:page]).per(ApplicationController::PER_PAGE)
@issues = @issues.preload(:author, :project)
respond_to do |format|
format.html
format.atom { render layout: false }
end
end
end

View file

@ -0,0 +1,9 @@
module MergeRequestsAction
extend ActiveSupport::Concern
def merge_requests
@merge_requests = get_merge_requests_collection
@merge_requests = @merge_requests.page(params[:page]).per(ApplicationController::PER_PAGE)
@merge_requests = @merge_requests.preload(:author, :target_project)
end
end

View file

@ -1,34 +1,19 @@
class Dashboard::MilestonesController < Dashboard::ApplicationController class Dashboard::MilestonesController < Dashboard::ApplicationController
before_action :load_projects include GlobalMilestones
before_action :projects
before_action :milestones, only: [:index]
before_action :milestone, only: [:show]
def index def index
project_milestones = case params[:state]
when 'all'; state
when 'closed'; state('closed')
else state('active')
end
@dashboard_milestones = Milestones::GroupService.new(project_milestones).execute
@dashboard_milestones = Kaminari.paginate_array(@dashboard_milestones).page(params[:page]).per(PER_PAGE)
end end
def show def show
project_milestones = Milestone.where(project_id: @projects).order("due_date ASC")
@dashboard_milestone = Milestones::GroupService.new(project_milestones).milestone(title)
end end
private private
def load_projects def projects
@projects = current_user.authorized_projects.sorted_by_activity.non_archived @projects ||= current_user.authorized_projects.sorted_by_activity.non_archived
end
def title
params[:title]
end
def state(state = nil)
conditions = { project_id: @projects }
conditions.reverse_merge!(state: state) if state
Milestone.where(conditions).order("title ASC")
end end
end end

View file

@ -1,25 +1,12 @@
class DashboardController < Dashboard::ApplicationController class DashboardController < Dashboard::ApplicationController
include IssuesAction
include MergeRequestsAction
before_action :event_filter, only: :activity before_action :event_filter, only: :activity
before_action :projects, only: [:issues, :merge_requests]
respond_to :html respond_to :html
def merge_requests
@merge_requests = get_merge_requests_collection
@merge_requests = @merge_requests.page(params[:page]).per(PER_PAGE)
@merge_requests = @merge_requests.preload(:author, :target_project)
end
def issues
@issues = get_issues_collection
@issues = @issues.page(params[:page]).per(PER_PAGE)
@issues = @issues.preload(:author, :project)
respond_to do |format|
format.html
format.atom { render layout: false }
end
end
def activity def activity
@last_push = current_user.recent_push @last_push = current_user.recent_push
@ -47,4 +34,8 @@ class DashboardController < Dashboard::ApplicationController
@events = @event_filter.apply_filter(@events).with_associations @events = @event_filter.apply_filter(@events).with_associations
@events = @events.limit(20).offset(params[:offset] || 0) @events = @events.limit(20).offset(params[:offset] || 0)
end end
def projects
@projects ||= current_user.authorized_projects.sorted_by_activity.non_archived
end
end end

View file

@ -1,8 +1,13 @@
class Groups::ApplicationController < ApplicationController class Groups::ApplicationController < ApplicationController
layout 'group' layout 'group'
before_action :group
private private
def group
@group ||= Group.find_by(path: params[:group_id])
end
def authorize_read_group! def authorize_read_group!
unless @group and can?(current_user, :read_group, @group) unless @group and can?(current_user, :read_group, @group)
if current_user.nil? if current_user.nil?
@ -12,13 +17,13 @@ class Groups::ApplicationController < ApplicationController
end end
end end
end end
def authorize_admin_group! def authorize_admin_group!
unless can?(current_user, :admin_group, group) unless can?(current_user, :admin_group, group)
return render_404 return render_404
end end
end end
def authorize_admin_group_member! def authorize_admin_group_member!
unless can?(current_user, :admin_group_member, group) unless can?(current_user, :admin_group_member, group)
return render_403 return render_403

View file

@ -1,8 +1,6 @@
class Groups::AvatarsController < ApplicationController class Groups::AvatarsController < Groups::ApplicationController
def destroy def destroy
@group = Group.find_by(path: params[:group_id])
@group.remove_avatar! @group.remove_avatar!
@group.save @group.save
redirect_to edit_group_path(@group) redirect_to edit_group_path(@group)

View file

@ -1,11 +1,9 @@
class Groups::GroupMembersController < Groups::ApplicationController class Groups::GroupMembersController < Groups::ApplicationController
skip_before_action :authenticate_user!, only: [:index] skip_before_action :authenticate_user!, only: [:index]
before_action :group
# Authorize # Authorize
before_action :authorize_read_group! before_action :authorize_read_group!
before_action :authorize_admin_group!, except: [:index, :leave] before_action :authorize_admin_group_member!, except: [:index, :leave]
before_action :authorize_admin_group_member!, only: [:create, :resend_invite]
def index def index
@project = @group.projects.find(params[:project_id]) if params[:project_id] @project = @group.projects.find(params[:project_id]) if params[:project_id]
@ -18,7 +16,8 @@ class Groups::GroupMembersController < Groups::ApplicationController
end end
@members = @members.order('access_level DESC').page(params[:page]).per(50) @members = @members.order('access_level DESC').page(params[:page]).per(50)
@group_member = GroupMember.new
@group_member = @group.group_members.new
end end
def create def create
@ -28,24 +27,23 @@ class Groups::GroupMembersController < Groups::ApplicationController
end end
def update def update
@member = @group.group_members.find(params[:id]) @group_member = @group.group_members.find(params[:id])
return render_403 unless can?(current_user, :update_group_member, @member) return render_403 unless can?(current_user, :update_group_member, @group_member)
@member.update_attributes(member_params) @group_member.update_attributes(member_params)
end end
def destroy def destroy
@group_member = @group.group_members.find(params[:id]) @group_member = @group.group_members.find(params[:id])
if can?(current_user, :destroy_group_member, @group_member) # May fail if last owner. return render_403 unless can?(current_user, :destroy_group_member, @group_member)
@group_member.destroy
respond_to do |format| @group_member.destroy
format.html { redirect_to group_group_members_path(@group), notice: 'User was successfully removed from group.' }
format.js { render nothing: true } respond_to do |format|
end format.html { redirect_to group_group_members_path(@group), notice: 'User was successfully removed from group.' }
else format.js { render nothing: true }
return render_403
end end
end end
@ -64,10 +62,11 @@ class Groups::GroupMembersController < Groups::ApplicationController
end end
def leave def leave
@group_member = @group.group_members.where(user_id: current_user.id).first @group_member = @group.group_members.find_by(user_id: current_user)
if can?(current_user, :destroy_group_member, @group_member) if can?(current_user, :destroy_group_member, @group_member)
@group_member.destroy @group_member.destroy
redirect_to(dashboard_groups_path, notice: "You left #{group.name} group.") redirect_to(dashboard_groups_path, notice: "You left #{group.name} group.")
else else
if @group.last_owner?(current_user) if @group.last_owner?(current_user)
@ -80,10 +79,6 @@ class Groups::GroupMembersController < Groups::ApplicationController
protected protected
def group
@group ||= Group.find_by(path: params[:group_id])
end
def member_params def member_params
params.require(:group_member).permit(:access_level, :user_id) params.require(:group_member).permit(:access_level, :user_id)
end end

View file

@ -1,54 +1,55 @@
class Groups::MilestonesController < Groups::ApplicationController class Groups::MilestonesController < Groups::ApplicationController
before_action :authorize_group_milestone!, only: :update include GlobalMilestones
before_action :projects
before_action :milestones, only: [:index]
before_action :milestone, only: [:show, :update]
before_action :authorize_group_milestone!, only: [:create, :update]
def index def index
project_milestones = case params[:state] end
when 'all'; state
when 'closed'; state('closed') def new
else state('active') @milestone = Milestone.new
end end
@group_milestones = Milestones::GroupService.new(project_milestones).execute
@group_milestones = Kaminari.paginate_array(@group_milestones).page(params[:page]).per(PER_PAGE) def create
project_ids = params[:milestone][:project_ids]
title = milestone_params[:title]
@group.projects.where(id: project_ids).each do |project|
Milestones::CreateService.new(project, current_user, milestone_params).execute
end
redirect_to milestone_path(title)
end end
def show def show
project_milestones = Milestone.where(project_id: group.projects).order("due_date ASC")
@group_milestone = Milestones::GroupService.new(project_milestones).milestone(title)
end end
def update def update
project_milestones = Milestone.where(project_id: group.projects).order("due_date ASC") @milestone.milestones.each do |milestone|
@group_milestones = Milestones::GroupService.new(project_milestones).milestone(title) Milestones::UpdateService.new(milestone.project, current_user, milestone_params).execute(milestone)
@group_milestones.milestones.each do |milestone|
Milestones::UpdateService.new(milestone.project, current_user, params[:milestone]).execute(milestone)
end end
respond_to do |format| redirect_back_or_default(default: milestone_path(@milestone.title))
format.js
format.html do
redirect_to group_milestones_path(group)
end
end
end end
private private
def group
@group ||= Group.find_by(path: params[:group_id])
end
def title
params[:title]
end
def state(state = nil)
conditions = { project_id: group.projects }
conditions.reverse_merge!(state: state) if state
Milestone.where(conditions).order("title ASC")
end
def authorize_group_milestone! def authorize_group_milestone!
return render_404 unless can?(current_user, :admin_group, group) return render_404 unless can?(current_user, :admin_milestones, group)
end
def milestone_params
params.require(:milestone).permit(:title, :description, :due_date, :state_event)
end
def milestone_path(title)
group_milestone_path(@group, title.parameterize, title: title)
end
def projects
@projects ||= @group.projects
end end
end end

View file

@ -1,15 +1,18 @@
class GroupsController < Groups::ApplicationController class GroupsController < Groups::ApplicationController
include IssuesAction
include MergeRequestsAction
skip_before_action :authenticate_user!, only: [:show, :issues, :merge_requests] skip_before_action :authenticate_user!, only: [:show, :issues, :merge_requests]
respond_to :html respond_to :html
before_action :group, except: [:new, :create] before_action :group, except: [:new, :create]
# Authorize # Authorize
before_action :authorize_read_group!, except: [:show, :new, :create] before_action :authorize_read_group!, except: [:show, :new, :create, :autocomplete]
before_action :authorize_admin_group!, only: [:edit, :update, :destroy, :projects] before_action :authorize_admin_group!, only: [:edit, :update, :destroy, :projects]
before_action :authorize_create_group!, only: [:new, :create] before_action :authorize_create_group!, only: [:new, :create]
# Load group projects # Load group projects
before_action :load_projects, except: [:new, :create, :projects, :edit, :update] before_action :load_projects, except: [:new, :create, :projects, :edit, :update, :autocomplete]
before_action :event_filter, only: :show before_action :event_filter, only: :show
layout :determine_layout layout :determine_layout
@ -53,23 +56,6 @@ class GroupsController < Groups::ApplicationController
end end
end end
def merge_requests
@merge_requests = get_merge_requests_collection
@merge_requests = @merge_requests.page(params[:page]).per(PER_PAGE)
@merge_requests = @merge_requests.preload(:author, :target_project)
end
def issues
@issues = get_issues_collection
@issues = @issues.page(params[:page]).per(PER_PAGE)
@issues = @issues.preload(:author, :project)
respond_to do |format|
format.html
format.atom { render layout: false }
end
end
def edit def edit
end end
@ -133,7 +119,7 @@ class GroupsController < Groups::ApplicationController
end end
def group_params def group_params
params.require(:group).permit(:name, :description, :path, :avatar) params.require(:group).permit(:name, :description, :path, :avatar, :public)
end end
def load_events def load_events

View file

@ -29,7 +29,7 @@ class Projects::ApplicationController < ApplicationController
private private
def ci_enabled def ci_enabled
return render_404 unless @project.gitlab_ci? return render_404 unless @project.builds_enabled?
end end
def ci_project def ci_project

View file

@ -161,7 +161,7 @@ class Projects::BlobController < Projects::ApplicationController
if params[:file].present? if params[:file].present?
params[:file_name] = params[:file].original_filename params[:file_name] = params[:file].original_filename
end end
File.join(@path, File.basename(params[:file_name])) File.join(@path, params[:file_name])
else else
@path @path
end end

View file

@ -3,6 +3,7 @@ class Projects::BuildsController < Projects::ApplicationController
before_action :build, except: [:index, :cancel_all] before_action :build, except: [:index, :cancel_all]
before_action :authorize_manage_builds!, except: [:index, :show, :status] before_action :authorize_manage_builds!, except: [:index, :show, :status]
before_action :authorize_download_build_artifacts!, only: [:download]
layout "project" layout "project"
@ -30,7 +31,7 @@ class Projects::BuildsController < Projects::ApplicationController
def show def show
@builds = @ci_project.commits.find_by_sha(@build.sha).builds.order('id DESC') @builds = @ci_project.commits.find_by_sha(@build.sha).builds.order('id DESC')
@builds = @builds.where("id not in (?)", @build.id).page(params[:page]).per(20) @builds = @builds.where("id not in (?)", @build.id)
@commit = @build.commit @commit = @build.commit
respond_to do |format| respond_to do |format|
@ -42,17 +43,25 @@ class Projects::BuildsController < Projects::ApplicationController
end end
def retry def retry
if @build.commands.blank? unless @build.retryable?
return page_404 return page_404
end end
build = Ci::Build.retry(@build) build = Ci::Build.retry(@build)
if params[:return_to] redirect_to build_path(build)
redirect_to URI.parse(params[:return_to]).path end
else
redirect_to build_path(build) def download
unless artifacts_file.file_storage?
return redirect_to artifacts_file.url
end end
unless artifacts_file.exists?
return not_found!
end
send_file artifacts_file.path, disposition: 'attachment'
end end
def status def status
@ -71,6 +80,10 @@ class Projects::BuildsController < Projects::ApplicationController
@build ||= ci_project.builds.unscoped.find_by!(id: params[:id]) @build ||= ci_project.builds.unscoped.find_by!(id: params[:id])
end end
def artifacts_file
build.artifacts_file
end
def build_path(build) def build_path(build)
namespace_project_build_path(build.gl_project.namespace, build.gl_project, build) namespace_project_build_path(build.gl_project.namespace, build.gl_project, build)
end end
@ -80,4 +93,14 @@ class Projects::BuildsController < Projects::ApplicationController
return page_404 return page_404
end end
end end
def authorize_download_build_artifacts!
unless can?(current_user, :download_build_artifacts, @project)
if current_user.nil?
return authenticate_user!
else
return render_404
end
end
end
end end

View file

@ -7,14 +7,14 @@ class Projects::CommitController < Projects::ApplicationController
before_action :authorize_download_code!, except: [:cancel_builds] before_action :authorize_download_code!, except: [:cancel_builds]
before_action :authorize_manage_builds!, only: [:cancel_builds] before_action :authorize_manage_builds!, only: [:cancel_builds]
before_action :commit before_action :commit
before_action :authorize_manage_builds!, only: [:cancel_builds, :retry_builds]
before_action :define_show_vars, only: [:show, :builds]
def show def show
return git_not_found! unless @commit return git_not_found! unless @commit
@line_notes = commit.notes.inline @line_notes = commit.notes.inline
@diffs = @commit.diffs
@note = @project.build_commit_note(commit) @note = @project.build_commit_note(commit)
@notes_count = commit.notes.count
@notes = commit.notes.not_inline.fresh @notes = commit.notes.not_inline.fresh
@noteable = @commit @noteable = @commit
@comments_allowed = @reply_allowed = true @comments_allowed = @reply_allowed = true
@ -23,8 +23,6 @@ class Projects::CommitController < Projects::ApplicationController
commit_id: @commit.id commit_id: @commit.id
} }
@ci_commit = project.ci_commit(commit.sha)
respond_to do |format| respond_to do |format|
format.html format.html
format.diff { render text: @commit.to_diff } format.diff { render text: @commit.to_diff }
@ -32,20 +30,25 @@ class Projects::CommitController < Projects::ApplicationController
end end
end end
def ci def builds
@ci_commit = @project.ci_commit(@commit.sha)
@builds = @ci_commit.builds if @ci_commit
@notes_count = @commit.notes.count
@ci_project = @project.gitlab_ci_project @ci_project = @project.gitlab_ci_project
end end
def cancel_builds def cancel_builds
@ci_commit = @project.ci_commit(@commit.sha) ci_commit.builds.running_or_pending.each(&:cancel)
@ci_commit.builds.running_or_pending.each(&:cancel)
redirect_to ci_namespace_project_commit_path(project.namespace, project, commit.sha) redirect_to builds_namespace_project_commit_path(project.namespace, project, commit.sha)
end end
def retry_builds
ci_commit.builds.latest.failed.each do |build|
if build.retryable?
Ci::Build.retry(build)
end
end
redirect_to builds_namespace_project_commit_path(project.namespace, project, commit.sha)
end
def branches def branches
@branches = @project.repository.branch_names_contains(commit.id) @branches = @project.repository.branch_names_contains(commit.id)
@ -53,11 +56,22 @@ class Projects::CommitController < Projects::ApplicationController
render layout: false render layout: false
end end
private
def commit def commit
@commit ||= @project.commit(params[:id]) @commit ||= @project.commit(params[:id])
end end
private def ci_commit
@ci_commit ||= project.ci_commit(commit.sha)
end
def define_show_vars
@diffs = commit.diffs
@notes_count = commit.notes.count
@builds = ci_commit.builds if ci_commit
end
def authorize_manage_builds! def authorize_manage_builds!
unless can?(current_user, :manage_builds, project) unless can?(current_user, :manage_builds, project)

View file

@ -12,15 +12,16 @@ class Projects::CompareController < Projects::ApplicationController
def show def show
base_ref = Addressable::URI.unescape(params[:from]) base_ref = Addressable::URI.unescape(params[:from])
@ref = head_ref = Addressable::URI.unescape(params[:to]) @ref = head_ref = Addressable::URI.unescape(params[:to])
diff_options = { ignore_whitespace_change: true } if params[:w] == '1'
compare_result = CompareService.new. compare_result = CompareService.new.
execute(@project, head_ref, @project, base_ref) execute(@project, head_ref, @project, base_ref, diff_options)
if compare_result if compare_result
@commits = Commit.decorate(compare_result.commits, @project) @commits = Commit.decorate(compare_result.commits, @project)
@diffs = compare_result.diffs @diffs = compare_result.diffs
@commit = @commits.last @commit = @project.commit(head_ref)
@first_commit = @commits.first @first_commit = @project.commit(base_ref)
@line_notes = [] @line_notes = []
end end
end end

View file

@ -28,8 +28,8 @@ class Projects::ImportsController < Projects::ApplicationController
if @project.import_finished? if @project.import_finished?
redirect_to(project_path(@project)) and return redirect_to(project_path(@project)) and return
else else
redirect_to new_namespace_project_import_path(@project.namespace, redirect_to(new_namespace_project_import_path(@project.namespace,
@project) && return @project)) and return
end end
end end
end end

View file

@ -158,10 +158,12 @@ class Projects::IssuesController < Projects::ApplicationController
end end
def issue_params def issue_params
params.require(:issue).permit( permitted = params.require(:issue).permit(
:title, :assignee_id, :position, :description, :title, :assignee_id, :position, :description,
:milestone_id, :state_event, :task_num, label_ids: [] :milestone_id, :state_event, :task_num, label_ids: []
) )
params[:issue][:title].strip! if params[:issue][:title]
permitted
end end
def bulk_update_params def bulk_update_params

View file

@ -31,6 +31,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
@merge_requests = @merge_requests.page(params[:page]).per(PER_PAGE) @merge_requests = @merge_requests.page(params[:page]).per(PER_PAGE)
@merge_requests = @merge_requests.preload(:target_project)
respond_to do |format| respond_to do |format|
format.html format.html
@ -275,11 +276,13 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
def merge_request_params def merge_request_params
params.require(:merge_request).permit( permitted = params.require(:merge_request).permit(
:title, :assignee_id, :source_project_id, :source_branch, :title, :assignee_id, :source_project_id, :source_branch,
:target_project_id, :target_branch, :milestone_id, :target_project_id, :target_branch, :milestone_id,
:state_event, :description, :task_num, label_ids: [] :state_event, :description, :task_num, label_ids: []
) )
params[:merge_request][:title].strip! if params[:merge_request][:title]
permitted
end end
# Make sure merge requests created before 8.0 # Make sure merge requests created before 8.0

View file

@ -1,6 +1,6 @@
class Projects::ProjectMembersController < Projects::ApplicationController class Projects::ProjectMembersController < Projects::ApplicationController
# Authorize # Authorize
before_action :authorize_admin_project!, except: :leave before_action :authorize_admin_project_member!, except: :leave
def index def index
@project_members = @project.project_members @project_members = @project.project_members
@ -29,10 +29,6 @@ class Projects::ProjectMembersController < Projects::ApplicationController
@project_member = @project.project_members.new @project_member = @project.project_members.new
end end
def new
@project_member = @project.project_members.new
end
def create def create
@project.team.add_users(params[:user_ids].split(','), params[:access_level], current_user) @project.team.add_users(params[:user_ids].split(','), params[:access_level], current_user)
@ -41,11 +37,17 @@ class Projects::ProjectMembersController < Projects::ApplicationController
def update def update
@project_member = @project.project_members.find(params[:id]) @project_member = @project.project_members.find(params[:id])
return render_403 unless can?(current_user, :update_project_member, @project_member)
@project_member.update_attributes(member_params) @project_member.update_attributes(member_params)
end end
def destroy def destroy
@project_member = @project.project_members.find(params[:id]) @project_member = @project.project_members.find(params[:id])
return render_403 unless can?(current_user, :destroy_project_member, @project_member)
@project_member.destroy @project_member.destroy
respond_to do |format| respond_to do |format|
@ -71,16 +73,22 @@ class Projects::ProjectMembersController < Projects::ApplicationController
end end
def leave def leave
if @project.namespace == current_user.namespace @project_member = @project.project_members.find_by(user_id: current_user)
message = 'You can not leave your own project. Transfer or delete the project.'
return redirect_back_or_default(default: { action: 'index' }, options: { alert: message })
end
@project.project_members.find_by(user_id: current_user).destroy if can?(current_user, :destroy_project_member, @project_member)
@project_member.destroy
respond_to do |format| respond_to do |format|
format.html { redirect_to dashboard_projects_path } format.html { redirect_to dashboard_projects_path, notice: "You left the project." }
format.js { render nothing: true } format.js { render nothing: true }
end
else
if current_user == @project.owner
message = 'You can not leave your own project. Transfer or delete the project.'
redirect_back_or_default(default: { action: 'index' }, options: { alert: message })
else
render_403
end
end end
end end

View file

@ -0,0 +1,31 @@
class Projects::ReleasesController < Projects::ApplicationController
# Authorize
before_action :require_non_empty_project
before_action :authorize_download_code!
before_action :authorize_push_code!
before_action :tag
before_action :release
def edit
end
def update
release.update_attributes(release_params)
redirect_to namespace_project_tag_path(@project.namespace, @project, @tag.name)
end
private
def tag
@tag ||= @repository.find_tag(params[:tag_id])
end
def release
@release ||= @project.releases.find_or_initialize_by(tag: @tag.name)
end
def release_params
params.require(:release).permit(:description)
end
end

View file

@ -8,15 +8,23 @@ class Projects::TagsController < Projects::ApplicationController
def index def index
sorted = VersionSorter.rsort(@repository.tag_names) sorted = VersionSorter.rsort(@repository.tag_names)
@tags = Kaminari.paginate_array(sorted).page(params[:page]).per(PER_PAGE) @tags = Kaminari.paginate_array(sorted).page(params[:page]).per(PER_PAGE)
@releases = project.releases.where(tag: @tags)
end
def show
@tag = @repository.find_tag(params[:id])
@release = @project.releases.find_or_initialize_by(tag: @tag.name)
@commit = @repository.commit(@tag.target)
end end
def create def create
result = CreateTagService.new(@project, current_user). result = CreateTagService.new(@project, current_user).
execute(params[:tag_name], params[:ref], params[:message]) execute(params[:tag_name], params[:ref], params[:message], params[:release_description])
if result[:status] == :success if result[:status] == :success
@tag = result[:tag] @tag = result[:tag]
redirect_to namespace_project_tags_path(@project.namespace, @project)
redirect_to namespace_project_tag_path(@project.namespace, @project, @tag.name)
else else
@error = result[:message] @error = result[:message]
render action: 'new' render action: 'new'
@ -26,12 +34,6 @@ class Projects::TagsController < Projects::ApplicationController
def destroy def destroy
DeleteTagService.new(project, current_user).execute(params[:id]) DeleteTagService.new(project, current_user).execute(params[:id])
respond_to do |format| redirect_to namespace_project_tags_path(@project.namespace, @project)
format.html do
redirect_to namespace_project_tags_path(@project.namespace,
@project)
end
format.js
end
end end
end end

View file

@ -1,7 +1,7 @@
class ProjectsController < ApplicationController class ProjectsController < ApplicationController
include ExtractsPath include ExtractsPath
prepend_before_filter :render_go_import, only: [:show] prepend_before_action :render_go_import, only: [:show]
skip_before_action :authenticate_user!, only: [:show, :activity] skip_before_action :authenticate_user!, only: [:show, :activity]
before_action :project, except: [:new, :create] before_action :project, except: [:new, :create]
before_action :repository, except: [:new, :create] before_action :repository, except: [:new, :create]
@ -72,8 +72,7 @@ class ProjectsController < ApplicationController
def remove_fork def remove_fork
return access_denied! unless can?(current_user, :remove_fork_project, @project) return access_denied! unless can?(current_user, :remove_fork_project, @project)
if @project.forked? if @project.unlink_fork
@project.forked_project_link.destroy
flash[:notice] = 'The fork relationship has been removed.' flash[:notice] = 'The fork relationship has been removed.'
end end
end end
@ -213,7 +212,8 @@ class ProjectsController < ApplicationController
params.require(:project).permit( params.require(:project).permit(
:name, :path, :description, :issues_tracker, :tag_list, :name, :path, :description, :issues_tracker, :tag_list,
:issues_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id, :default_branch, :issues_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id, :default_branch,
:wiki_enabled, :visibility_level, :import_url, :last_activity_at, :namespace_id, :avatar :wiki_enabled, :visibility_level, :import_url, :last_activity_at, :namespace_id, :avatar,
:builds_enabled
) )
end end
@ -242,7 +242,7 @@ class ProjectsController < ApplicationController
project.repository_exists? && !project.empty_repo? project.repository_exists? && !project.empty_repo?
end end
# Override get_id from ExtractsPath, which returns the branch and file path # Override get_id from ExtractsPath, which returns the branch and file path
# for the blob/tree, which in this case is just the root of the default branch. # for the blob/tree, which in this case is just the root of the default branch.
def get_id def get_id
project.repository.root_ref project.repository.root_ref

View file

@ -23,8 +23,8 @@ class SearchController < ApplicationController
@search_results = @search_results =
if @project if @project
unless %w(blobs notes issues merge_requests milestones wiki_blobs). unless %w(blobs notes issues merge_requests milestones wiki_blobs
include?(@scope) commits).include?(@scope)
@scope = 'blobs' @scope = 'blobs'
end end

View file

@ -0,0 +1,12 @@
module Sherlock
class ApplicationController < ::ApplicationController
before_action :find_transaction
def find_transaction
if params[:transaction_id]
@transaction = Gitlab::Sherlock.collection.
find_transaction(params[:transaction_id])
end
end
end
end

View file

@ -0,0 +1,7 @@
module Sherlock
class FileSamplesController < Sherlock::ApplicationController
def show
@file_sample = @transaction.find_file_sample(params[:id])
end
end
end

View file

@ -0,0 +1,7 @@
module Sherlock
class QueriesController < Sherlock::ApplicationController
def show
@query = @transaction.find_query(params[:id])
end
end
end

View file

@ -0,0 +1,19 @@
module Sherlock
class TransactionsController < Sherlock::ApplicationController
def index
@transactions = Gitlab::Sherlock.collection.newest_first
end
def show
@transaction = Gitlab::Sherlock.collection.find_transaction(params[:id])
render_404 unless @transaction
end
def destroy_all
Gitlab::Sherlock.collection.clear
redirect_to(:back)
end
end
end

View file

@ -3,14 +3,11 @@ class UsersController < ApplicationController
before_action :set_user before_action :set_user
def show def show
@contributed_projects = contributed_projects.joined(@user). @contributed_projects = contributed_projects.joined(@user).reject(&:forked?)
reject(&:forked?)
@projects = @user.personal_projects. @projects = PersonalProjectsFinder.new(@user).execute(current_user)
where(id: authorized_projects_ids).includes(:namespace)
# Collect only groups common for both users @groups = JoinedGroupsFinder.new(@user).execute(current_user)
@groups = @user.groups & GroupsFinder.new.execute(current_user)
respond_to do |format| respond_to do |format|
format.html format.html
@ -53,16 +50,8 @@ class UsersController < ApplicationController
@user = User.find_by_username!(params[:username]) @user = User.find_by_username!(params[:username])
end end
def authorized_projects_ids
# Projects user can view
@authorized_projects_ids ||=
ProjectsFinder.new.execute(current_user).pluck(:id)
end
def contributed_projects def contributed_projects
@contributed_projects = Project. ContributedProjectsFinder.new(@user).execute(current_user)
where(id: authorized_projects_ids & @user.contributed_projects_ids).
includes(:namespace)
end end
def contributions_calendar def contributions_calendar
@ -73,9 +62,13 @@ class UsersController < ApplicationController
def load_events def load_events
# Get user activity feed for projects common for both users # Get user activity feed for projects common for both users
@events = @user.recent_events. @events = @user.recent_events.
where(project_id: authorized_projects_ids). merge(projects_for_current_user).
with_associations references(:project).
with_associations.
limit_recent(20, params[:offset])
end
@events = @events.limit(20).offset(params[:offset] || 0) def projects_for_current_user
ProjectsFinder.new.execute(current_user)
end end
end end

View file

@ -0,0 +1,37 @@
class ContributedProjectsFinder
def initialize(user)
@user = user
end
# Finds the projects "@user" contributed to, limited to either public projects
# or projects visible to the given user.
#
# current_user - When given the list of the projects is limited to those only
# visible by this user.
#
# Returns an ActiveRecord::Relation.
def execute(current_user = nil)
if current_user
relation = projects_visible_to_user(current_user)
else
relation = public_projects
end
relation.includes(:namespace).order_id_desc
end
private
def projects_visible_to_user(current_user)
authorized = @user.contributed_projects.visible_to_user(current_user)
union = Gitlab::SQL::Union.
new([authorized.select(:id), public_projects.select(:id)])
Project.where("projects.id IN (#{union.to_sql})")
end
def public_projects
@user.contributed_projects.public_only
end
end

View file

@ -1,38 +1,44 @@
class GroupsFinder class GroupsFinder
def execute(current_user, options = {}) # Finds the groups available to the given user.
all_groups(current_user) #
# current_user - The user to find the groups for.
#
# Returns an ActiveRecord::Relation.
def execute(current_user = nil)
if current_user
relation = groups_visible_to_user(current_user)
else
relation = public_groups
end
relation.order_id_desc
end end
private private
def all_groups(current_user) # This method returns the groups "current_user" can see.
if current_user def groups_visible_to_user(current_user)
if current_user.authorized_groups.any? base = groups_for_projects(public_and_internal_projects)
# User has access to groups
# union = Gitlab::SQL::Union.
# Return only: new([base.select(:id), current_user.authorized_groups.select(:id)])
# groups with public projects
# groups with internal projects Group.where("namespaces.id IN (#{union.to_sql})")
# groups with joined projects end
#
group_ids = Project.public_and_internal_only.pluck(:namespace_id) + def public_groups
current_user.authorized_groups.pluck(:id) groups_for_projects(public_projects)
Group.where(id: group_ids) end
else
# User has no group membership def groups_for_projects(projects)
# Group.public_and_given_groups(projects.select(:namespace_id))
# Return only: end
# groups with public projects
# groups with internal projects def public_projects
# Project.unscoped.public_only
Group.where(id: Project.public_and_internal_only.pluck(:namespace_id)) end
end
else def public_and_internal_projects
# Not authenticated Project.unscoped.public_and_internal_only
#
# Return only:
# groups with public projects
Group.where(id: Project.public_only.pluck(:namespace_id))
end
end end
end end

View file

@ -0,0 +1,49 @@
# Class for finding the groups a user is a member of.
class JoinedGroupsFinder
def initialize(user = nil)
@user = user
end
# Finds the groups of the source user, optionally limited to those visible to
# the current user.
#
# current_user - If given the groups of "@user" will only include the groups
# "current_user" can also see.
#
# Returns an ActiveRecord::Relation.
def execute(current_user = nil)
if current_user
relation = groups_visible_to_user(current_user)
else
relation = public_groups
end
relation.order_id_desc
end
private
# Returns the groups the user in "current_user" can see.
#
# This list includes all public/internal projects as well as the projects of
# "@user" that "current_user" also has access to.
def groups_visible_to_user(current_user)
base = @user.authorized_groups.visible_to_user(current_user)
extra = public_and_internal_groups
union = Gitlab::SQL::Union.new([base.select(:id), extra.select(:id)])
Group.where("namespaces.id IN (#{union.to_sql})")
end
def public_groups
groups_for_projects(@user.authorized_projects.public_only)
end
def public_and_internal_groups
groups_for_projects(@user.authorized_projects.public_and_internal_only)
end
def groups_for_projects(projects)
@user.groups.public_and_given_groups(projects.select(:namespace_id))
end
end

View file

@ -0,0 +1,12 @@
class MilestonesFinder
def execute(projects, params)
milestones = Milestone.of_projects(projects)
milestones = milestones.order("due_date ASC")
case params[:state]
when 'closed' then milestones.closed
when 'all' then milestones
else milestones.active
end
end
end

View file

@ -0,0 +1,41 @@
class PersonalProjectsFinder
def initialize(user)
@user = user
end
# Finds the projects belonging to the user in "@user", limited to either
# public projects or projects visible to the given user.
#
# current_user - When given the list of projects is limited to those only
# visible by this user.
#
# Returns an ActiveRecord::Relation.
def execute(current_user = nil)
if current_user
relation = projects_visible_to_user(current_user)
else
relation = public_projects
end
relation.includes(:namespace).order_id_desc
end
private
def projects_visible_to_user(current_user)
authorized = @user.personal_projects.visible_to_user(current_user)
union = Gitlab::SQL::Union.
new([authorized.select(:id), public_and_internal_projects.select(:id)])
Project.where("projects.id IN (#{union.to_sql})")
end
def public_projects
@user.personal_projects.public_only
end
def public_and_internal_projects
@user.personal_projects.public_and_internal_only
end
end

View file

@ -1,11 +1,39 @@
class ProjectsFinder class ProjectsFinder
def execute(current_user, options = {}) # Returns all projects, optionally including group projects a user has access
# to.
#
# ## Examples
#
# Retrieving all public projects:
#
# ProjectsFinder.new.execute
#
# Retrieving all public/internal projects and those the given user has access
# to:
#
# ProjectsFinder.new.execute(some_user)
#
# Retrieving all public/internal projects as well as the group's projects the
# user has access to:
#
# ProjectsFinder.new.execute(some_user, group: some_group)
#
# Returns an ActiveRecord::Relation.
def execute(current_user = nil, options = {})
group = options[:group] group = options[:group]
if group if group
group_projects(current_user, group) base, extra = group_projects(current_user, group)
else else
all_projects(current_user) base, extra = all_projects(current_user)
end
if base and extra
union = Gitlab::SQL::Union.new([base.select(:id), extra.select(:id)])
Project.where("projects.id IN (#{union.to_sql})")
else
base
end end
end end
@ -13,77 +41,36 @@ class ProjectsFinder
def group_projects(current_user, group) def group_projects(current_user, group)
if current_user if current_user
if group.users.include?(current_user) [
# User is group member group_projects_for_user(current_user, group),
# group.projects.public_and_internal_only
# Return ALL group projects ]
group.projects
else
projects_members = ProjectMember.in_projects(group.projects).
with_user(current_user)
if projects_members.any?
# User is a project member
#
# Return only:
# public projects
# internal projects
# joined projects
#
group.projects.where(
"projects.id IN (?) OR projects.visibility_level IN (?)",
projects_members.pluck(:source_id),
Project.public_and_internal_levels
)
else
# User has no access to group or group projects
#
# Return only:
# public projects
# internal projects
#
group.projects.public_and_internal_only
end
end
else else
# Not authenticated [group.projects.public_only]
#
# Return only:
# public projects
group.projects.public_only
end end
end end
def all_projects(current_user) def all_projects(current_user)
if current_user if current_user
if current_user.authorized_projects.any? [current_user.authorized_projects, public_and_internal_projects]
# User has access to private projects
#
# Return only:
# public projects
# internal projects
# joined projects
#
Project.where(
"projects.id IN (?) OR projects.visibility_level IN (?)",
current_user.authorized_projects.pluck(:id),
Project.public_and_internal_levels
)
else
# User has no access to private projects
#
# Return only:
# public projects
# internal projects
#
Project.public_and_internal_only
end
else else
# Not authenticated [Project.public_only]
#
# Return only:
# public projects
Project.public_only
end end
end end
def group_projects_for_user(current_user, group)
if group.users.include?(current_user)
group.projects
else
group.projects.visible_to_user(current_user)
end
end
def public_projects
Project.unscoped.public_only
end
def public_and_internal_projects
Project.unscoped.public_and_internal_only
end
end end

View file

@ -1,5 +1,5 @@
module AuthHelper module AuthHelper
PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2).freeze PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2 facebook).freeze
FORM_BASED_PROVIDERS = [/\Aldap/, 'crowd'].freeze FORM_BASED_PROVIDERS = [/\Aldap/, 'crowd'].freeze
def ldap_enabled? def ldap_enabled?

View file

@ -1,13 +0,0 @@
module BuildsHelper
def build_ref_link build
gitlab_ref_link build.project, build.ref
end
def build_commit_link build
gitlab_commit_link build.project, build.short_sha
end
def build_url(build)
namespace_project_build_path(build.gl_project, build.project, build)
end
end

View file

@ -4,25 +4,6 @@ module Ci
{ :"data-no-turbolink" => "data-no-turbolink" } { :"data-no-turbolink" => "data-no-turbolink" }
end end
def gitlab_ref_link project, ref
gitlab_url = project.gitlab_url.dup
gitlab_url << "/commits/#{ref}"
link_to ref, gitlab_url, no_turbolink
end
def gitlab_compare_link project, before, after
gitlab_url = project.gitlab_url.dup
gitlab_url << "/compare/#{before}...#{after}"
link_to "#{before}...#{after}", gitlab_url, no_turbolink
end
def gitlab_commit_link project, sha
gitlab_url = project.gitlab_url.dup
gitlab_url << "/commit/#{sha}"
link_to Ci::Commit.truncate_sha(sha), gitlab_url, no_turbolink
end
def yaml_web_editor_link(project) def yaml_web_editor_link(project)
commits = project.commits commits = project.commits

View file

@ -1,7 +1,7 @@
module CiStatusHelper module CiStatusHelper
def ci_status_path(ci_commit) def ci_status_path(ci_commit)
project = ci_commit.gl_project project = ci_commit.gl_project
ci_namespace_project_commit_path(project.namespace, project, ci_commit.sha) builds_namespace_project_commit_path(project.namespace, project, ci_commit.sha)
end end
def ci_status_icon(ci_commit) def ci_status_icon(ci_commit)

View file

@ -1,4 +1,8 @@
module DiffHelper module DiffHelper
def diff_view
params[:view] == 'parallel' ? 'parallel' : 'inline'
end
def allowed_diff_size def allowed_diff_size
if diff_hard_limit_enabled? if diff_hard_limit_enabled?
Commit::DIFF_HARD_LIMIT_FILES Commit::DIFF_HARD_LIMIT_FILES
@ -132,25 +136,11 @@ module DiffHelper
end end
def inline_diff_btn def inline_diff_btn
params_copy = params.dup diff_btn('Inline', 'inline', diff_view == 'inline')
params_copy[:view] = 'inline'
# Always use HTML to handle case where JSON diff rendered this button
params_copy.delete(:format)
link_to url_for(params_copy), id: "inline-diff-btn", class: (params[:view] != 'parallel' ? 'btn btn-sm active' : 'btn btn-sm') do
'Inline'
end
end end
def parallel_diff_btn def parallel_diff_btn
params_copy = params.dup diff_btn('Side-by-side', 'parallel', diff_view == 'parallel')
params_copy[:view] = 'parallel'
# Always use HTML to handle case where JSON diff rendered this button
params_copy.delete(:format)
link_to url_for(params_copy), id: "parallel-diff-btn", class: (params[:view] == 'parallel' ? 'btn active btn-sm' : 'btn btn-sm') do
'Side-by-side'
end
end end
def submodule_link(blob, ref, repository = @repository) def submodule_link(blob, ref, repository = @repository)
@ -171,7 +161,7 @@ module DiffHelper
def commit_for_diff(diff) def commit_for_diff(diff)
if diff.deleted_file if diff.deleted_file
first_commit = @first_commit || @commit first_commit = @first_commit || @commit
first_commit.parent first_commit.parent || @first_commit
else else
@commit @commit
end end
@ -187,4 +177,18 @@ module DiffHelper
def editable_diff?(diff) def editable_diff?(diff)
!diff.deleted_file && @merge_request && @merge_request.source_project !diff.deleted_file && @merge_request && @merge_request.source_project
end end
private
def diff_btn(title, name, selected)
params_copy = params.dup
params_copy[:view] = name
# Always use HTML to handle case where JSON diff rendered this button
params_copy.delete(:format)
link_to url_for(params_copy), id: "#{name}-diff-btn", class: (selected ? 'btn active' : 'btn') do
title
end
end
end end

View file

@ -108,19 +108,23 @@ module EventsHelper
end end
end end
elsif event.push? elsif event.push?
if event.push_with_commits? && event.md_ref? push_event_feed_url(event)
if event.commits_count > 1 end
namespace_project_compare_url(event.project.namespace, event.project, end
from: event.commit_from, to:
event.commit_to) def push_event_feed_url(event)
else if event.push_with_commits? && event.md_ref?
namespace_project_commit_url(event.project.namespace, event.project, if event.commits_count > 1
id: event.commit_to) namespace_project_compare_url(event.project.namespace, event.project,
end from: event.commit_from, to:
event.commit_to)
else else
namespace_project_commits_url(event.project.namespace, event.project, namespace_project_commit_url(event.project.namespace, event.project,
event.ref_name) id: event.commit_to)
end end
else
namespace_project_commits_url(event.project.namespace, event.project,
event.ref_name)
end end
end end
@ -198,7 +202,7 @@ module EventsHelper
xml.link href: event_link xml.link href: event_link
xml.title truncate(event_title, length: 80) xml.title truncate(event_title, length: 80)
xml.updated event.created_at.xmlschema xml.updated event.created_at.xmlschema
xml.media :thumbnail, width: "40", height: "40", url: avatar_icon(event.author_email) xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(event.author_email))
xml.author do |author| xml.author do |author|
xml.name event.author_name xml.name event.author_name
xml.email event.author_email xml.email event.author_email

View file

@ -49,7 +49,7 @@ module GitlabMarkdownHelper
return "" unless text.present? return "" unless text.present?
context[:project] ||= @project context[:project] ||= @project
html = Gitlab::Markdown.render(text, context) html = Gitlab::Markdown.render(text, context)
context.merge!( context.merge!(

View file

@ -74,7 +74,7 @@ module IssuesHelper
issue.project, issue) issue.project, issue)
xml.title truncate(issue.title, length: 80) xml.title truncate(issue.title, length: 80)
xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ")
xml.media :thumbnail, width: "40", height: "40", url: avatar_icon(issue.author_email) xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(issue.author_email))
xml.author do |author| xml.author do |author|
xml.name issue.author_name xml.name issue.author_name
xml.email issue.author_email xml.email issue.author_email

View file

@ -100,7 +100,7 @@ module LabelsHelper
Label.where(project_id: @projects) Label.where(project_id: @projects)
end end
grouped_labels = Labels::GroupService.new(labels).execute grouped_labels = GlobalLabel.build_collection(labels)
grouped_labels.unshift(Label::None) grouped_labels.unshift(Label::None)
grouped_labels.unshift(Label::Any) grouped_labels.unshift(Label::Any)

View file

@ -28,7 +28,7 @@ module MilestonesHelper
Milestone.where(project_id: @projects) Milestone.where(project_id: @projects)
end.active end.active
grouped_milestones = Milestones::GroupService.new(milestones).execute grouped_milestones = GlobalMilestone.build_collection(milestones)
grouped_milestones.unshift(Milestone::None) grouped_milestones.unshift(Milestone::None)
grouped_milestones.unshift(Milestone::Any) grouped_milestones.unshift(Milestone::Any)

View file

@ -17,15 +17,6 @@ module NamespacesHelper
grouped_options_for_select(options, selected) grouped_options_for_select(options, selected)
end end
def namespace_select_tag(id, opts = {})
css_class = "ajax-namespace-select "
css_class << "multiselect " if opts[:multiple]
css_class << (opts[:class] || '')
value = opts[:selected] || ''
hidden_field_tag(id, value, class: css_class)
end
def namespace_icon(namespace, size = 40) def namespace_icon(namespace, size = 40)
if namespace.kind_of?(Group) if namespace.kind_of?(Group)
group_icon(namespace) group_icon(namespace)

View file

@ -16,40 +16,28 @@ module NotificationsHelper
def notification_list_item(notification_level, user_membership) def notification_list_item(notification_level, user_membership)
case notification_level case notification_level
when Notification::N_DISABLED when Notification::N_DISABLED
content_tag(:li, class: active_level_for(user_membership, Notification::N_DISABLED)) do update_notification_link(Notification::N_DISABLED, user_membership, 'Disabled', 'microphone-slash')
link_to '#', class: 'update-notification', data: { notification_level: Notification::N_DISABLED } do
icon('microphone-slash fw', text: 'Disabled')
end
end
when Notification::N_PARTICIPATING when Notification::N_PARTICIPATING
content_tag(:li, class: active_level_for(user_membership, Notification::N_PARTICIPATING)) do update_notification_link(Notification::N_PARTICIPATING, user_membership, 'Participate', 'volume-up')
link_to '#', class: 'update-notification', data: { notification_level: Notification::N_PARTICIPATING } do
icon('volume-up fw', text: 'Participate')
end
end
when Notification::N_WATCH when Notification::N_WATCH
content_tag(:li, class: active_level_for(user_membership, Notification::N_WATCH)) do update_notification_link(Notification::N_WATCH, user_membership, 'Watch', 'eye')
link_to '#', class: 'update-notification', data: { notification_level: Notification::N_WATCH } do
icon('eye fw', text: 'Watch')
end
end
when Notification::N_MENTION when Notification::N_MENTION
content_tag(:li, class: active_level_for(user_membership, Notification::N_MENTION)) do update_notification_link(Notification::N_MENTION, user_membership, 'On mention', 'at')
link_to '#', class: 'update-notification', data: { notification_level: Notification::N_MENTION } do
icon('at fw', text: 'On mention')
end
end
when Notification::N_GLOBAL when Notification::N_GLOBAL
content_tag(:li, class: active_level_for(user_membership, Notification::N_GLOBAL)) do update_notification_link(Notification::N_GLOBAL, user_membership, 'Global', 'globe')
link_to '#', class: 'update-notification', data: { notification_level: Notification::N_GLOBAL } do
icon('globe fw', text: 'Global')
end
end
else else
# do nothing # do nothing
end end
end end
def update_notification_link(notification_level, user_membership, title, icon)
content_tag(:li, class: active_level_for(user_membership, notification_level)) do
link_to '#', class: 'update-notification', data: { notification_level: notification_level } do
icon("#{icon} fw", text: title)
end
end
end
def notification_label(user_membership) def notification_label(user_membership)
Notification.new(user_membership).to_s Notification.new(user_membership).to_s
end end

View file

@ -117,7 +117,7 @@ module ProjectsHelper
nav_tabs << :merge_requests nav_tabs << :merge_requests
end end
if project.gitlab_ci? && can?(current_user, :read_build, project) if project.builds_enabled? && can?(current_user, :read_build, project)
nav_tabs << :builds nav_tabs << :builds
end end
@ -253,14 +253,6 @@ module ProjectsHelper
filename_path(project, :version) filename_path(project, :version)
end end
def hidden_pass_url(original_url)
result = URI(original_url)
result.password = '*****' unless result.password.nil?
result
rescue
original_url
end
def project_wiki_path_with_version(proj, page, version, is_newest) def project_wiki_path_with_version(proj, page, version, is_newest)
url_params = is_newest ? {} : { version_id: version } url_params = is_newest ? {} : { version_id: version }
namespace_project_wiki_path(proj.namespace, proj, page, url_params) namespace_project_wiki_path(proj.namespace, proj, page, url_params)

View file

@ -70,7 +70,7 @@ module SearchHelper
# Autocomplete results for the current user's groups # Autocomplete results for the current user's groups
def groups_autocomplete(term, limit = 5) def groups_autocomplete(term, limit = 5)
current_user.authorized_groups.search(term).limit(limit).map do |group| GroupsFinder.new.execute(current_user).search(term).limit(limit).map do |group|
{ {
label: "group: #{search_result_sanitize(group.name)}", label: "group: #{search_result_sanitize(group.name)}",
url: group_path(group) url: group_path(group)

View file

@ -35,8 +35,20 @@ module SelectsHelper
end end
def groups_select_tag(id, opts = {}) def groups_select_tag(id, opts = {})
css_class = "ajax-groups-select " opts[:class] ||= ''
css_class << "multiselect " if opts[:multiple] opts[:class] << ' ajax-groups-select'
select2_tag(id, opts)
end
def namespace_select_tag(id, opts = {})
opts[:class] ||= ''
opts[:class] << ' ajax-namespace-select'
select2_tag(id, opts)
end
def select2_tag(id, opts = {})
css_class = ''
css_class << 'multiselect ' if opts[:multiple]
css_class << (opts[:class] || '') css_class << (opts[:class] || '')
value = opts[:selected] || '' value = opts[:selected] || ''

View file

@ -1,53 +1,49 @@
module Emails module Emails
module Issues module Issues
def new_issue_email(recipient_id, issue_id) def new_issue_email(recipient_id, issue_id)
@issue = Issue.find(issue_id) issue_mail_with_notification(issue_id, recipient_id) do
@project = @issue.project mail_new_thread(@issue, issue_thread_options(@issue.author_id, recipient_id))
@target_url = namespace_project_issue_url(@project.namespace, @project, @issue) end
mail_new_thread(@issue,
from: sender(@issue.author_id),
to: recipient(recipient_id),
subject: subject("#{@issue.title} (##{@issue.iid})"))
SentNotification.record(@issue, recipient_id, reply_key)
end end
def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id, updated_by_user_id) def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id, updated_by_user_id)
@issue = Issue.find(issue_id) issue_mail_with_notification(issue_id, recipient_id) do
@previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id @previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id
@project = @issue.project mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id))
@target_url = namespace_project_issue_url(@project.namespace, @project, @issue) end
mail_answer_thread(@issue,
from: sender(updated_by_user_id),
to: recipient(recipient_id),
subject: subject("#{@issue.title} (##{@issue.iid})"))
SentNotification.record(@issue, recipient_id, reply_key)
end end
def closed_issue_email(recipient_id, issue_id, updated_by_user_id) def closed_issue_email(recipient_id, issue_id, updated_by_user_id)
@issue = Issue.find issue_id issue_mail_with_notification(issue_id, recipient_id) do
@project = @issue.project @updated_by = User.find updated_by_user_id
@updated_by = User.find updated_by_user_id mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id))
@target_url = namespace_project_issue_url(@project.namespace, @project, @issue) end
mail_answer_thread(@issue,
from: sender(updated_by_user_id),
to: recipient(recipient_id),
subject: subject("#{@issue.title} (##{@issue.iid})"))
SentNotification.record(@issue, recipient_id, reply_key)
end end
def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id) def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id)
@issue = Issue.find issue_id issue_mail_with_notification(issue_id, recipient_id) do
@issue_status = status @issue_status = status
@updated_by = User.find updated_by_user_id
mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id))
end
end
private
def issue_thread_options(sender_id, recipient_id)
{
from: sender(sender_id),
to: recipient(recipient_id),
subject: subject("#{@issue.title} (##{@issue.iid})")
}
end
def issue_mail_with_notification(issue_id, recipient_id)
@issue = Issue.find(issue_id)
@project = @issue.project @project = @issue.project
@updated_by = User.find updated_by_user_id
@target_url = namespace_project_issue_url(@project.namespace, @project, @issue) @target_url = namespace_project_issue_url(@project.namespace, @project, @issue)
mail_answer_thread(@issue,
from: sender(updated_by_user_id), yield
to: recipient(recipient_id),
subject: subject("#{@issue.title} (##{@issue.iid})"))
SentNotification.record(@issue, recipient_id, reply_key) SentNotification.record(@issue, recipient_id, reply_key)
end end

Some files were not shown because too many files have changed in this diff Show more