Merge branch 'master' into reference-pipeline-and-caching
This commit is contained in:
commit
f5a630111f
571 changed files with 9843 additions and 3255 deletions
1
.flayignore
Normal file
1
.flayignore
Normal file
|
@ -0,0 +1 @@
|
||||||
|
*.erb
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -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/*
|
||||||
|
|
|
@ -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
|
||||||
|
|
64
CHANGELOG
64
CHANGELOG
|
@ -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.
|
||||||
|
|
|
@ -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/)
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
0.3.0
|
|
|
@ -1 +1 @@
|
||||||
2.6.5
|
2.6.7
|
||||||
|
|
1
GITLAB_WORKHORSE
Normal file
1
GITLAB_WORKHORSE
Normal file
|
@ -0,0 +1 @@
|
||||||
|
0.4.1
|
1
GITLAB_WORKHORSE_VERSION
Normal file
1
GITLAB_WORKHORSE_VERSION
Normal file
|
@ -0,0 +1 @@
|
||||||
|
0.3.1
|
25
Gemfile
25
Gemfile
|
@ -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
|
||||||
|
|
75
Gemfile.lock
75
Gemfile.lock
|
@ -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)
|
||||||
|
|
14
PROCESS.md
14
PROCESS.md
|
@ -40,7 +40,12 @@ Workflow labels are purposely not very detailed since that would be hard to keep
|
||||||
- *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).
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
8.1.0.pre
|
8.3.0.pre
|
||||||
|
|
BIN
app/assets/images/auth_buttons/facebook_64.png
Normal file
BIN
app/assets/images/auth_buttons/facebook_64.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
|
@ -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")
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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]
|
||||||
|
@ -96,4 +96,3 @@ window.ContributorsStatGraphUtil =
|
||||||
true
|
true
|
||||||
else
|
else
|
||||||
false
|
false
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -180,3 +180,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-clipboard {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,6 +118,10 @@ header {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.impersonation i {
|
||||||
|
color: $red-normal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin collapsed-header {
|
@mixin collapsed-header {
|
||||||
|
|
|
@ -5,7 +5,6 @@ html {
|
||||||
|
|
||||||
body {
|
body {
|
||||||
padding-top: $header-height;
|
padding-top: $header-height;
|
||||||
text-rendering: geometricPrecision;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,7 +117,7 @@ ul.content-list {
|
||||||
}
|
}
|
||||||
|
|
||||||
.controls {
|
.controls {
|
||||||
padding-top: 4px;
|
padding-top: 1px;
|
||||||
float: right;
|
float: right;
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -172,7 +172,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel-body {
|
.panel-body {
|
||||||
form {
|
form, pre {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
|
|
||||||
li {
|
li {
|
||||||
padding: 3px 0px;
|
padding: 3px 0px;
|
||||||
|
line-height: 20px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.new-file {
|
.new-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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -367,7 +367,6 @@
|
||||||
|
|
||||||
.inline-parallel-buttons {
|
.inline-parallel-buttons {
|
||||||
float: right;
|
float: right;
|
||||||
margin-top: -5px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mobile
|
// Mobile
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
33
app/assets/stylesheets/pages/sherlock.scss
Normal file
33
app/assets/stylesheets/pages/sherlock.scss
Normal 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;
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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: []
|
||||||
)
|
)
|
||||||
|
|
32
app/controllers/admin/impersonation_controller.rb
Normal file
32
app/controllers/admin/impersonation_controller.rb
Normal 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
|
|
@ -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),
|
||||||
|
|
|
@ -59,14 +59,9 @@ 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
|
|
||||||
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
|
redirect_to current_application_settings.home_page_url and return
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
super(*args)
|
super(*args)
|
||||||
end
|
end
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
||||||
|
|
|
@ -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])
|
||||||
|
|
||||||
|
|
19
app/controllers/concerns/global_milestones.rb
Normal file
19
app/controllers/concerns/global_milestones.rb
Normal 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
|
14
app/controllers/concerns/issues_action.rb
Normal file
14
app/controllers/concerns/issues_action.rb
Normal 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
|
9
app/controllers/concerns/merge_requests_action.rb
Normal file
9
app/controllers/concerns/merge_requests_action.rb
Normal 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
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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?
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,25 +27,24 @@ 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
|
@group_member.destroy
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html { redirect_to group_group_members_path(@group), notice: 'User was successfully removed from group.' }
|
format.html { redirect_to group_group_members_path(@group), notice: 'User was successfully removed from group.' }
|
||||||
format.js { render nothing: true }
|
format.js { render nothing: true }
|
||||||
end
|
end
|
||||||
else
|
|
||||||
return render_403
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def resend_invite
|
def resend_invite
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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]
|
|
||||||
when 'all'; state
|
|
||||||
when 'closed'; state('closed')
|
|
||||||
else state('active')
|
|
||||||
end
|
end
|
||||||
@group_milestones = Milestones::GroupService.new(project_milestones).execute
|
|
||||||
@group_milestones = Kaminari.paginate_array(@group_milestones).page(params[:page]).per(PER_PAGE)
|
def new
|
||||||
|
@milestone = Milestone.new
|
||||||
|
end
|
||||||
|
|
||||||
|
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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 URI.parse(params[:return_to]).path
|
|
||||||
else
|
|
||||||
redirect_to build_path(build)
|
redirect_to build_path(build)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def download
|
||||||
|
unless artifacts_file.file_storage?
|
||||||
|
return redirect_to artifacts_file.url
|
||||||
|
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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,17 +73,23 @@ 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
|
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
|
||||||
|
|
||||||
def apply_import
|
def apply_import
|
||||||
|
|
31
app/controllers/projects/releases_controller.rb
Normal file
31
app/controllers/projects/releases_controller.rb
Normal 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
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
12
app/controllers/sherlock/application_controller.rb
Normal file
12
app/controllers/sherlock/application_controller.rb
Normal 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
|
7
app/controllers/sherlock/file_samples_controller.rb
Normal file
7
app/controllers/sherlock/file_samples_controller.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
module Sherlock
|
||||||
|
class FileSamplesController < Sherlock::ApplicationController
|
||||||
|
def show
|
||||||
|
@file_sample = @transaction.find_file_sample(params[:id])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
7
app/controllers/sherlock/queries_controller.rb
Normal file
7
app/controllers/sherlock/queries_controller.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
module Sherlock
|
||||||
|
class QueriesController < Sherlock::ApplicationController
|
||||||
|
def show
|
||||||
|
@query = @transaction.find_query(params[:id])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
19
app/controllers/sherlock/transactions_controller.rb
Normal file
19
app/controllers/sherlock/transactions_controller.rb
Normal 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
|
|
@ -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
|
||||||
|
|
37
app/finders/contributed_projects_finder.rb
Normal file
37
app/finders/contributed_projects_finder.rb
Normal 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
|
|
@ -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
|
|
||||||
#
|
|
||||||
group_ids = Project.public_and_internal_only.pluck(:namespace_id) +
|
|
||||||
current_user.authorized_groups.pluck(:id)
|
|
||||||
Group.where(id: group_ids)
|
|
||||||
else
|
|
||||||
# User has no group membership
|
|
||||||
#
|
|
||||||
# Return only:
|
|
||||||
# groups with public projects
|
|
||||||
# groups with internal projects
|
|
||||||
#
|
|
||||||
Group.where(id: Project.public_and_internal_only.pluck(:namespace_id))
|
|
||||||
end
|
end
|
||||||
else
|
|
||||||
# Not authenticated
|
def public_groups
|
||||||
#
|
groups_for_projects(public_projects)
|
||||||
# Return only:
|
|
||||||
# groups with public projects
|
|
||||||
Group.where(id: Project.public_only.pluck(:namespace_id))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def groups_for_projects(projects)
|
||||||
|
Group.public_and_given_groups(projects.select(:namespace_id))
|
||||||
|
end
|
||||||
|
|
||||||
|
def public_projects
|
||||||
|
Project.unscoped.public_only
|
||||||
|
end
|
||||||
|
|
||||||
|
def public_and_internal_projects
|
||||||
|
Project.unscoped.public_and_internal_only
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
49
app/finders/joined_groups_finder.rb
Normal file
49
app/finders/joined_groups_finder.rb
Normal 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
|
12
app/finders/milestones_finder.rb
Normal file
12
app/finders/milestones_finder.rb
Normal 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
|
41
app/finders/personal_projects_finder.rb
Normal file
41
app/finders/personal_projects_finder.rb
Normal 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
|
|
@ -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),
|
||||||
#
|
|
||||||
# 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
|
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
|
else
|
||||||
# User has no access to private projects
|
[Project.public_only]
|
||||||
#
|
|
||||||
# Return only:
|
|
||||||
# public projects
|
|
||||||
# internal projects
|
|
||||||
#
|
|
||||||
Project.public_and_internal_only
|
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def group_projects_for_user(current_user, group)
|
||||||
|
if group.users.include?(current_user)
|
||||||
|
group.projects
|
||||||
else
|
else
|
||||||
# Not authenticated
|
group.projects.visible_to_user(current_user)
|
||||||
#
|
|
||||||
# Return only:
|
|
||||||
# public projects
|
|
||||||
Project.public_only
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def public_projects
|
||||||
|
Project.unscoped.public_only
|
||||||
|
end
|
||||||
|
|
||||||
|
def public_and_internal_projects
|
||||||
|
Project.unscoped.public_and_internal_only
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -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?
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -108,6 +108,11 @@ module EventsHelper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elsif event.push?
|
elsif event.push?
|
||||||
|
push_event_feed_url(event)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def push_event_feed_url(event)
|
||||||
if event.push_with_commits? && event.md_ref?
|
if event.push_with_commits? && event.md_ref?
|
||||||
if event.commits_count > 1
|
if event.commits_count > 1
|
||||||
namespace_project_compare_url(event.project.namespace, event.project,
|
namespace_project_compare_url(event.project.namespace, event.project,
|
||||||
|
@ -122,7 +127,6 @@ module EventsHelper
|
||||||
event.ref_name)
|
event.ref_name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def event_feed_summary(event)
|
def event_feed_summary(event)
|
||||||
if event.issue?
|
if event.issue?
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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] || ''
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
@target_url = namespace_project_issue_url(@project.namespace, @project, @issue)
|
mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id))
|
||||||
mail_answer_thread(@issue,
|
end
|
||||||
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
|
||||||
@project = @issue.project
|
|
||||||
@updated_by = User.find updated_by_user_id
|
@updated_by = User.find updated_by_user_id
|
||||||
@target_url = namespace_project_issue_url(@project.namespace, @project, @issue)
|
mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id))
|
||||||
mail_answer_thread(@issue,
|
end
|
||||||
from: sender(updated_by_user_id),
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def issue_thread_options(sender_id, recipient_id)
|
||||||
|
{
|
||||||
|
from: sender(sender_id),
|
||||||
to: recipient(recipient_id),
|
to: recipient(recipient_id),
|
||||||
subject: subject("#{@issue.title} (##{@issue.iid})"))
|
subject: subject("#{@issue.title} (##{@issue.iid})")
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def issue_mail_with_notification(issue_id, recipient_id)
|
||||||
|
@issue = Issue.find(issue_id)
|
||||||
|
@project = @issue.project
|
||||||
|
@target_url = namespace_project_issue_url(@project.namespace, @project, @issue)
|
||||||
|
|
||||||
|
yield
|
||||||
|
|
||||||
SentNotification.record(@issue, recipient_id, reply_key)
|
SentNotification.record(@issue, recipient_id, reply_key)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,49 +1,54 @@
|
||||||
module Emails
|
module Emails
|
||||||
module Notes
|
module Notes
|
||||||
def note_commit_email(recipient_id, note_id)
|
def note_commit_email(recipient_id, note_id)
|
||||||
@note = Note.find(note_id)
|
note_mail_with_notification(note_id, recipient_id) do
|
||||||
@commit = @note.noteable
|
@commit = @note.noteable
|
||||||
@project = @note.project
|
@target_url = namespace_project_commit_url(*note_target_url_options)
|
||||||
@target_url = namespace_project_commit_url(@project.namespace, @project,
|
|
||||||
@commit, anchor:
|
|
||||||
"note_#{@note.id}")
|
|
||||||
mail_answer_thread(@commit,
|
mail_answer_thread(@commit,
|
||||||
from: sender(@note.author_id),
|
from: sender(@note.author_id),
|
||||||
to: recipient(recipient_id),
|
to: recipient(recipient_id),
|
||||||
subject: subject("#{@commit.title} (#{@commit.short_id})"))
|
subject: subject("#{@commit.title} (#{@commit.short_id})"))
|
||||||
|
end
|
||||||
SentNotification.record_note(@note, recipient_id, reply_key)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def note_issue_email(recipient_id, note_id)
|
def note_issue_email(recipient_id, note_id)
|
||||||
@note = Note.find(note_id)
|
note_mail_with_notification(note_id, recipient_id) do
|
||||||
@issue = @note.noteable
|
@issue = @note.noteable
|
||||||
@project = @note.project
|
@target_url = namespace_project_issue_url(*note_target_url_options)
|
||||||
@target_url = namespace_project_issue_url(@project.namespace, @project,
|
mail_answer_thread(@issue, note_thread_options(recipient_id))
|
||||||
@issue, anchor:
|
end
|
||||||
"note_#{@note.id}")
|
|
||||||
mail_answer_thread(@issue,
|
|
||||||
from: sender(@note.author_id),
|
|
||||||
to: recipient(recipient_id),
|
|
||||||
subject: subject("#{@issue.title} (##{@issue.iid})"))
|
|
||||||
|
|
||||||
SentNotification.record_note(@note, recipient_id, reply_key)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def note_merge_request_email(recipient_id, note_id)
|
def note_merge_request_email(recipient_id, note_id)
|
||||||
@note = Note.find(note_id)
|
note_mail_with_notification(note_id, recipient_id) do
|
||||||
@merge_request = @note.noteable
|
@merge_request = @note.noteable
|
||||||
@project = @note.project
|
@target_url = namespace_project_merge_request_url(*note_target_url_options)
|
||||||
@target_url = namespace_project_merge_request_url(@project.namespace,
|
mail_answer_thread(@merge_request, note_thread_options(recipient_id))
|
||||||
@project,
|
end
|
||||||
@merge_request, anchor:
|
end
|
||||||
"note_#{@note.id}")
|
|
||||||
mail_answer_thread(@merge_request,
|
private
|
||||||
|
|
||||||
|
def note_target_url_options
|
||||||
|
[@project.namespace, @project, @note.noteable, anchor: "note_#{@note.id}"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def note_thread_options(recipient_id)
|
||||||
|
{
|
||||||
from: sender(@note.author_id),
|
from: sender(@note.author_id),
|
||||||
to: recipient(recipient_id),
|
to: recipient(recipient_id),
|
||||||
subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
|
subject: subject("#{@note.noteable.title} (##{@note.noteable.iid})")
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
SentNotification.record_note(@note, recipient_id, reply_key)
|
def note_mail_with_notification(note_id, recipient_id)
|
||||||
|
@note = Note.find(note_id)
|
||||||
|
@project = @note.project
|
||||||
|
|
||||||
|
yield
|
||||||
|
|
||||||
|
SentNotification.record(@note, recipient_id, reply_key)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,6 +15,7 @@ class Ability
|
||||||
when "Group" then group_abilities(user, subject)
|
when "Group" then group_abilities(user, subject)
|
||||||
when "Namespace" then namespace_abilities(user, subject)
|
when "Namespace" then namespace_abilities(user, subject)
|
||||||
when "GroupMember" then group_member_abilities(user, subject)
|
when "GroupMember" then group_member_abilities(user, subject)
|
||||||
|
when "ProjectMember" then project_member_abilities(user, subject)
|
||||||
else []
|
else []
|
||||||
end.concat(global_abilities(user))
|
end.concat(global_abilities(user))
|
||||||
end
|
end
|
||||||
|
@ -154,6 +155,7 @@ class Ability
|
||||||
:create_merge_request,
|
:create_merge_request,
|
||||||
:create_wiki,
|
:create_wiki,
|
||||||
:manage_builds,
|
:manage_builds,
|
||||||
|
:download_build_artifacts,
|
||||||
:push_code
|
:push_code
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
@ -230,18 +232,19 @@ class Ability
|
||||||
|
|
||||||
# Only group masters and group owners can create new projects in group
|
# Only group masters and group owners can create new projects in group
|
||||||
if group.has_master?(user) || group.has_owner?(user) || user.admin?
|
if group.has_master?(user) || group.has_owner?(user) || user.admin?
|
||||||
rules.push(*[
|
rules += [
|
||||||
:create_projects,
|
:create_projects,
|
||||||
])
|
:admin_milestones
|
||||||
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
# Only group owner and administrators can admin group
|
# Only group owner and administrators can admin group
|
||||||
if group.has_owner?(user) || user.admin?
|
if group.has_owner?(user) || user.admin?
|
||||||
rules.push(*[
|
rules += [
|
||||||
:admin_group,
|
:admin_group,
|
||||||
:admin_namespace,
|
:admin_namespace,
|
||||||
:admin_group_member
|
:admin_group_member
|
||||||
])
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
rules.flatten
|
rules.flatten
|
||||||
|
@ -252,16 +255,15 @@ class Ability
|
||||||
|
|
||||||
# Only namespace owner and administrators can admin it
|
# Only namespace owner and administrators can admin it
|
||||||
if namespace.owner == user || user.admin?
|
if namespace.owner == user || user.admin?
|
||||||
rules.push(*[
|
rules += [
|
||||||
:create_projects,
|
:create_projects,
|
||||||
:admin_namespace
|
:admin_namespace
|
||||||
])
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
rules.flatten
|
rules.flatten
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
[:issue, :merge_request].each do |name|
|
[:issue, :merge_request].each do |name|
|
||||||
define_method "#{name}_abilities" do |user, subject|
|
define_method "#{name}_abilities" do |user, subject|
|
||||||
rules = []
|
rules = []
|
||||||
|
@ -302,16 +304,40 @@ class Ability
|
||||||
rules = []
|
rules = []
|
||||||
target_user = subject.user
|
target_user = subject.user
|
||||||
group = subject.group
|
group = subject.group
|
||||||
|
|
||||||
|
unless group.last_owner?(target_user)
|
||||||
can_manage = group_abilities(user, group).include?(:admin_group_member)
|
can_manage = group_abilities(user, group).include?(:admin_group_member)
|
||||||
|
|
||||||
if can_manage && (user != target_user)
|
if can_manage && user != target_user
|
||||||
rules << :update_group_member
|
rules << :update_group_member
|
||||||
rules << :destroy_group_member
|
rules << :destroy_group_member
|
||||||
end
|
end
|
||||||
|
|
||||||
if !group.last_owner?(user) && (can_manage || (user == target_user))
|
if user == target_user
|
||||||
rules << :destroy_group_member
|
rules << :destroy_group_member
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
rules
|
||||||
|
end
|
||||||
|
|
||||||
|
def project_member_abilities(user, subject)
|
||||||
|
rules = []
|
||||||
|
target_user = subject.user
|
||||||
|
project = subject.project
|
||||||
|
|
||||||
|
unless target_user == project.owner
|
||||||
|
can_manage = project_abilities(user, project).include?(:admin_project_member)
|
||||||
|
|
||||||
|
if can_manage && user != target_user
|
||||||
|
rules << :update_project_member
|
||||||
|
rules << :destroy_project_member
|
||||||
|
end
|
||||||
|
|
||||||
|
if user == target_user
|
||||||
|
rules << :destroy_project_member
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
rules
|
rules
|
||||||
end
|
end
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue