Commit 9d491712 authored by Z.J. van de Weg's avatar Z.J. van de Weg

Merge branch 'master' into awardables

parents fab69546 ca3c5c29
...@@ -222,7 +222,7 @@ Style/EndBlock: ...@@ -222,7 +222,7 @@ Style/EndBlock:
# Use Unix-style line endings. # Use Unix-style line endings.
Style/EndOfLine: Style/EndOfLine:
Enabled: false Enabled: true
# Favor the use of Fixnum#even? && Fixnum#odd? # Favor the use of Fixnum#even? && Fixnum#odd?
Style/EvenOdd: Style/EvenOdd:
...@@ -247,7 +247,7 @@ Style/FlipFlop: ...@@ -247,7 +247,7 @@ Style/FlipFlop:
# Checks use of for or each in multiline loops. # Checks use of for or each in multiline loops.
Style/For: Style/For:
Enabled: false Enabled: true
# Enforce the use of Kernel#sprintf, Kernel#format or String#%. # Enforce the use of Kernel#sprintf, Kernel#format or String#%.
Style/FormatString: Style/FormatString:
...@@ -286,7 +286,7 @@ Style/IdenticalConditionalBranches: ...@@ -286,7 +286,7 @@ Style/IdenticalConditionalBranches:
# Checks the indentation of the first line of the right-hand-side of a # Checks the indentation of the first line of the right-hand-side of a
# multi-line assignment. # multi-line assignment.
Style/IndentAssignment: Style/IndentAssignment:
Enabled: false Enabled: true
# Keep indentation straight. # Keep indentation straight.
Style/IndentationConsistency: Style/IndentationConsistency:
...@@ -318,7 +318,7 @@ Style/LambdaCall: ...@@ -318,7 +318,7 @@ Style/LambdaCall:
# Comments should start with a space. # Comments should start with a space.
Style/LeadingCommentSpace: Style/LeadingCommentSpace:
Enabled: false Enabled: true
# Use \ instead of + or << to concatenate two string literals at line end. # Use \ instead of + or << to concatenate two string literals at line end.
Style/LineEndConcatenation: Style/LineEndConcatenation:
...@@ -330,7 +330,7 @@ Style/MethodCallParentheses: ...@@ -330,7 +330,7 @@ Style/MethodCallParentheses:
# Checks if the method definitions have or don't have parentheses. # Checks if the method definitions have or don't have parentheses.
Style/MethodDefParentheses: Style/MethodDefParentheses:
Enabled: false Enabled: true
# Use the configured style when naming methods. # Use the configured style when naming methods.
Style/MethodName: Style/MethodName:
...@@ -362,7 +362,7 @@ Style/MultilineHashBraceLayout: ...@@ -362,7 +362,7 @@ Style/MultilineHashBraceLayout:
# Do not use then for multi-line if/unless. # Do not use then for multi-line if/unless.
Style/MultilineIfThen: Style/MultilineIfThen:
Enabled: false Enabled: true
# Checks that the closing brace in a method call is either on the same line as # Checks that the closing brace in a method call is either on the same line as
# the last method argument, or a new line. # the last method argument, or a new line.
...@@ -394,7 +394,7 @@ Style/MutableConstant: ...@@ -394,7 +394,7 @@ Style/MutableConstant:
# Favor unless over if for negative conditions (or control flow or). # Favor unless over if for negative conditions (or control flow or).
Style/NegatedIf: Style/NegatedIf:
Enabled: false Enabled: true
# Favor until over while for negative conditions. # Favor until over while for negative conditions.
Style/NegatedWhile: Style/NegatedWhile:
...@@ -486,10 +486,9 @@ Style/RedundantException: ...@@ -486,10 +486,9 @@ Style/RedundantException:
Style/RedundantFreeze: Style/RedundantFreeze:
Enabled: false Enabled: false
# TODO: Enable RedundantParentheses Cop.
# Checks for parentheses that seem not to serve any purpose. # Checks for parentheses that seem not to serve any purpose.
Style/RedundantParentheses: Style/RedundantParentheses:
Enabled: false Enabled: true
# Don't use return where it's not required. # Don't use return where it's not required.
Style/RedundantReturn: Style/RedundantReturn:
...@@ -515,7 +514,7 @@ Style/SelfAssignment: ...@@ -515,7 +514,7 @@ Style/SelfAssignment:
# Don't use semicolons to terminate expressions. # Don't use semicolons to terminate expressions.
Style/Semicolon: Style/Semicolon:
Enabled: false Enabled: true
# Checks for proper usage of fail and raise. # Checks for proper usage of fail and raise.
Style/SignalException: Style/SignalException:
...@@ -541,7 +540,7 @@ Style/SpaceAfterComma: ...@@ -541,7 +540,7 @@ Style/SpaceAfterComma:
# Do not put a space between a method name and the opening parenthesis in a # Do not put a space between a method name and the opening parenthesis in a
# method definition. # method definition.
Style/SpaceAfterMethodName: Style/SpaceAfterMethodName:
Enabled: false Enabled: true
# Tracks redundant space after the ! operator. # Tracks redundant space after the ! operator.
Style/SpaceAfterNot: Style/SpaceAfterNot:
...@@ -570,11 +569,11 @@ Style/SpaceBeforeBlockBraces: ...@@ -570,11 +569,11 @@ Style/SpaceBeforeBlockBraces:
# No spaces before commas. # No spaces before commas.
Style/SpaceBeforeComma: Style/SpaceBeforeComma:
Enabled: false Enabled: true
# Checks for missing space between code and a comment on the same line. # Checks for missing space between code and a comment on the same line.
Style/SpaceBeforeComment: Style/SpaceBeforeComment:
Enabled: false Enabled: true
# Checks that exactly one space is used between a method name and the first # Checks that exactly one space is used between a method name and the first
# argument for method calls without parentheses. # argument for method calls without parentheses.
...@@ -705,7 +704,7 @@ Style/WhenThen: ...@@ -705,7 +704,7 @@ Style/WhenThen:
# Checks for redundant do after while or until. # Checks for redundant do after while or until.
Style/WhileUntilDo: Style/WhileUntilDo:
Enabled: false Enabled: true
# Favor modifier while/until usage when you have a single-line body. # Favor modifier while/until usage when you have a single-line body.
Style/WhileUntilModifier: Style/WhileUntilModifier:
...@@ -785,7 +784,7 @@ Lint/AssignmentInCondition: ...@@ -785,7 +784,7 @@ Lint/AssignmentInCondition:
# Align block ends correctly. # Align block ends correctly.
Lint/BlockAlignment: Lint/BlockAlignment:
Enabled: false Enabled: true
# Default values in optional keyword arguments and optional ordinal arguments # Default values in optional keyword arguments and optional ordinal arguments
# should not refer back to the name of the argument. # should not refer back to the name of the argument.
...@@ -878,7 +877,7 @@ Lint/InvalidCharacterLiteral: ...@@ -878,7 +877,7 @@ Lint/InvalidCharacterLiteral:
# Checks of literals used in conditions. # Checks of literals used in conditions.
Lint/LiteralInCondition: Lint/LiteralInCondition:
Enabled: false Enabled: true
# Checks for literals used in interpolation. # Checks for literals used in interpolation.
Lint/LiteralInInterpolation: Lint/LiteralInInterpolation:
...@@ -1027,10 +1026,9 @@ Performance/StartWith: ...@@ -1027,10 +1026,9 @@ Performance/StartWith:
Performance/StringReplacement: Performance/StringReplacement:
Enabled: true Enabled: true
# TODO: Enable TimesMap Cop.
# Checks for `.times.map` calls. # Checks for `.times.map` calls.
Performance/TimesMap: Performance/TimesMap:
Enabled: false Enabled: true
##################### Rails ################################## ##################### Rails ##################################
......
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.9.0 (unreleased) v 8.9.0 (unreleased)
- Allow enabling wiki page events from Webhook management UI
- Make EmailsOnPushWorker use Sidekiq mailers queue
- Fix wiki page events' webhook to point to the wiki repository
- Fix issue todo not remove when leave project !4150 (Long Nguyen)
- Allow forking projects with restricted visibility level - Allow forking projects with restricted visibility level
- Improve note validation to prevent errors when creating invalid note via API - Improve note validation to prevent errors when creating invalid note via API
- Reduce number of fog gem dependencies
- Remove project notification settings associated with deleted projects
- Fix 404 page when viewing TODOs that contain milestones or labels in different projects
- Redesign navigation for project pages - Redesign navigation for project pages
- Fix groups API to list only user's accessible projects - Fix groups API to list only user's accessible projects
- Redesign account and email confirmation emails - Redesign account and email confirmation emails
- Use gitlab-shell v3.0.0 - Use gitlab-shell v3.0.0
- Add `sha` parameter to MR merge API, to ensure only reviewed changes are merged
- Don't allow MRs to be merged when commits were added since the last review / page load
- Add DB index on users.state - Add DB index on users.state
- Add rake task 'gitlab:db:configure' for conditionally seeding or migrating the database - Add rake task 'gitlab:db:configure' for conditionally seeding or migrating the database
- Changed the Slack build message to use the singular duration if necessary (Aran Koning) - Changed the Slack build message to use the singular duration if necessary (Aran Koning)
- Fix issues filter when ordering by milestone - Fix issues filter when ordering by milestone
- Todos will display target state if issuable target is 'Closed' or 'Merged' - Todos will display target state if issuable target is 'Closed' or 'Merged'
- Fix bug when sorting issues by milestone due date and filtering by two or more labels
- Link to blank group icon doesn't throw a 404 anymore
- Remove 'main language' feature - Remove 'main language' feature
- Pipelines can be canceled only when there are running builds
- Use downcased path to container repository as this is expected path by Docker
- Projects pending deletion will render a 404 page - Projects pending deletion will render a 404 page
- Measure queue duration between gitlab-workhorse and Rails - Measure queue duration between gitlab-workhorse and Rails
- Make authentication service for Container Registry to be compatible with < Docker 1.11
- Add Application Setting to configure Container Registry token expire delay (default 5min)
- Cache assigned issue and merge request counts in sidebar nav
- Cache project build count in sidebar nav
- Reduce number of queries needed to render issue labels in the sidebar
- Improve error handling importing projects
- Put project Files and Commits tabs under Code tab
v 8.8.4
- Fix todos page throwing errors when you have a project pending deletion
- Reduce number of SQL queries when rendering user references
v 8.8.4 (unreleased)
- Ensure branch cleanup regardless of whether the GitHub import process succeeds
v 8.8.3 v 8.8.3
- Fix gitlab importer failing to import new projects due to missing credentials - Fix 404 page when viewing TODOs that contain milestones or labels in different projects. !4312
- Fix import URL migration not rescuing with the correct Error - Fixed JS error when trying to remove discussion form. !4303
- Fixed issue with button color when no CI enabled. !4287
- Fixed potential issue with 2 CI status polling events happening. !3869
- Improve design of Pipeline view. !4230
- Fix gitlab importer failing to import new projects due to missing credentials. !4301
- Fix import URL migration not rescuing with the correct Error. !4321
- Fix health check access token changing due to old application settings being used. !4332
- Make authentication service for Container Registry to be compatible with Docker versions before 1.11. !4363
- Add Application Setting to configure Container Registry token expire delay (default 5 min). !4364
- Pass the "Remember me" value to the 2FA token form. !4369
- Fix incorrect links on pipeline page when merge request created from fork. !4376
- Use downcased path to container repository as this is expected path by Docker. !4420
- Fix wiki project clone address error (chujinjin). !4429
- Fix serious performance bug with rendering Markdown with InlineDiffFilter. !4392
- Fix missing number on generated ordered list element. !4437
- Prevent disclosure of notes on confidential issues in search results.
v 8.8.2 v 8.8.2
- Added remove due date button. !4209 - Added remove due date button. !4209
......
...@@ -308,16 +308,14 @@ tests are least likely to receive timely feedback. The workflow to make a merge ...@@ -308,16 +308,14 @@ tests are least likely to receive timely feedback. The workflow to make a merge
request is as follows: request is as follows:
1. Fork the project into your personal space on GitLab.com 1. Fork the project into your personal space on GitLab.com
1. Create a feature branch 1. Create a feature branch, branch away from `master`.
1. Write [tests](https://gitlab.com/gitlab-org/gitlab-development-kit#running-the-tests) and code 1. Write [tests](https://gitlab.com/gitlab-org/gitlab-development-kit#running-the-tests) and code
1. Add your changes to the [CHANGELOG](CHANGELOG) 1. Add your changes to the [CHANGELOG](CHANGELOG)
1. If you are changing the README, some documentation or other things which 1. If you are writing documentation, make sure to read the [documentation styleguide][doc-styleguide]
have no effect on the tests, add `[ci skip]` somewhere in the commit message
and make sure to read the [documentation styleguide][doc-styleguide]
1. If you have multiple commits please combine them into one commit by 1. If you have multiple commits please combine them into one commit by
[squashing them][git-squash] [squashing them][git-squash]
1. Push the commit(s) to your fork 1. Push the commit(s) to your fork
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
1. The MR description should give a motive for your change and the method you 1. The MR description should give a motive for your change and the method you
used to achieve it, see the [merge request description format] used to achieve it, see the [merge request description format]
......
...@@ -18,9 +18,8 @@ gem "mysql2", '~> 0.3.16', group: :mysql ...@@ -18,9 +18,8 @@ gem "mysql2", '~> 0.3.16', group: :mysql
gem "pg", '~> 0.18.2', group: :postgres gem "pg", '~> 0.18.2', group: :postgres
# Authentication libraries # Authentication libraries
gem 'devise', '~> 3.5.4' gem 'devise', '~> 4.0'
gem 'doorkeeper', '~> 3.1' gem 'doorkeeper', '~> 3.1'
gem 'devise-async', '~> 0.9.0'
gem 'omniauth', '~> 1.3.1' gem 'omniauth', '~> 1.3.1'
gem 'omniauth-auth0', '~> 1.4.1' gem 'omniauth-auth0', '~> 1.4.1'
gem 'omniauth-azure-oauth2', '~> 0.0.6' gem 'omniauth-azure-oauth2', '~> 0.0.6'
...@@ -43,9 +42,9 @@ gem 'recaptcha', require: 'recaptcha/rails' ...@@ -43,9 +42,9 @@ gem 'recaptcha', require: 'recaptcha/rails'
gem 'akismet', '~> 2.0' gem 'akismet', '~> 2.0'
# Two-factor authentication # Two-factor authentication
gem 'devise-two-factor', '~> 2.0.0' gem 'devise-two-factor', '~> 3.0.0'
gem 'rqrcode-rails3', '~> 0.1.7' gem 'rqrcode-rails3', '~> 0.1.7'
gem 'attr_encrypted', '~> 1.3.4' gem 'attr_encrypted', '~> 3.0.0'
# Browser detection # Browser detection
gem "browser", '~> 1.0.0' gem "browser", '~> 1.0.0'
...@@ -73,7 +72,7 @@ gem 'grape-entity', '~> 0.4.2' ...@@ -73,7 +72,7 @@ gem 'grape-entity', '~> 0.4.2'
gem 'rack-cors', '~> 0.4.0', require: 'rack/cors' gem 'rack-cors', '~> 0.4.0', require: 'rack/cors'
# Pagination # Pagination
gem "kaminari", "~> 0.16.3" gem "kaminari", "~> 0.17.0"
# HAML # HAML
gem "haml-rails", '~> 0.9.0' gem "haml-rails", '~> 0.9.0'
...@@ -84,8 +83,14 @@ gem "carrierwave", '~> 0.10.0' ...@@ -84,8 +83,14 @@ gem "carrierwave", '~> 0.10.0'
# Drag and Drop UI # Drag and Drop UI
gem 'dropzonejs-rails', '~> 0.7.1' gem 'dropzonejs-rails', '~> 0.7.1'
# for backups
gem 'fog-aws', '~> 0.9'
gem 'fog-core', '~> 1.40'
gem 'fog-local', '~> 0.3'
gem 'fog-google', '~> 0.3'
gem 'fog-openstack', '~> 0.1'
# for aws storage # for aws storage
gem "fog", "~> 1.36.0"
gem "unf", '~> 0.1.4' gem "unf", '~> 0.1.4'
# Authorization # Authorization
......
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
CFPropertyList (2.3.2)
RedCloth (4.2.9) RedCloth (4.2.9)
ace-rails-ap (4.0.2) ace-rails-ap (4.0.2)
actionmailer (4.2.6) actionmailer (4.2.6)
...@@ -60,8 +59,8 @@ GEM ...@@ -60,8 +59,8 @@ GEM
oauth2 (~> 1.0) oauth2 (~> 1.0)
asciidoctor (1.5.3) asciidoctor (1.5.3)
ast (2.2.0) ast (2.2.0)
attr_encrypted (1.3.4) attr_encrypted (3.0.1)
encryptor (>= 1.3.0) encryptor (~> 3.0.0)
attr_required (1.0.0) attr_required (1.0.0)
autoprefixer-rails (6.2.3) autoprefixer-rails (6.2.3)
execjs execjs
...@@ -73,7 +72,7 @@ GEM ...@@ -73,7 +72,7 @@ GEM
thread_safe (~> 0.3, >= 0.3.1) thread_safe (~> 0.3, >= 0.3.1)
babosa (1.0.2) babosa (1.0.2)
base32 (0.3.2) base32 (0.3.2)
bcrypt (3.1.10) bcrypt (3.1.11)
benchmark-ips (2.3.0) benchmark-ips (2.3.0)
better_errors (1.0.1) better_errors (1.0.1)
coderay (>= 1.0.0) coderay (>= 1.0.0)
...@@ -155,21 +154,18 @@ GEM ...@@ -155,21 +154,18 @@ GEM
activerecord (>= 3.2.0, < 5.0) activerecord (>= 3.2.0, < 5.0)
descendants_tracker (0.0.4) descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1) thread_safe (~> 0.3, >= 0.3.1)
devise (3.5.4) devise (4.1.1)
bcrypt (~> 3.0) bcrypt (~> 3.0)
orm_adapter (~> 0.1) orm_adapter (~> 0.1)
railties (>= 3.2.6, < 5) railties (>= 4.1.0, < 5.1)
responders responders
thread_safe (~> 0.1)
warden (~> 1.2.3) warden (~> 1.2.3)
devise-async (0.9.0) devise-two-factor (3.0.0)
devise (~> 3.2)
devise-two-factor (2.0.1)
activesupport activesupport
attr_encrypted (~> 1.3.2) attr_encrypted (>= 1.3, < 4, != 2)
devise (~> 3.5.0) devise (~> 4.0)
railties railties
rotp (~> 2) rotp (~> 2.0)
diff-lcs (1.2.5) diff-lcs (1.2.5)
diffy (3.0.7) diffy (3.0.7)
docile (1.1.5) docile (1.1.5)
...@@ -181,12 +177,12 @@ GEM ...@@ -181,12 +177,12 @@ GEM
email_spec (1.6.0) email_spec (1.6.0)
launchy (~> 2.1) launchy (~> 2.1)
mail (~> 2.2) mail (~> 2.2)
encryptor (1.3.0) encryptor (3.0.0)
equalizer (0.0.11) equalizer (0.0.11)
erubis (2.7.0) erubis (2.7.0)
escape_utils (1.1.1) escape_utils (1.1.1)
eventmachine (1.0.8) eventmachine (1.0.8)
excon (0.45.4) excon (0.49.0)
execjs (2.6.0) execjs (2.6.0)
expression_parser (0.9.0) expression_parser (0.9.0)
factory_girl (4.5.0) factory_girl (4.5.0)
...@@ -203,8 +199,6 @@ GEM ...@@ -203,8 +199,6 @@ GEM
multi_json multi_json
ffaker (2.0.0) ffaker (2.0.0)
ffi (1.9.10) ffi (1.9.10)
fission (0.5.0)
CFPropertyList (~> 2.2)
flay (2.6.1) flay (2.6.1)
ruby_parser (~> 3.0) ruby_parser (~> 3.0)
sexp_processor (~> 4.0) sexp_processor (~> 4.0)
...@@ -214,109 +208,28 @@ GEM ...@@ -214,109 +208,28 @@ GEM
flowdock (0.7.1) flowdock (0.7.1)
httparty (~> 0.7) httparty (~> 0.7)
multi_json multi_json
fog (1.36.0) fog-aws (0.9.2)
fog-aliyun (>= 0.1.0)
fog-atmos
fog-aws (>= 0.6.0)
fog-brightbox (~> 0.4)
fog-core (~> 1.32)
fog-dynect (~> 0.0.2)
fog-ecloud (~> 0.1)
fog-google (<= 0.1.0)
fog-json
fog-local
fog-powerdns (>= 0.1.1)
fog-profitbricks
fog-radosgw (>= 0.0.2)
fog-riakcs
fog-sakuracloud (>= 0.0.4)
fog-serverlove
fog-softlayer
fog-storm_on_demand
fog-terremark
fog-vmfusion
fog-voxel
fog-xenserver
fog-xml (~> 0.1.1)
ipaddress (~> 0.5)
nokogiri (~> 1.5, >= 1.5.11)
fog-aliyun (0.1.0)
fog-core (~> 1.27)
fog-json (~> 1.0)
ipaddress (~> 0.8)
xml-simple (~> 1.1)
fog-atmos (0.1.0)
fog-core
fog-xml
fog-aws (0.8.1)
fog-core (~> 1.27) fog-core (~> 1.27)
fog-json (~> 1.0) fog-json (~> 1.0)
fog-xml (~> 0.1) fog-xml (~> 0.1)
ipaddress (~> 0.8) ipaddress (~> 0.8)
fog-brightbox (0.10.1) fog-core (1.40.0)
fog-core (~> 1.22)
fog-json
inflecto (~> 0.0.2)
fog-core (1.35.0)
builder builder
excon (~> 0.45) excon (~> 0.49)
formatador (~> 0.2) formatador (~> 0.2)
fog-dynect (0.0.2) fog-google (0.3.2)
fog-core
fog-json
fog-xml
fog-ecloud (0.3.0)
fog-core
fog-xml
fog-google (0.1.0)
fog-core fog-core
fog-json fog-json
fog-xml fog-xml
fog-json (1.0.2) fog-json (1.0.2)
fog-core (~> 1.0) fog-core (~> 1.0)
multi_json (~> 1.10) multi_json (~> 1.10)
fog-local (0.2.1) fog-local (0.3.0)
fog-core (~> 1.27)
fog-powerdns (0.1.1)
fog-core (~> 1.27) fog-core (~> 1.27)
fog-json (~> 1.0) fog-openstack (0.1.6)
fog-xml (~> 0.1) fog-core (>= 1.39)
fog-profitbricks (0.0.5) fog-json (>= 1.0)
fog-core ipaddress (>= 0.8)
fog-xml
nokogiri
fog-radosgw (0.0.5)
fog-core (>= 1.21.0)
fog-json
fog-xml (>= 0.0.1)
fog-riakcs (0.1.0)
fog-core
fog-json
fog-xml
fog-sakuracloud (1.7.5)
fog-core
fog-json
fog-serverlove (0.1.2)
fog-core
fog-json
fog-softlayer (1.0.3)
fog-core
fog-json
fog-storm_on_demand (0.1.1)
fog-core
fog-json
fog-terremark (0.1.0)
fog-core
fog-xml
fog-vmfusion (0.1.0)
fission
fog-core
fog-voxel (0.1.0)
fog-core
fog-xml
fog-xenserver (0.2.2)
fog-core
fog-xml
fog-xml (0.1.2) fog-xml (0.1.2)
fog-core fog-core
nokogiri (~> 1.5, >= 1.5.11) nokogiri (~> 1.5, >= 1.5.11)
...@@ -425,11 +338,10 @@ GEM ...@@ -425,11 +338,10 @@ GEM
httpclient (2.7.0.1) httpclient (2.7.0.1)
i18n (0.7.0) i18n (0.7.0)
ice_nine (0.11.1) ice_nine (0.11.1)
inflecto (0.0.2)
influxdb (0.2.3) influxdb (0.2.3)
cause cause
json json
ipaddress (0.8.2) ipaddress (0.8.3)
jquery-atwho-rails (1.3.2) jquery-atwho-rails (1.3.2)
jquery-rails (4.1.1) jquery-rails (4.1.1)
rails-dom-testing (>= 1, < 3) rails-dom-testing (>= 1, < 3)
...@@ -442,7 +354,7 @@ GEM ...@@ -442,7 +354,7 @@ GEM
railties (>= 3.2.16) railties (>= 3.2.16)
json (1.8.3) json (1.8.3)
jwt (1.5.2) jwt (1.5.2)
kaminari (0.16.3) kaminari (0.17.0)
actionpack (>= 3.0.0) actionpack (>= 3.0.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
kgio (2.10.0) kgio (2.10.0)
...@@ -656,7 +568,7 @@ GEM ...@@ -656,7 +568,7 @@ GEM
responders (2.1.1) responders (2.1.1)
railties (>= 4.2.0, < 5.1) railties (>= 4.2.0, < 5.1)
rinku (1.7.3) rinku (1.7.3)
rotp (2.1.1) rotp (2.1.2)
rouge (1.10.1) rouge (1.10.1)
rqrcode (0.7.0) rqrcode (0.7.0)
chunky_png chunky_png
...@@ -859,7 +771,7 @@ GEM ...@@ -859,7 +771,7 @@ GEM
coercible (~> 1.0) coercible (~> 1.0)
descendants_tracker (~> 0.0, >= 0.0.3) descendants_tracker (~> 0.0, >= 0.0.3)
equalizer (~> 0.0, >= 0.0.9) equalizer (~> 0.0, >= 0.0.9)
warden (1.2.4) warden (1.2.6)
rack (>= 1.0) rack (>= 1.0)
web-console (2.3.0) web-console (2.3.0)
activemodel (>= 4.0) activemodel (>= 4.0)
...@@ -876,7 +788,6 @@ GEM ...@@ -876,7 +788,6 @@ GEM
builder builder
expression_parser expression_parser
rinku rinku
xml-simple (1.1.5)
xpath (2.0.0) xpath (2.0.0)
nokogiri (~> 1.3) nokogiri (~> 1.3)
...@@ -894,7 +805,7 @@ DEPENDENCIES ...@@ -894,7 +805,7 @@ DEPENDENCIES
allocations (~> 1.0) allocations (~> 1.0)
asana (~> 0.4.0) asana (~> 0.4.0)
asciidoctor (~> 1.5.2) asciidoctor (~> 1.5.2)
attr_encrypted (~> 1.3.4) attr_encrypted (~> 3.0.0)
awesome_print (~> 1.2.0) awesome_print (~> 1.2.0)
babosa (~> 1.0.2) babosa (~> 1.0.2)
base32 (~> 0.3.0) base32 (~> 0.3.0)
...@@ -919,9 +830,8 @@ DEPENDENCIES ...@@ -919,9 +830,8 @@ DEPENDENCIES
d3_rails (~> 3.5.0) d3_rails (~> 3.5.0)
database_cleaner (~> 1.4.0) database_cleaner (~> 1.4.0)
default_value_for (~> 3.0.0) default_value_for (~> 3.0.0)
devise (~> 3.5.4) devise (~> 4.0)
devise-async (~> 0.9.0) devise-two-factor (~> 3.0.0)
devise-two-factor (~> 2.0.0)
diffy (~> 3.0.3) diffy (~> 3.0.3)
doorkeeper (~> 3.1) doorkeeper (~> 3.1)
dropzonejs-rails (~> 0.7.1) dropzonejs-rails (~> 0.7.1)
...@@ -931,7 +841,11 @@ DEPENDENCIES ...@@ -931,7 +841,11 @@ DEPENDENCIES
ffaker (~> 2.0.0) ffaker (~> 2.0.0)
flay flay
flog flog
fog (~> 1.36.0) fog-aws (~> 0.9)
fog-core (~> 1.40)
fog-google (~> 0.3)
fog-local (~> 0.3)
fog-openstack (~> 0.1)
font-awesome-rails (~> 4.2) font-awesome-rails (~> 4.2)
foreman foreman
fuubar (~> 2.0.0) fuubar (~> 2.0.0)
...@@ -959,7 +873,7 @@ DEPENDENCIES ...@@ -959,7 +873,7 @@ DEPENDENCIES
jquery-turbolinks (~> 2.1.0) jquery-turbolinks (~> 2.1.0)
jquery-ui-rails (~> 5.0.0) jquery-ui-rails (~> 5.0.0)
jwt jwt
kaminari (~> 0.16.3) kaminari (~> 0.17.0)
letter_opener_web (~> 1.3.0) letter_opener_web (~> 1.3.0)
licensee (~> 8.0.0) licensee (~> 8.0.0)
loofah (~> 2.0.3) loofah (~> 2.0.3)
......
# GitLab # GitLab
[![build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master) [![build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master)
[![Build Status](https://semaphoreci.com/api/v1/projects/2f1a5809-418b-4cc2-a1f4-819607579fe7/400484/shields_badge.svg)](https://semaphoreci.com/gitlabhq/gitlabhq)
[![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq) [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq)
[![Coverage Status](https://coveralls.io/repos/gitlabhq/gitlabhq/badge.svg?branch=master)](https://coveralls.io/r/gitlabhq/gitlabhq?branch=master)
## Canonical source ## Canonical source
......
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
#= require jquery.atwho #= require jquery.atwho
#= require jquery.scrollTo #= require jquery.scrollTo
#= require jquery.turbolinks #= require jquery.turbolinks
#= require d3
#= require turbolinks #= require turbolinks
#= require autosave #= require autosave
#= require bootstrap/affix #= require bootstrap/affix
...@@ -51,7 +50,13 @@ ...@@ -51,7 +50,13 @@
#= require shortcuts_network #= require shortcuts_network
#= require jquery.nicescroll #= require jquery.nicescroll
#= require date.format #= require date.format
#= require_tree . #= require_directory ./behaviors
#= require_directory ./blob
#= require_directory ./ci
#= require_directory ./commit
#= require_directory ./extensions
#= require_directory ./lib
#= require_directory .
#= require fuzzaldrin-plus #= require fuzzaldrin-plus
#= require cropper #= require cropper
......
# This is a manifest file that'll be compiled into including all the files listed below.
# Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
# be included in the compiled file accessible from http://example.com/assets/application.js
# It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
# the compiled file.
#
#= require_tree .
#= require d3 #= require d3
#= require stat_graph_contributors_util
class @ContributorsStatGraph class @ContributorsStatGraph
init: (log) -> init: (log) ->
......
#= require d3 #= require d3
#= require jquery
#= require underscore
class @ContributorsGraph class @ContributorsGraph
MARGIN: MARGIN:
......
...@@ -20,8 +20,7 @@ class @SearchAutocomplete ...@@ -20,8 +20,7 @@ class @SearchAutocomplete
@dropdown = @wrap.find('.dropdown') @dropdown = @wrap.find('.dropdown')
@dropdownContent = @dropdown.find('.dropdown-content') @dropdownContent = @dropdown.find('.dropdown-content')
@locationBadgeEl = @getElement('.search-location-badge') @locationBadgeEl = @getElement('.location-badge')
@locationText = @getElement('.location-text')
@scopeInputEl = @getElement('#scope') @scopeInputEl = @getElement('#scope')
@searchInput = @getElement('.search-input') @searchInput = @getElement('.search-input')
@projectInputEl = @getElement('#search_project_id') @projectInputEl = @getElement('#search_project_id')
...@@ -133,7 +132,7 @@ class @SearchAutocomplete ...@@ -133,7 +132,7 @@ class @SearchAutocomplete
scope: @scopeInputEl.val() scope: @scopeInputEl.val()
# Location badge # Location badge
_location: @locationText.text() _location: @locationBadgeEl.text()
} }
bindEvents: -> bindEvents: ->
...@@ -143,12 +142,14 @@ class @SearchAutocomplete ...@@ -143,12 +142,14 @@ class @SearchAutocomplete
@searchInput.on 'click', @onSearchInputClick @searchInput.on 'click', @onSearchInputClick
@searchInput.on 'focus', @onSearchInputFocus @searchInput.on 'focus', @onSearchInputFocus
@clearInput.on 'click', @onClearInputClick @clearInput.on 'click', @onClearInputClick
@locationBadgeEl.on 'click', =>
@searchInput.focus()
onDocumentClick: (e) => onDocumentClick: (e) =>
# If clicking outside the search box # If clicking outside the search box
# And search input is not focused # And search input is not focused
# And we are not clicking inside a suggestion # And we are not clicking inside a suggestion
if not $.contains(@dropdown[0], e.target) and @isFocused and not $(e.target).parents('ul').length if not $.contains(@dropdown[0], e.target) and @isFocused and not $(e.target).closest('.search-form').length
@onSearchInputBlur() @onSearchInputBlur()
enableAutocomplete: -> enableAutocomplete: ->
...@@ -221,10 +222,8 @@ class @SearchAutocomplete ...@@ -221,10 +222,8 @@ class @SearchAutocomplete
category = if item.category? then "#{item.category}: " else '' category = if item.category? then "#{item.category}: " else ''
value = if item.value? then item.value else '' value = if item.value? then item.value else ''
html = "<span class='location-badge'> badgeText = "#{category}#{value}"
<i class='location-text'>#{category}#{value}</i> @locationBadgeEl.text(badgeText).show()
</span>"
@locationBadgeEl.html(html)
@wrap.addClass('has-location-badge') @wrap.addClass('has-location-badge')
restoreOriginalState: -> restoreOriginalState: ->
...@@ -233,9 +232,8 @@ class @SearchAutocomplete ...@@ -233,9 +232,8 @@ class @SearchAutocomplete
for input in inputs for input in inputs
@getElement("##{input}").val(@originalState[input]) @getElement("##{input}").val(@originalState[input])
if @originalState._location is '' if @originalState._location is ''
@locationBadgeEl.empty() @locationBadgeEl.hide()
else else
@addLocationBadge( @addLocationBadge(
value: @originalState._location value: @originalState._location
...@@ -244,7 +242,7 @@ class @SearchAutocomplete ...@@ -244,7 +242,7 @@ class @SearchAutocomplete
@dropdown.removeClass 'open' @dropdown.removeClass 'open'
badgePresent: -> badgePresent: ->
@locationBadgeEl.children().length @locationBadgeEl.length
resetSearchState: -> resetSearchState: ->
inputs = Object.keys @originalState inputs = Object.keys @originalState
...@@ -257,7 +255,7 @@ class @SearchAutocomplete ...@@ -257,7 +255,7 @@ class @SearchAutocomplete
@getElement("##{input}").val('') @getElement("##{input}").val('')
removeLocationBadge: -> removeLocationBadge: ->
@locationBadgeEl.empty() @locationBadgeEl.hide()
# Reset state # Reset state
@resetSearchState() @resetSearchState()
......
# This is a manifest file that'll be compiled into including all the files listed below.
# Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
# be included in the compiled file accessible from http://example.com/assets/application.js
# It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
# the compiled file.
#
#= require d3
#= require_tree .
...@@ -16,6 +16,19 @@ ...@@ -16,6 +16,19 @@
@include btn-default; @include btn-default;
} }
@mixin btn-outline($background, $text, $border, $hover-background, $hover-text, $hover-border) {
background-color: $background;
color: $text;
border-color: $border;
&:hover,
&:focus {
background-color: $hover-background;
color: $hover-text;
border-color: $hover-border;;
}
}
@mixin btn-color($light, $border-light, $normal, $border-normal, $dark, $border-dark, $color) { @mixin btn-color($light, $border-light, $normal, $border-normal, $dark, $border-dark, $color) {
background-color: $light; background-color: $light;
border-color: $border-light; border-color: $border-light;
...@@ -106,11 +119,14 @@ ...@@ -106,11 +119,14 @@
@include btn-blue; @include btn-blue;
} }
&.btn-close,
&.btn-warning { &.btn-warning {
@include btn-orange; @include btn-orange;
} }
&.btn-close {
@include btn-outline($white-light, $orange-normal, $orange-normal, $orange-light, $white-light, $orange-light);
}
&.btn-danger, &.btn-danger,
&.btn-remove, &.btn-remove,
&.btn-red { &.btn-red {
......
...@@ -63,7 +63,8 @@ $gl-padding-top: 10px; ...@@ -63,7 +63,8 @@ $gl-padding-top: 10px;
/* /*
* Misc * Misc
*/ */
$row-hover: #f4f8fe; $row-hover: #f7faff;
$row-hover-border: #b2d7ff;
$progress-color: #c0392b; $progress-color: #c0392b;
$avatar_radius: 50%; $avatar_radius: 50%;
$header-height: 50px; $header-height: 50px;
...@@ -104,7 +105,7 @@ $blue-medium-light: #3498cb; ...@@ -104,7 +105,7 @@ $blue-medium-light: #3498cb;
$blue-medium: #2f8ebf; $blue-medium: #2f8ebf;
$blue-medium-dark: #2d86b4; $blue-medium-dark: #2d86b4;
$orange-light: rgba(252, 109, 38, 0.80); $orange-light: #fc8a51;
$orange-normal: #e75e40; $orange-normal: #e75e40;
$orange-dark: #ce5237; $orange-dark: #ce5237;
......
...@@ -29,8 +29,6 @@ ...@@ -29,8 +29,6 @@
margin-top: 6px; margin-top: 6px;
p { p {
overflow-x: auto;
&:last-child { &:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
......
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
margin: 0; margin: 0;
margin-left: 20px; margin-left: 20px;
padding: 5px; padding: 5px;
padding-top: 12px; padding-top: 8px;
line-height: 20px; line-height: 20px;
&.right { &.right {
...@@ -110,6 +110,29 @@ ...@@ -110,6 +110,29 @@
p:last-child { p:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
@media (max-width: $screen-sm-max) {
h4 {
font-size: 15px;
}
p {
font-size: 13px;
}
.btn,
.btn-group,
.accept-action {
width: 100%;
margin-bottom: 4px;
}
.accept-control {
width: 100%;
text-align: center;
margin: 0;
}
}
} }
.mr-widget-footer { .mr-widget-footer {
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
} }
.search-input { .search-input {
padding-right: 20px;
border: none; border: none;
font-size: 14px; font-size: 14px;
outline: none; outline: none;
...@@ -47,6 +48,7 @@ ...@@ -47,6 +48,7 @@
display: inline-block; display: inline-block;
background-color: $location-badge-bg; background-color: $location-badge-bg;
vertical-align: top; vertical-align: top;
cursor: default;
} }
.search-input-container { .search-input-container {
...@@ -55,7 +57,7 @@ ...@@ -55,7 +57,7 @@
position: relative; position: relative;
} }
.search-location-badge, .search-input-wrap { .search-input-wrap {
// Fallback if flexbox is not supported // Fallback if flexbox is not supported
display: inline-block; display: inline-block;
} }
......
...@@ -15,16 +15,23 @@ ...@@ -15,16 +15,23 @@
margin-bottom: 0; margin-bottom: 0;
tr { tr {
> td, > th { border-bottom: 1px solid $table-border-gray;
border-top: 1px solid $table-border-gray;
td, th {
line-height: 23px; line-height: 23px;
} }
&:hover { &:hover {
cursor: pointer;
td { td {
background: $row-hover; background-color: $row-hover;
border-top: 1px solid $row-hover-border;
border-bottom: 1px solid $row-hover-border;
} }
cursor: pointer;
} }
&.selected { &.selected {
td { td {
background: $gray-dark; background: $gray-dark;
......
...@@ -107,6 +107,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController ...@@ -107,6 +107,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:repository_checks_enabled, :repository_checks_enabled,
:metrics_packet_size, :metrics_packet_size,
:send_user_confirmation_email, :send_user_confirmation_email,
:container_registry_token_expire_delay,
restricted_visibility_levels: [], restricted_visibility_levels: [],
import_sources: [], import_sources: [],
disabled_oauth_sign_in_sources: [] disabled_oauth_sign_in_sources: []
......
...@@ -232,7 +232,7 @@ class ApplicationController < ActionController::Base ...@@ -232,7 +232,7 @@ class ApplicationController < ActionController::Base
end end
def configure_permitted_parameters def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_in) { |u| u.permit(:username, :email, :password, :login, :remember_me, :otp_attempt) } devise_parameter_sanitizer.permit(:sign_in, keys: [:username, :email, :password, :login, :remember_me, :otp_attempt])
end end
def hexdigest(string) def hexdigest(string)
...@@ -263,7 +263,7 @@ class ApplicationController < ActionController::Base ...@@ -263,7 +263,7 @@ class ApplicationController < ActionController::Base
# internal repos where you are not a member. Enable this filter # internal repos where you are not a member. Enable this filter
# or improve current implementation to filter only issues you # or improve current implementation to filter only issues you
# created or assigned or mentioned # created or assigned or mentioned
#@filter_params[:authorized_only] = true # @filter_params[:authorized_only] = true
end end
@filter_params @filter_params
......
...@@ -32,7 +32,7 @@ class JwtController < ApplicationController ...@@ -32,7 +32,7 @@ class JwtController < ApplicationController
end end
def auth_params def auth_params
params.permit(:service, :scope, :offline_token, :account, :client_id) params.permit(:service, :scope, :account, :client_id)
end end
def authenticate_project(login, password) def authenticate_project(login, password)
......
...@@ -97,7 +97,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController ...@@ -97,7 +97,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
handle_signup_error handle_signup_error
end end
def handle_service_ticket provider, ticket def handle_service_ticket(provider, ticket)
Gitlab::OAuth::Session.create provider, ticket Gitlab::OAuth::Session.create provider, ticket
session[:service_tickets] ||= {} session[:service_tickets] ||= {}
session[:service_tickets][provider] = ticket session[:service_tickets][provider] = ticket
......
...@@ -50,7 +50,7 @@ class Projects::BranchesController < Projects::ApplicationController ...@@ -50,7 +50,7 @@ class Projects::BranchesController < Projects::ApplicationController
redirect_to namespace_project_branches_path(@project.namespace, redirect_to namespace_project_branches_path(@project.namespace,
@project), status: 303 @project), status: 303
end end
format.js { render status: status[:return_code] } format.js { render nothing: true, status: status[:return_code] }
end end
end end
......
# Controller for viewing a repository's file structure # Controller for viewing a repository's file structure
class Projects::FindFileController < Projects::ApplicationController class Projects::FindFileController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
include ActionView::Helpers::SanitizeHelper include ActionView::Helpers::SanitizeHelper
include TreeHelper include TreeHelper
before_action :require_non_empty_project before_action :require_non_empty_project
before_action :assign_ref_vars before_action :assign_ref_vars
before_action :authorize_download_code! before_action :authorize_download_code!
def show def show
return render_404 unless @repository.commit(@ref) return render_404 unless @repository.commit(@ref)
respond_to do |format| respond_to do |format|
format.html format.html
end end
end end
def list def list
file_paths = @repo.ls_files(@ref) file_paths = @repo.ls_files(@ref)
respond_to do |format| respond_to do |format|
format.json { render json: file_paths } format.json { render json: file_paths }
end end
end end
end end
...@@ -63,7 +63,8 @@ class Projects::HooksController < Projects::ApplicationController ...@@ -63,7 +63,8 @@ class Projects::HooksController < Projects::ApplicationController
:push_events, :push_events,
:tag_push_events, :tag_push_events,
:token, :token,
:url :url,
:wiki_page_events
) )
end end
end end
...@@ -191,6 +191,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -191,6 +191,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
return return
end end
if params[:sha] != @merge_request.source_sha
@status = :sha_mismatch
return
end
TodoService.new.merge_merge_request(merge_request, current_user) TodoService.new.merge_merge_request(merge_request, current_user)
@merge_request.update(merge_error: nil) @merge_request.update(merge_error: nil)
...@@ -206,7 +211,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -206,7 +211,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
def branch_from def branch_from
#This is always source # This is always source
@source_project = @merge_request.nil? ? @project : @merge_request.source_project @source_project = @merge_request.nil? ? @project : @merge_request.source_project
@commit = @repository.commit(params[:ref]) if params[:ref].present? @commit = @repository.commit(params[:ref]) if params[:ref].present?
render layout: false render layout: false
......
...@@ -91,8 +91,8 @@ class Projects::WikisController < Projects::ApplicationController ...@@ -91,8 +91,8 @@ class Projects::WikisController < Projects::ApplicationController
def markdown_preview def markdown_preview
text = params[:text] text = params[:text]
ext = Gitlab::ReferenceExtractor.new(@project, current_user, current_user) ext = Gitlab::ReferenceExtractor.new(@project, current_user)
ext.analyze(text) ext.analyze(text, author: current_user)
render json: { render json: {
body: view_context.markdown(text, pipeline: :wiki, project_wiki: @project_wiki), body: view_context.markdown(text, pipeline: :wiki, project_wiki: @project_wiki),
......
...@@ -197,8 +197,8 @@ class ProjectsController < Projects::ApplicationController ...@@ -197,8 +197,8 @@ class ProjectsController < Projects::ApplicationController
def markdown_preview def markdown_preview
text = params[:text] text = params[:text]
ext = Gitlab::ReferenceExtractor.new(@project, current_user, current_user) ext = Gitlab::ReferenceExtractor.new(@project, current_user)
ext.analyze(text) ext.analyze(text, author: current_user)
render json: { render json: {
body: view_context.markdown(text), body: view_context.markdown(text),
......
class SessionsController < Devise::SessionsController class SessionsController < Devise::SessionsController
include AuthenticatesWithTwoFactor include AuthenticatesWithTwoFactor
include Devise::Controllers::Rememberable
include Recaptcha::ClientHelper include Recaptcha::ClientHelper
skip_before_action :check_2fa_requirement, only: [:destroy] skip_before_action :check_2fa_requirement, only: [:destroy]
...@@ -96,6 +97,7 @@ class SessionsController < Devise::SessionsController ...@@ -96,6 +97,7 @@ class SessionsController < Devise::SessionsController
# Remove any lingering user data from login # Remove any lingering user data from login
session.delete(:otp_user_id) session.delete(:otp_user_id)
remember_me(user) if user_params[:remember_me] == '1'
sign_in(user) and return sign_in(user) and return
else else
flash.now[:alert] = 'Invalid two-factor code.' flash.now[:alert] = 'Invalid two-factor code.'
......
...@@ -271,7 +271,7 @@ class IssuableFinder ...@@ -271,7 +271,7 @@ class IssuableFinder
if filter_by_no_label? if filter_by_no_label?
items = items.without_label items = items.without_label
else else
items = items.with_label(label_names) items = items.with_label(label_names, params[:sort])
if projects if projects
items = items.where(labels: { project_id: projects }) items = items.where(labels: { project_id: projects })
end end
......
...@@ -30,7 +30,7 @@ class TodosFinder ...@@ -30,7 +30,7 @@ class TodosFinder
items = by_state(items) items = by_state(items)
items = by_type(items) items = by_type(items)
items items.reorder(id: :desc)
end end
private private
...@@ -78,6 +78,16 @@ class TodosFinder ...@@ -78,6 +78,16 @@ class TodosFinder
@project @project
end end
def projects
return @projects if defined?(@projects)
if project?
@projects = project
else
@projects = ProjectsFinder.new.execute(current_user)
end
end
def type? def type?
type.present? && ['Issue', 'MergeRequest'].include?(type) type.present? && ['Issue', 'MergeRequest'].include?(type)
end end
...@@ -105,6 +115,8 @@ class TodosFinder ...@@ -105,6 +115,8 @@ class TodosFinder
def by_project(items) def by_project(items)
if project? if project?
items = items.where(project: project) items = items.where(project: project)
elsif projects
items = items.merge(projects).joins(:project)
end end
items items
......
...@@ -30,7 +30,7 @@ module ButtonHelper ...@@ -30,7 +30,7 @@ module ButtonHelper
content_tag :a, protocol, content_tag :a, protocol,
class: klass, class: klass,
href: @project.http_url_to_repo, href: project.http_url_to_repo,
data: { data: {
html: true, html: true,
placement: 'right', placement: 'right',
......
...@@ -39,11 +39,11 @@ module DiffHelper ...@@ -39,11 +39,11 @@ module DiffHelper
end end
def unfold_bottom_class(bottom) def unfold_bottom_class(bottom)
(bottom) ? 'js-unfold-bottom' : '' bottom ? 'js-unfold-bottom' : ''
end end
def unfold_class(unfold) def unfold_class(unfold)
(unfold) ? 'unfold js-unfold' : '' unfold ? 'unfold js-unfold' : ''
end end
def diff_line_content(line, line_type = nil) def diff_line_content(line, line_type = nil)
......
...@@ -31,7 +31,7 @@ module GroupsHelper ...@@ -31,7 +31,7 @@ module GroupsHelper
if group && group.avatar.present? if group && group.avatar.present?
group.avatar.url group.avatar.url
else else
'no_group_avatar.png' image_path('no_group_avatar.png')
end end
end end
......
module JavascriptHelper
def page_specific_javascripts(js = nil)
@page_specific_javascripts = js unless js.nil?
@page_specific_javascripts
end
end
...@@ -17,7 +17,9 @@ module TodosHelper ...@@ -17,7 +17,9 @@ module TodosHelper
def todo_target_link(todo) def todo_target_link(todo)
target = todo.target_type.titleize.downcase target = todo.target_type.titleize.downcase
link_to "#{target} #{todo.target_reference}", todo_target_path(todo), { title: todo.target.title } link_to "#{target} #{todo.target_reference}", todo_target_path(todo),
class: 'has-tooltip',
title: todo.target.title
end end
def todo_target_path(todo) def todo_target_path(todo)
......
...@@ -23,20 +23,41 @@ class Ability ...@@ -23,20 +23,41 @@ class Ability
end.concat(global_abilities(user)) end.concat(global_abilities(user))
end end
# Given a list of users and a project this method returns the users that can
# read the given project.
def users_that_can_read_project(users, project)
if project.public?
users
else
users.select do |user|
if user.admin?
true
elsif project.internal? && !user.external?
true
elsif project.owner == user
true
elsif project.team.members.include?(user)
true
else
false
end
end
end
end
# List of possible abilities for anonymous user # List of possible abilities for anonymous user
def anonymous_abilities(user, subject) def anonymous_abilities(user, subject)
case true if subject.is_a?(PersonalSnippet)
when subject.is_a?(PersonalSnippet)
anonymous_personal_snippet_abilities(subject) anonymous_personal_snippet_abilities(subject)
when subject.is_a?(ProjectSnippet) elsif subject.is_a?(ProjectSnippet)
anonymous_project_snippet_abilities(subject) anonymous_project_snippet_abilities(subject)
when subject.is_a?(CommitStatus) elsif subject.is_a?(CommitStatus)
anonymous_commit_status_abilities(subject) anonymous_commit_status_abilities(subject)
when subject.is_a?(Project) || subject.respond_to?(:project) elsif subject.is_a?(Project) || subject.respond_to?(:project)
anonymous_project_abilities(subject) anonymous_project_abilities(subject)
when subject.is_a?(Group) || subject.respond_to?(:group) elsif subject.is_a?(Group) || subject.respond_to?(:group)
anonymous_group_abilities(subject) anonymous_group_abilities(subject)
when subject.is_a?(User) elsif subject.is_a?(User)
anonymous_user_abilities anonymous_user_abilities
else else
[] []
......
...@@ -51,6 +51,10 @@ class ApplicationSetting < ActiveRecord::Base ...@@ -51,6 +51,10 @@ class ApplicationSetting < ActiveRecord::Base
presence: true, presence: true,
numericality: { only_integer: true, greater_than: 0 } numericality: { only_integer: true, greater_than: 0 }
validates :container_registry_token_expire_delay,
presence: true,
numericality: { only_integer: true, greater_than: 0 }
validates_each :restricted_visibility_levels do |record, attr, value| validates_each :restricted_visibility_levels do |record, attr, value|
unless value.nil? unless value.nil?
value.each do |level| value.each do |level|
...@@ -98,6 +102,10 @@ class ApplicationSetting < ActiveRecord::Base ...@@ -98,6 +102,10 @@ class ApplicationSetting < ActiveRecord::Base
Rails.cache.delete(CACHE_KEY) Rails.cache.delete(CACHE_KEY)
end end
def self.cached
Rails.cache.fetch(CACHE_KEY)
end
def self.create_from_defaults def self.create_from_defaults
create( create(
default_projects_limit: Settings.gitlab['default_projects_limit'], default_projects_limit: Settings.gitlab['default_projects_limit'],
...@@ -121,7 +129,8 @@ class ApplicationSetting < ActiveRecord::Base ...@@ -121,7 +129,8 @@ class ApplicationSetting < ActiveRecord::Base
akismet_enabled: false, akismet_enabled: false,
repository_checks_enabled: true, repository_checks_enabled: true,
disabled_oauth_sign_in_sources: [], disabled_oauth_sign_in_sources: [],
send_user_confirmation_email: false send_user_confirmation_email: false,
container_registry_token_expire_delay: 5,
) )
end end
......
...@@ -286,7 +286,7 @@ module Ci ...@@ -286,7 +286,7 @@ module Ci
project.runners_token project.runners_token
end end
def valid_token? token def valid_token?(token)
project.valid_runners_token? token project.valid_runners_token? token
end end
...@@ -313,6 +313,7 @@ module Ci ...@@ -313,6 +313,7 @@ module Ci
build_data = Gitlab::BuildDataBuilder.build(self) build_data = Gitlab::BuildDataBuilder.build(self)
project.execute_hooks(build_data.dup, :build_hooks) project.execute_hooks(build_data.dup, :build_hooks)
project.execute_services(build_data.dup, :build_hooks) project.execute_services(build_data.dup, :build_hooks)
project.running_or_pending_build_count(force: true)
end end
def artifacts? def artifacts?
......
...@@ -66,6 +66,10 @@ module Ci ...@@ -66,6 +66,10 @@ module Ci
end end
end end
def cancelable?
builds.running_or_pending.any?
end
def cancel_running def cancel_running
builds.running_or_pending.each(&:cancel) builds.running_or_pending.each(&:cancel)
end end
......
...@@ -60,7 +60,7 @@ module Ci ...@@ -60,7 +60,7 @@ module Ci
end end
def display_name def display_name
return short_sha unless !description.blank? return short_sha if description.blank?
description description
end end
......
...@@ -11,6 +11,9 @@ module Ci ...@@ -11,6 +11,9 @@ module Ci
format: { with: /\A[a-zA-Z0-9_]+\z/, format: { with: /\A[a-zA-Z0-9_]+\z/,
message: "can contain only letters, digits and '_'." } message: "can contain only letters, digits and '_'." }
attr_encrypted :value, mode: :per_attribute_iv_and_salt, key: Gitlab::Application.secrets.db_key_base attr_encrypted :value,
mode: :per_attribute_iv_and_salt,
key: Gitlab::Application.secrets.db_key_base,
algorithm: 'aes-256-cbc'
end end
end end
...@@ -8,7 +8,10 @@ class Commit ...@@ -8,7 +8,10 @@ class Commit
include StaticModel include StaticModel
attr_mentionable :safe_message, pipeline: :single_line attr_mentionable :safe_message, pipeline: :single_line
participant :author, :committer, :notes
participant :author
participant :committer
participant :notes_with_associations
attr_accessor :project attr_accessor :project
...@@ -194,6 +197,10 @@ class Commit ...@@ -194,6 +197,10 @@ class Commit
project.notes.for_commit_id(self.id) project.notes.for_commit_id(self.id)
end end
def notes_with_associations
notes.includes(:author, :project)
end
def method_missing(m, *args, &block) def method_missing(m, *args, &block)
@raw.send(m, *args, &block) @raw.send(m, *args, &block)
end end
...@@ -219,7 +226,7 @@ class Commit ...@@ -219,7 +226,7 @@ class Commit
def revert_branch_name def revert_branch_name
"revert-#{short_id}" "revert-#{short_id}"
end end
def cherry_pick_branch_name def cherry_pick_branch_name
project.repository.next_branch("cherry-pick-#{short_id}", mild: true) project.repository.next_branch("cherry-pick-#{short_id}", mild: true)
end end
...@@ -251,11 +258,13 @@ class Commit ...@@ -251,11 +258,13 @@ class Commit
end end
def has_been_reverted?(current_user = nil, noteable = self) def has_been_reverted?(current_user = nil, noteable = self)
Gitlab::ReferenceExtractor.lazily do ext = all_references(current_user)
noteable.notes.system.flat_map do |note|
note.all_references(current_user).commits noteable.notes_with_associations.system.each do |note|
end note.all_references(current_user, extractor: ext)
end.any? { |commit_ref| commit_ref.reverts_commit?(self) } end
ext.commits.any? { |commit_ref| commit_ref.reverts_commit?(self) }
end end
def change_type_title def change_type_title
......
...@@ -62,7 +62,7 @@ class CommitRange ...@@ -62,7 +62,7 @@ class CommitRange
def initialize(range_string, project) def initialize(range_string, project)
@project = project @project = project
range_string.strip! range_string = range_string.strip
unless range_string =~ /\A#{PATTERN}\z/ unless range_string =~ /\A#{PATTERN}\z/
raise ArgumentError, "invalid CommitRange string format: #{range_string}" raise ArgumentError, "invalid CommitRange string format: #{range_string}"
......
...@@ -60,11 +60,23 @@ module Issuable ...@@ -60,11 +60,23 @@ module Issuable
prefix: true prefix: true
attr_mentionable :title, pipeline: :single_line attr_mentionable :title, pipeline: :single_line
attr_mentionable :description, cache: true attr_mentionable :description
participant :author, :assignee, :notes_with_associations
participant :author
participant :assignee
participant :notes_with_associations
strip_attributes :title strip_attributes :title
acts_as_paranoid acts_as_paranoid
after_save :update_assignee_cache_counts, if: :assignee_id_changed?
def update_assignee_cache_counts
# make sure we flush the cache for both the old *and* new assignee
User.find(assignee_id_was).update_cache_counts if assignee_id_was
assignee.update_cache_counts if assignee
end
end end
module ClassMethods module ClassMethods
...@@ -104,13 +116,29 @@ module Issuable ...@@ -104,13 +116,29 @@ module Issuable
end end
end end
def with_label(title) def with_label(title, sort = nil)
if title.is_a?(Array) && title.size > 1 if title.is_a?(Array) && title.size > 1
joins(:labels).where(labels: { title: title }).group(arel_table[:id]).having("COUNT(DISTINCT labels.title) = #{title.size}") joins(:labels).where(labels: { title: title }).group(*grouping_columns(sort)).having("COUNT(DISTINCT labels.title) = #{title.size}")
else else
joins(:labels).where(labels: { title: title }) joins(:labels).where(labels: { title: title })
end end
end end
# Includes table keys in group by clause when sorting
# preventing errors in postgres
#
# Returns an array of arel columns
def grouping_columns(sort)
grouping_columns = [arel_table[:id]]
if ["milestone_due_desc", "milestone_due_asc"].include?(sort)
milestone_table = Milestone.arel_table
grouping_columns << milestone_table[:id]
grouping_columns << milestone_table[:due_date]
end
grouping_columns
end
end end
def today? def today?
...@@ -121,10 +149,6 @@ module Issuable ...@@ -121,10 +149,6 @@ module Issuable
today? && created_at == updated_at today? && created_at == updated_at
end end
def is_assigned?
!!assignee_id
end
def is_being_reassigned? def is_being_reassigned?
assignee_id_changed? assignee_id_changed?
end end
...@@ -155,6 +179,10 @@ module Issuable ...@@ -155,6 +179,10 @@ module Issuable
hook_data hook_data
end end
def labels_array
labels.to_a
end
def label_names def label_names
labels.order('title ASC').pluck(:title) labels.order('title ASC').pluck(:title)
end end
......
...@@ -23,7 +23,7 @@ module Mentionable ...@@ -23,7 +23,7 @@ module Mentionable
included do included do
if self < Participable if self < Participable
participant ->(current_user) { mentioned_users(current_user) } participant -> (user, ext) { all_references(user, extractor: ext) }
end end
end end
...@@ -43,23 +43,22 @@ module Mentionable ...@@ -43,23 +43,22 @@ module Mentionable
self self
end end
def all_references(current_user = nil, text = nil) def all_references(current_user = nil, text = nil, extractor: nil)
ext = Gitlab::ReferenceExtractor.new(self.project, current_user || self.author, self.author) extractor ||= Gitlab::ReferenceExtractor.
new(project, current_user || author)
if text if text
ext.analyze(text) extractor.analyze(text, author: author)
else else
self.class.mentionable_attrs.each do |attr, options| self.class.mentionable_attrs.each do |attr, options|
text = send(attr) text = __send__(attr)
options = options.merge(cache_key: [self, attr], author: author)
context = options.dup extractor.analyze(text, options)
context[:cache_key] = [self, attr] if context.delete(:cache) && self.persisted?
ext.analyze(text, context)
end end
end end
ext extractor
end end
def mentioned_users(current_user = nil) def mentioned_users(current_user = nil)
......
...@@ -3,8 +3,6 @@ ...@@ -3,8 +3,6 @@
# Contains functionality related to objects that can have participants, such as # Contains functionality related to objects that can have participants, such as
# an author, an assignee and people mentioned in its description or comments. # an author, an assignee and people mentioned in its description or comments.
# #
# Used by Issue, Note, MergeRequest, Snippet and Commit.
#
# Usage: # Usage:
# #
# class Issue < ActiveRecord::Base # class Issue < ActiveRecord::Base
...@@ -12,22 +10,36 @@ ...@@ -12,22 +10,36 @@
# #
# # ... # # ...
# #
# participant :author, :assignee, :notes, ->(current_user) { mentioned_users(current_user) } # participant :author
# participant :assignee
# participant :notes
#
# participant -> (current_user, ext) do
# ext.analyze('...')
# end
# end # end
# #
# issue = Issue.last # issue = Issue.last
# users = issue.participants # users = issue.participants
# # `users` will contain the issue's author, its assignee,
# # all users returned by its #mentioned_users method,
# # as well as all participants to all of the issue's notes,
# # since Note implements Participable as well.
#
module Participable module Participable
extend ActiveSupport::Concern extend ActiveSupport::Concern
module ClassMethods module ClassMethods
def participant(*attrs) # Adds a list of participant attributes. Attributes can either be symbols or
participant_attrs.concat(attrs) # Procs.
#
# When using a Proc instead of a Symbol the Proc will be given two
# arguments:
#
# 1. The current user (as an instance of User)
# 2. An instance of `Gitlab::ReferenceExtractor`
#
# It is expected that a Proc populates the given reference extractor
# instance with data. The return value of the Proc is ignored.
#
# attr - The name of the attribute or a Proc
def participant(attr)
participant_attrs << attr
end end
def participant_attrs def participant_attrs
...@@ -35,42 +47,42 @@ module Participable ...@@ -35,42 +47,42 @@ module Participable
end end
end end
# Be aware that this method makes a lot of sql queries. # Returns the users participating in a discussion.
# Save result into variable if you are going to reuse it inside same request #
def participants(current_user = self.author) # This method processes attributes of objects in breadth-first order.
participants = #
Gitlab::ReferenceExtractor.lazily do # Returns an Array of User instances.
self.class.participant_attrs.flat_map do |attr| def participants(current_user = nil)
value = current_user ||= author
if attr.respond_to?(:call) ext = Gitlab::ReferenceExtractor.new(project, current_user)
instance_exec(current_user, &attr) participants = Set.new
else process = [self]
send(attr)
end
participants_for(value, current_user) until process.empty?
end.compact.uniq source = process.pop
end
unless Gitlab::ReferenceExtractor.lazy? case source
participants.select! do |user| when User
user.can?(:read_project, project) participants << source
when Participable
source.class.participant_attrs.each do |attr|
if attr.respond_to?(:call)
source.instance_exec(current_user, ext, &attr)
else
process << source.__send__(attr)
end
end
when Enumerable, ActiveRecord::Relation
# This uses reverse_each so we can use "pop" to get the next value to
# process (in order). Using unshift instead of pop would require
# moving all Array values one index to the left (which can be
# expensive).
source.reverse_each { |obj| process << obj }
end end
end end
participants participants.merge(ext.users)
end
private
def participants_for(value, current_user = nil) Ability.users_that_can_read_project(participants.to_a, project)
case value
when User, Banzai::LazyReference
[value]
when Enumerable, ActiveRecord::Relation
value.flat_map { |v| participants_for(v, current_user) }
when Participable
value.participants(current_user)
end
end end
end end
...@@ -95,14 +95,13 @@ class Issue < ActiveRecord::Base ...@@ -95,14 +95,13 @@ class Issue < ActiveRecord::Base
end end
def referenced_merge_requests(current_user = nil) def referenced_merge_requests(current_user = nil)
@referenced_merge_requests ||= {} ext = all_references(current_user)
@referenced_merge_requests[current_user] ||= begin
Gitlab::ReferenceExtractor.lazily do notes_with_associations.each do |object|
[self, *notes].flat_map do |note| object.all_references(current_user, extractor: ext)
note.all_references(current_user).merge_requests
end
end.sort_by(&:iid).uniq
end end
ext.merge_requests.sort_by(&:iid)
end end
# All branches containing the current issue's ID, except for # All branches containing the current issue's ID, except for
...@@ -139,9 +138,13 @@ class Issue < ActiveRecord::Base ...@@ -139,9 +138,13 @@ class Issue < ActiveRecord::Base
def closed_by_merge_requests(current_user = nil) def closed_by_merge_requests(current_user = nil)
return [] unless open? return [] unless open?
notes.system.flat_map do |note| ext = all_references(current_user)
note.all_references(current_user).merge_requests
end.uniq.select { |mr| mr.open? && mr.closes_issue?(self) } notes.system.each do |note|
note.all_references(current_user, extractor: ext)
end
ext.merge_requests.select { |mr| mr.open? && mr.closes_issue?(self) }
end end
def moved? def moved?
......
...@@ -26,7 +26,7 @@ class Key < ActiveRecord::Base ...@@ -26,7 +26,7 @@ class Key < ActiveRecord::Base
end end
def publishable_key def publishable_key
#Removes anything beyond the keytype and key itself # Removes anything beyond the keytype and key itself
self.key.split[0..1].join(' ') self.key.split[0..1].join(' ')
end end
......
...@@ -5,7 +5,6 @@ class ProjectMember < Member ...@@ -5,7 +5,6 @@ class ProjectMember < Member
belongs_to :project, class_name: 'Project', foreign_key: 'source_id' belongs_to :project, class_name: 'Project', foreign_key: 'source_id'
# Make sure project member points only to project as it source # Make sure project member points only to project as it source
default_value_for :source_type, SOURCE_TYPE default_value_for :source_type, SOURCE_TYPE
validates_format_of :source_type, with: /\AProject\z/ validates_format_of :source_type, with: /\AProject\z/
...@@ -15,6 +14,8 @@ class ProjectMember < Member ...@@ -15,6 +14,8 @@ class ProjectMember < Member
scope :in_projects, ->(projects) { where(source_id: projects.pluck(:id)) } scope :in_projects, ->(projects) { where(source_id: projects.pluck(:id)) }
scope :with_user, ->(user) { where(user_id: user.id) } scope :with_user, ->(user) { where(user_id: user.id) }
before_destroy :delete_member_todos
class << self class << self
# Add users to project teams with passed access option # Add users to project teams with passed access option
...@@ -102,6 +103,10 @@ class ProjectMember < Member ...@@ -102,6 +103,10 @@ class ProjectMember < Member
private private
def delete_member_todos
user.todos.where(project_id: source_id).destroy_all if user
end
def send_invite def send_invite
notification_service.invite_project_member(self, @raw_invite_token) notification_service.invite_project_member(self, @raw_invite_token)
......
...@@ -22,9 +22,16 @@ module Network ...@@ -22,9 +22,16 @@ module Network
def collect_notes def collect_notes
h = Hash.new(0) h = Hash.new(0)
@project.notes.where('noteable_type = ?' ,"Commit").group('notes.commit_id').select('notes.commit_id, count(notes.id) as note_count').each do |item|
h[item.commit_id] = item.note_count.to_i @project
end .notes
.where('noteable_type = ?', 'Commit')
.group('notes.commit_id')
.select('notes.commit_id, count(notes.id) as note_count')
.each do |item|
h[item.commit_id] = item.note_count.to_i
end
h h
end end
...@@ -89,7 +96,7 @@ module Network ...@@ -89,7 +96,7 @@ module Network
end end
end end
if self.class.max_count / 2 < offset then if self.class.max_count / 2 < offset
# get max index that commit is displayed in the center. # get max index that commit is displayed in the center.
offset - self.class.max_count / 2 offset - self.class.max_count / 2
else else
...@@ -130,7 +137,7 @@ module Network ...@@ -130,7 +137,7 @@ module Network
commit.parents(@map).each do |parent| commit.parents(@map).each do |parent|
range = commit.time..parent.time range = commit.time..parent.time
space = if commit.space >= parent.space then space = if commit.space >= parent.space
find_free_parent_space(range, parent.space, -1, commit.space) find_free_parent_space(range, parent.space, -1, commit.space)
else else
find_free_parent_space(range, commit.space, -1, parent.space) find_free_parent_space(range, commit.space, -1, parent.space)
...@@ -144,7 +151,7 @@ module Network ...@@ -144,7 +151,7 @@ module Network
end end
def find_free_parent_space(range, space_base, space_step, space_default) def find_free_parent_space(range, space_base, space_step, space_default)
if is_overlap?(range, space_default) then if is_overlap?(range, space_default)
find_free_space(range, space_step, space_base, space_default) find_free_space(range, space_step, space_base, space_default)
else else
space_default space_default
...@@ -155,9 +162,9 @@ module Network ...@@ -155,9 +162,9 @@ module Network
range.each do |i| range.each do |i|
if i != range.first && if i != range.first &&
i != range.last && i != range.last &&
@commits[i].spaces.include?(overlap_space) then @commits[i].spaces.include?(overlap_space)
return true; return true
end end
end end
...@@ -198,7 +205,7 @@ module Network ...@@ -198,7 +205,7 @@ module Network
# Visit branching chains # Visit branching chains
leaves.each do |l| leaves.each do |l|
parents = l.parents(@map).select{|p| p.space.zero?} parents = l.parents(@map).select{|p| p.space.zero?}
for p in parents parents.each do |p|
place_chain(p, l.time) place_chain(p, l.time)
end end
end end
...@@ -216,7 +223,7 @@ module Network ...@@ -216,7 +223,7 @@ module Network
end end
def mark_reserved(time_range, space) def mark_reserved(time_range, space)
for day in time_range time_range.each do |day|
@reserved[day].push(space) @reserved[day].push(space)
end end
end end
...@@ -225,15 +232,15 @@ module Network ...@@ -225,15 +232,15 @@ module Network
space_default ||= space_base space_default ||= space_base
reserved = [] reserved = []
for day in time_range time_range.each do |day|
reserved.push(*@reserved[day]) reserved.push(*@reserved[day])
end end
reserved.uniq! reserved.uniq!
space = space_default space = space_default
while reserved.include?(space) do while reserved.include?(space)
space += space_step space += space_step
if space < space_base then if space < space_base
space_step *= -1 space_step *= -1
space = space_base + space_step space = space_base + space_step
end end
......
...@@ -6,7 +6,7 @@ class Note < ActiveRecord::Base ...@@ -6,7 +6,7 @@ class Note < ActiveRecord::Base
default_value_for :system, false default_value_for :system, false
attr_mentionable :note, cache: true, pipeline: :note attr_mentionable :note, pipeline: :note
participant :author participant :author
belongs_to :project belongs_to :project
...@@ -79,14 +79,30 @@ class Note < ActiveRecord::Base ...@@ -79,14 +79,30 @@ class Note < ActiveRecord::Base
# #
# This method uses ILIKE on PostgreSQL and LIKE on MySQL. # This method uses ILIKE on PostgreSQL and LIKE on MySQL.
# #
# query - The search query as a String. # query - The search query as a String.
# as_user - Limit results to those viewable by a specific user
# #
# Returns an ActiveRecord::Relation. # Returns an ActiveRecord::Relation.
def search(query) def search(query, as_user: nil)
table = arel_table table = arel_table
pattern = "%#{query}%" pattern = "%#{query}%"
where(table[:note].matches(pattern)) found_notes = joins('LEFT JOIN issues ON issues.id = noteable_id').
where(table[:note].matches(pattern))
if as_user
found_notes.where('
issues.confidential IS NULL
OR issues.confidential IS FALSE
OR (issues.confidential IS TRUE
AND (issues.author_id = :user_id
OR issues.assignee_id = :user_id
OR issues.project_id IN(:project_ids)))',
user_id: as_user.id,
project_ids: as_user.authorized_projects.select(:id))
else
found_notes.where('issues.confidential IS NULL OR issues.confidential IS FALSE')
end
end end
end end
......
...@@ -309,21 +309,25 @@ class Project < ActiveRecord::Base ...@@ -309,21 +309,25 @@ class Project < ActiveRecord::Base
@repository ||= Repository.new(path_with_namespace, self) @repository ||= Repository.new(path_with_namespace, self)
end end
def container_registry_path_with_namespace
path_with_namespace.downcase
end
def container_registry_repository def container_registry_repository
return unless Gitlab.config.registry.enabled return unless Gitlab.config.registry.enabled
@container_registry_repository ||= begin @container_registry_repository ||= begin
token = Auth::ContainerRegistryAuthenticationService.full_access_token(path_with_namespace) token = Auth::ContainerRegistryAuthenticationService.full_access_token(container_registry_path_with_namespace)
url = Gitlab.config.registry.api_url url = Gitlab.config.registry.api_url
host_port = Gitlab.config.registry.host_port host_port = Gitlab.config.registry.host_port
registry = ContainerRegistry::Registry.new(url, token: token, path: host_port) registry = ContainerRegistry::Registry.new(url, token: token, path: host_port)
registry.repository(path_with_namespace) registry.repository(container_registry_path_with_namespace)
end end
end end
def container_registry_repository_url def container_registry_repository_url
if Gitlab.config.registry.enabled if Gitlab.config.registry.enabled
"#{Gitlab.config.registry.host_port}/#{path_with_namespace}" "#{Gitlab.config.registry.host_port}/#{container_registry_path_with_namespace}"
end end
end end
...@@ -946,13 +950,13 @@ class Project < ActiveRecord::Base ...@@ -946,13 +950,13 @@ class Project < ActiveRecord::Base
shared_runners_enabled? && Ci::Runner.shared.active.any?(&block) shared_runners_enabled? && Ci::Runner.shared.active.any?(&block)
end end
def valid_runners_token? token def valid_runners_token?(token)
self.runners_token && ActiveSupport::SecurityUtils.variable_size_secure_compare(token, self.runners_token) self.runners_token && ActiveSupport::SecurityUtils.variable_size_secure_compare(token, self.runners_token)
end end
# TODO (ayufan): For now we use runners_token (backward compatibility) # TODO (ayufan): For now we use runners_token (backward compatibility)
# In 8.4 every build will have its own individual token valid for time of build # In 8.4 every build will have its own individual token valid for time of build
def valid_build_token? token def valid_build_token?(token)
self.builds_enabled? && self.runners_token && ActiveSupport::SecurityUtils.variable_size_secure_compare(token, self.runners_token) self.builds_enabled? && self.runners_token && ActiveSupport::SecurityUtils.variable_size_secure_compare(token, self.runners_token)
end end
...@@ -1007,4 +1011,22 @@ class Project < ActiveRecord::Base ...@@ -1007,4 +1011,22 @@ class Project < ActiveRecord::Base
update_attribute(:pending_delete, true) update_attribute(:pending_delete, true)
end end
def running_or_pending_build_count(force: false)
Rails.cache.fetch(['projects', id, 'running_or_pending_build_count'], force: force) do
builds.running_or_pending.count(:all)
end
end
def mark_import_as_failed(error_message)
original_errors = errors.dup
sanitized_message = Gitlab::UrlSanitizer.sanitize(error_message)
import_fail
update_column(:import_error, sanitized_message)
rescue ActiveRecord::ActiveRecordError => e
Rails.logger.error("Error setting import status to failed: #{e.message}. Original error: #{sanitized_message}")
ensure
@errors = original_errors
end
end end
...@@ -6,7 +6,8 @@ class ProjectImportData < ActiveRecord::Base ...@@ -6,7 +6,8 @@ class ProjectImportData < ActiveRecord::Base
key: Gitlab::Application.secrets.db_key_base, key: Gitlab::Application.secrets.db_key_base,
marshal: true, marshal: true,
encode: true, encode: true,
mode: :per_attribute_iv_and_salt mode: :per_attribute_iv_and_salt,
algorithm: 'aes-256-cbc'
serialize :data, JSON serialize :data, JSON
......
...@@ -70,7 +70,7 @@ class IrkerService < Service ...@@ -70,7 +70,7 @@ class IrkerService < Service
private private
def get_channels def get_channels
return true unless :activated? return true unless activated?
return true if recipients.nil? || recipients.empty? return true if recipients.nil? || recipients.empty?
map_recipients map_recipients
......
...@@ -7,5 +7,6 @@ class ProjectSnippet < Snippet ...@@ -7,5 +7,6 @@ class ProjectSnippet < Snippet
# Scopes # Scopes
scope :fresh, -> { order("created_at DESC") } scope :fresh, -> { order("created_at DESC") }
participant :author, :notes participant :author
participant :notes_with_associations
end end
...@@ -27,6 +27,10 @@ class ProjectWiki ...@@ -27,6 +27,10 @@ class ProjectWiki
@project.path_with_namespace + ".wiki" @project.path_with_namespace + ".wiki"
end end
def web_url
Gitlab::Routing.url_helpers.namespace_project_wiki_url(@project.namespace, @project, :home)
end
def url_to_repo def url_to_repo
gitlab_shell.url_to_repo(path_with_namespace) gitlab_shell.url_to_repo(path_with_namespace)
end end
...@@ -142,6 +146,16 @@ class ProjectWiki ...@@ -142,6 +146,16 @@ class ProjectWiki
wiki wiki
end end
def hook_attrs
{
web_url: web_url,
git_ssh_url: ssh_url_to_repo,
git_http_url: http_url_to_repo,
path_with_namespace: path_with_namespace,
default_branch: default_branch
}
end
private private
def init_repo(path_with_namespace) def init_repo(path_with_namespace)
......
...@@ -30,7 +30,8 @@ class Snippet < ActiveRecord::Base ...@@ -30,7 +30,8 @@ class Snippet < ActiveRecord::Base
scope :public_and_internal, -> { where(visibility_level: [Snippet::PUBLIC, Snippet::INTERNAL]) } scope :public_and_internal, -> { where(visibility_level: [Snippet::PUBLIC, Snippet::INTERNAL]) }
scope :fresh, -> { order("created_at DESC") } scope :fresh, -> { order("created_at DESC") }
participant :author, :notes participant :author
participant :notes_with_associations
def self.reference_prefix def self.reference_prefix
'$' '$'
...@@ -100,6 +101,10 @@ class Snippet < ActiveRecord::Base ...@@ -100,6 +101,10 @@ class Snippet < ActiveRecord::Base
content.lines.count > 1000 content.lines.count > 1000
end end
def notes_with_associations
notes.includes(:author, :project)
end
class << self class << self
# Searches for snippets with a matching title or file name. # Searches for snippets with a matching title or file name.
# #
......
...@@ -20,6 +20,11 @@ class User < ActiveRecord::Base ...@@ -20,6 +20,11 @@ class User < ActiveRecord::Base
default_value_for :hide_no_password, false default_value_for :hide_no_password, false
default_value_for :theme_id, gitlab_config.default_theme default_value_for :theme_id, gitlab_config.default_theme
attr_encrypted :otp_secret,
key: Gitlab::Application.config.secret_key_base,
mode: :per_attribute_iv_and_salt,
algorithm: 'aes-256-cbc'
devise :two_factor_authenticatable, devise :two_factor_authenticatable,
otp_secret_encryption_key: Gitlab::Application.config.secret_key_base otp_secret_encryption_key: Gitlab::Application.config.secret_key_base
alias_attribute :two_factor_enabled, :otp_required_for_login alias_attribute :two_factor_enabled, :otp_required_for_login
...@@ -27,7 +32,7 @@ class User < ActiveRecord::Base ...@@ -27,7 +32,7 @@ class User < ActiveRecord::Base
devise :two_factor_backupable, otp_number_of_backup_codes: 10 devise :two_factor_backupable, otp_number_of_backup_codes: 10
serialize :otp_backup_codes, JSON serialize :otp_backup_codes, JSON
devise :lockable, :async, :recoverable, :rememberable, :trackable, devise :lockable, :recoverable, :rememberable, :trackable,
:validatable, :omniauthable, :confirmable, :registerable :validatable, :omniauthable, :confirmable, :registerable
attr_accessor :force_random_password attr_accessor :force_random_password
...@@ -772,6 +777,23 @@ class User < ActiveRecord::Base ...@@ -772,6 +777,23 @@ class User < ActiveRecord::Base
notification_settings.find_or_initialize_by(source: source) notification_settings.find_or_initialize_by(source: source)
end end
def assigned_open_merge_request_count(force: false)
Rails.cache.fetch(['users', id, 'assigned_open_merge_request_count'], force: force) do
assigned_merge_requests.opened.count
end
end
def assigned_open_issues_count(force: false)
Rails.cache.fetch(['users', id, 'assigned_open_issues_count'], force: force) do
assigned_issues.opened.count
end
end
def update_cache_counts
assigned_open_merge_request_count(force: true)
assigned_open_issues_count(force: true)
end
private private
def projects_union def projects_union
......
module Auth module Auth
class ContainerRegistryAuthenticationService < BaseService class ContainerRegistryAuthenticationService < BaseService
include Gitlab::CurrentSettings
AUDIENCE = 'container_registry' AUDIENCE = 'container_registry'
def execute def execute
return error('not found', 404) unless registry.enabled return error('not found', 404) unless registry.enabled
if params[:offline_token] unless current_user || project
return error('unauthorized', 401) unless current_user || project
else
return error('forbidden', 403) unless scope return error('forbidden', 403) unless scope
end end
...@@ -19,6 +19,7 @@ module Auth ...@@ -19,6 +19,7 @@ module Auth
token = JSONWebToken::RSAToken.new(registry.key) token = JSONWebToken::RSAToken.new(registry.key)
token.issuer = registry.issuer token.issuer = registry.issuer
token.audience = AUDIENCE token.audience = AUDIENCE
token.expire_time = token_expire_at
token[:access] = names.map do |name| token[:access] = names.map do |name|
{ type: 'repository', name: name, actions: %w(*) } { type: 'repository', name: name, actions: %w(*) }
end end
...@@ -32,6 +33,7 @@ module Auth ...@@ -32,6 +33,7 @@ module Auth
token.issuer = registry.issuer token.issuer = registry.issuer
token.audience = params[:service] token.audience = params[:service]
token.subject = current_user.try(:username) token.subject = current_user.try(:username)
token.expire_time = ContainerRegistryAuthenticationService.token_expire_at
token[:access] = accesses.compact token[:access] = accesses.compact
token token
end end
...@@ -77,5 +79,9 @@ module Auth ...@@ -77,5 +79,9 @@ module Auth
def registry def registry
Gitlab.config.registry Gitlab.config.registry
end end
def self.token_expire_at
Time.now + current_application_settings.container_registry_token_expire_delay.minutes
end
end end
end end
...@@ -23,7 +23,7 @@ class GitTagPushService < BaseService ...@@ -23,7 +23,7 @@ class GitTagPushService < BaseService
commits = [] commits = []
message = nil message = nil
if !Gitlab::Git.blank_ref?(params[:newrev]) unless Gitlab::Git.blank_ref?(params[:newrev])
tag_name = Gitlab::Git.ref_name(params[:ref]) tag_name = Gitlab::Git.ref_name(params[:ref])
tag = project.repository.find_tag(tag_name) tag = project.repository.find_tag(tag_name)
if tag && tag.target == params[:newrev] if tag && tag.target == params[:newrev]
......
...@@ -56,14 +56,14 @@ module Projects ...@@ -56,14 +56,14 @@ module Projects
after_create_actions if @project.persisted? after_create_actions if @project.persisted?
@project.add_import_job if @project.import? if @project.errors.empty?
@project.add_import_job if @project.import?
else
fail(error: @project.errors.full_messages.join(', '))
end
@project @project
rescue => e rescue => e
message = "Unable to save project: #{e.message}" fail(error: e.message)
Rails.logger.error(message)
@project.errors.add(:base, message) if @project
@project
end end
protected protected
...@@ -103,5 +103,19 @@ module Projects ...@@ -103,5 +103,19 @@ module Projects
end end
end end
end end
def fail(error:)
message = "Unable to save project. Error: #{error}"
message << "Project ID: #{@project.id}" if @project && @project.id
Rails.logger.error(message)
if @project && @project.import?
@project.errors.add(:base, message)
@project.mark_import_as_failed(message)
end
@project
end
end end
end end
...@@ -22,7 +22,7 @@ module Projects ...@@ -22,7 +22,7 @@ module Projects
end end
def execute def execute
raise LeaseTaken if !try_obtain_lease raise LeaseTaken unless try_obtain_lease
GitlabShellOneShotWorker.perform_async(:gc, @project.path_with_namespace) GitlabShellOneShotWorker.perform_async(:gc, @project.path_with_namespace)
ensure ensure
......
...@@ -39,7 +39,7 @@ module Projects ...@@ -39,7 +39,7 @@ module Projects
begin begin
gitlab_shell.import_repository(project.path_with_namespace, project.import_url) gitlab_shell.import_repository(project.path_with_namespace, project.import_url)
rescue Gitlab::Shell::Error => e rescue Gitlab::Shell::Error => e
raise Error, e.message raise Error, "Error importing repository #{project.import_url} into #{project.path_with_namespace} - #{e.message}"
end end
end end
......
...@@ -6,9 +6,8 @@ module WikiPages ...@@ -6,9 +6,8 @@ module WikiPages
object_kind: page.class.name.underscore, object_kind: page.class.name.underscore,
user: current_user.hook_attrs, user: current_user.hook_attrs,
project: @project.hook_attrs, project: @project.hook_attrs,
object_attributes: page.hook_attrs, wiki: @project.wiki.hook_attrs,
# DEPRECATED object_attributes: page.hook_attrs
repository: @project.hook_attrs.slice(:name, :url, :description, :homepage)
} }
page_url = Gitlab::UrlBuilder.build(page) page_url = Gitlab::UrlBuilder.build(page)
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
.light.small .light.small
= time_ago_with_tooltip(abuse_report.created_at) = time_ago_with_tooltip(abuse_report.created_at)
%td %td
= markdown(abuse_report.message.squish!, pipeline: :single_line) = markdown(abuse_report.message.squish!, pipeline: :single_line, author: reporter)
%td %td
- if user - if user
= link_to 'Remove user & report', admin_abuse_report_path(abuse_report, remove_user: true), = link_to 'Remove user & report', admin_abuse_report_path(abuse_report, remove_user: true),
......
...@@ -178,6 +178,14 @@ ...@@ -178,6 +178,14 @@
.col-sm-10 .col-sm-10
= f.number_field :max_artifacts_size, class: 'form-control' = f.number_field :max_artifacts_size, class: 'form-control'
- if Gitlab.config.registry.enabled
%fieldset
%legend Container Registry
.form-group
= f.label :container_registry_token_expire_delay, 'Authorization token duration (minutes)', class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :container_registry_token_expire_delay, class: 'form-control'
%fieldset %fieldset
%legend Metrics %legend Metrics
%p %p
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
%h3 Two-factor Authentication %h3 Two-factor Authentication
.login-body .login-body
= form_for(resource, as: resource_name, url: session_path(resource_name), method: :post) do |f| = form_for(resource, as: resource_name, url: session_path(resource_name), method: :post) do |f|
= f.hidden_field :remember_me, value: params[resource_name][:remember_me]
= f.text_field :otp_attempt, class: 'form-control', placeholder: 'Two-factor Authentication code', required: true, autofocus: true = f.text_field :otp_attempt, class: 'form-control', placeholder: 'Two-factor Authentication code', required: true, autofocus: true
%p.help-block.hint Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes. %p.help-block.hint Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes.
.prepend-top-20 .prepend-top-20
......
...@@ -2,4 +2,4 @@ ...@@ -2,4 +2,4 @@
.commit-row-title .commit-row-title
= link_to truncate_sha(commit[:id]), namespace_project_commit_path(project.namespace, project, commit[:id]), class: "commit_short_id", alt: '', title: truncate_sha(commit[:id]) = link_to truncate_sha(commit[:id]), namespace_project_commit_path(project.namespace, project, commit[:id]), class: "commit_short_id", alt: '', title: truncate_sha(commit[:id])
&middot; &middot;
= markdown event_commit_title(commit[:message]), project: project, pipeline: :single_line = markdown event_commit_title(commit[:message]), project: project, pipeline: :single_line, author: event.author
%div{xmlns: "http://www.w3.org/1999/xhtml"} %div{xmlns: "http://www.w3.org/1999/xhtml"}
= markdown(issue.description, pipeline: :atom, project: issue.project) = markdown(issue.description, pipeline: :atom, project: issue.project, author: issue.author)
%div{xmlns: "http://www.w3.org/1999/xhtml"} %div{xmlns: "http://www.w3.org/1999/xhtml"}
= markdown(merge_request.description, pipeline: :atom, project: merge_request.project) = markdown(merge_request.description, pipeline: :atom, project: merge_request.project, author: merge_request.author)
%div{xmlns: "http://www.w3.org/1999/xhtml"} %div{xmlns: "http://www.w3.org/1999/xhtml"}
= markdown(note.note, pipeline: :atom, project: note.project) = markdown(note.note, pipeline: :atom, project: note.project, author: note.author)
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
%i %i
at at
= commit[:timestamp].to_time.to_s(:short) = commit[:timestamp].to_time.to_s(:short)
%blockquote= markdown(escape_once(commit[:message]), pipeline: :atom, project: event.project) %blockquote= markdown(escape_once(commit[:message]), pipeline: :atom, project: event.project, author: event.author)
- if event.commits_count > 15 - if event.commits_count > 15
%p %p
%i %i
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
= event_action_name(event) = event_action_name(event)
- if event.target - if event.target
%strong= link_to event.target.reference_link_text, [event.project.namespace.becomes(Namespace), event.project, event.target], title: event.target_title %strong= link_to event.target.reference_link_text, [event.project.namespace.becomes(Namespace), event.project, event.target], class: 'has-tooltip', title: event.target_title
= event_preposition(event) = event_preposition(event)
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
%ul.well-list.event_commits %ul.well-list.event_commits
- few_commits = event.commits[0...2] - few_commits = event.commits[0...2]
- few_commits.each do |commit| - few_commits.each do |commit|
= render "events/commit", commit: commit, project: project = render "events/commit", commit: commit, project: project, event: event
- create_mr = event.new_ref? && create_mr_button?(event.project.default_branch, event.ref_name, event.project) - create_mr = event.new_ref? && create_mr_button?(event.project.default_branch, event.ref_name, event.project)
- if event.commits_count > 1 - if event.commits_count > 1
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
-# available local variables -# available local variables
-# url: url to the first page -# url: url to the first page
-# current_page: a page object for the currently displayed page -# current_page: a page object for the currently displayed page
-# num_pages: total number of pages -# total_pages: total number of pages
-# per_page: number of items to fetch per page -# per_page: number of items to fetch per page
-# remote: data-remote -# remote: data-remote
%li.first %li.first
......
-# Non-link tag that stands for skipped pages... -# Non-link tag that stands for skipped pages...
-# available local variables -# available local variables
-# current_page: a page object for the currently displayed page -# current_page: a page object for the currently displayed page
-# num_pages: total number of pages -# total_pages: total number of pages
-# per_page: number of items to fetch per page -# per_page: number of items to fetch per page
-# remote: data-remote -# remote: data-remote
%li{class: "page"} %li{class: "page"}
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
-# available local variables -# available local variables
-# url: url to the last page -# url: url to the last page
-# current_page: a page object for the currently displayed page -# current_page: a page object for the currently displayed page
-# num_pages: total number of pages -# total_pages: total number of pages
-# per_page: number of items to fetch per page -# per_page: number of items to fetch per page
-# remote: data-remote -# remote: data-remote
%li.last %li.last
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
-# available local variables -# available local variables
-# url: url to the next page -# url: url to the next page
-# current_page: a page object for the currently displayed page -# current_page: a page object for the currently displayed page
-# num_pages: total number of pages -# total_pages: total number of pages
-# per_page: number of items to fetch per page -# per_page: number of items to fetch per page
-# remote: data-remote -# remote: data-remote
- if current_page.last? - if current_page.last?
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
-# page: a page object for "this" page -# page: a page object for "this" page
-# url: url to this page -# url: url to this page
-# current_page: a page object for the currently displayed page -# current_page: a page object for the currently displayed page
-# num_pages: total number of pages -# total_pages: total number of pages
-# per_page: number of items to fetch per page -# per_page: number of items to fetch per page
-# remote: data-remote -# remote: data-remote
%li{class: "page#{' active' if page.current?}"} %li{class: "page#{' active' if page.current?}"}
......
-# The container tag -# The container tag
-# available local variables -# available local variables
-# current_page: a page object for the currently displayed page -# current_page: a page object for the currently displayed page
-# num_pages: total number of pages -# total_pages: total number of pages
-# per_page: number of items to fetch per page -# per_page: number of items to fetch per page
-# remote: data-remote -# remote: data-remote
-# paginator: the paginator that renders the pagination tags inside -# paginator: the paginator that renders the pagination tags inside
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
%div.gl-pagination %div.gl-pagination
%ul.pagination.clearfix %ul.pagination.clearfix
- unless current_page.first? - unless current_page.first?
= first_page_tag unless num_pages < 5 # As kaminari will always show the first 5 pages = first_page_tag unless total_pages < 5 # As kaminari will always show the first 5 pages
= prev_page_tag = prev_page_tag
- each_page do |page| - each_page do |page|
- if page.left_outer? || page.right_outer? || page.inside_window? - if page.left_outer? || page.right_outer? || page.inside_window?
...@@ -18,5 +18,5 @@ ...@@ -18,5 +18,5 @@
= gap_tag = gap_tag
= next_page_tag = next_page_tag
- unless current_page.last? - unless current_page.last?
= last_page_tag unless num_pages < 5 = last_page_tag unless total_pages < 5
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
-# available local variables -# available local variables
-# url: url to the previous page -# url: url to the previous page
-# current_page: a page object for the currently displayed page -# current_page: a page object for the currently displayed page
-# num_pages: total number of pages -# total_pages: total number of pages
-# per_page: number of items to fetch per page -# per_page: number of items to fetch per page
-# remote: data-remote -# remote: data-remote
- if current_page.first? - if current_page.first?
......
...@@ -30,6 +30,9 @@ ...@@ -30,6 +30,9 @@
= javascript_include_tag "application" = javascript_include_tag "application"
- if page_specific_javascripts
= javascript_include_tag page_specific_javascripts, {"data-turbolinks-track" => true}
= csrf_meta_tags = csrf_meta_tags
= include_gon = include_gon
......
...@@ -6,11 +6,8 @@ ...@@ -6,11 +6,8 @@
.search.search-form{class: "#{'has-location-badge' if label.present?}"} .search.search-form{class: "#{'has-location-badge' if label.present?}"}
= form_tag search_path, method: :get, class: 'navbar-form' do |f| = form_tag search_path, method: :get, class: 'navbar-form' do |f|
.search-input-container .search-input-container
.search-location-badge - if label.present?
- if label.present? .location-badge= label
%span.location-badge
%i.location-text
= label
.search-input-wrap .search-input-wrap
.dropdown{ data: {url: search_autocomplete_path } } .dropdown{ data: {url: search_autocomplete_path } }
= search_field_tag "search", nil, placeholder: 'Search', class: "search-input dropdown-menu-toggle", spellcheck: false, tabindex: "1", autocomplete: 'off', data: { toggle: 'dropdown' } = search_field_tag "search", nil, placeholder: 'Search', class: "search-input dropdown-menu-toggle", spellcheck: false, tabindex: "1", autocomplete: 'off', data: { toggle: 'dropdown' }
......
...@@ -30,13 +30,13 @@ ...@@ -30,13 +30,13 @@
= icon('exclamation-circle fw') = icon('exclamation-circle fw')
%span %span
Issues Issues
%span.count= number_with_delimiter(current_user.assigned_issues.opened.count) %span.count= number_with_delimiter(current_user.assigned_open_issues_count)
= nav_link(path: 'dashboard#merge_requests') do = nav_link(path: 'dashboard#merge_requests') do
= link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'dashboard-shortcuts-merge_requests' do = link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'dashboard-shortcuts-merge_requests' do
= icon('tasks fw') = icon('tasks fw')
%span %span
Merge Requests Merge Requests
%span.count= number_with_delimiter(current_user.assigned_merge_requests.opened.count) %span.count= number_with_delimiter(current_user.assigned_open_merge_request_count)
= nav_link(controller: :snippets) do = nav_link(controller: :snippets) do
= link_to dashboard_snippets_path, title: 'Snippets' do = link_to dashboard_snippets_path, title: 'Snippets' do
= icon('clipboard fw') = icon('clipboard fw')
......
...@@ -33,18 +33,11 @@ ...@@ -33,18 +33,11 @@
%span %span
Activity Activity
- if project_nav_tab? :files - if project_nav_tab? :files
= nav_link(controller: %w(tree blob blame edit_tree new_tree find_file)) do = nav_link(controller: %w(tree blob blame edit_tree new_tree find_file commit commits compare repositories tags branches releases network)) do
= link_to project_files_path(@project), title: 'Files', class: 'shortcuts-tree' do = link_to project_files_path(@project), title: 'Files', class: 'shortcuts-tree' do
= icon('files-o fw') = icon('code fw')
%span %span
Files Code
- if project_nav_tab? :commits
= nav_link(controller: %w(commit commits compare repositories tags branches releases network)) do
= link_to project_commits_path(@project), title: 'Commits', class: 'shortcuts-commits' do
= icon('history fw')
%span
Commits
- if project_nav_tab? :pipelines - if project_nav_tab? :pipelines
= nav_link(controller: :pipelines) do = nav_link(controller: :pipelines) do
...@@ -52,15 +45,6 @@ ...@@ -52,15 +45,6 @@
= icon('ship fw') = icon('ship fw')
%span %span
Pipelines Pipelines
%span.badge.count.ci_counter= number_with_delimiter(@project.ci_commits.running_or_pending.count)
- if project_nav_tab? :builds
= nav_link(controller: %w(builds)) do
= link_to project_builds_path(@project), title: 'Builds', class: 'shortcuts-builds' do
= icon('cubes fw')
%span
Builds
%span.badge.count.builds_counter= number_with_delimiter(@project.builds.running_or_pending.count(:all))
- if project_nav_tab? :container_registry - if project_nav_tab? :container_registry
= nav_link(controller: %w(container_registry)) do = nav_link(controller: %w(container_registry)) do
...@@ -132,4 +116,16 @@ ...@@ -132,4 +116,16 @@
= link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'shortcuts-new-issue' do = link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'shortcuts-new-issue' do
Create a new issue Create a new issue
-# Shortcut to builds page
- if project_nav_tab? :builds
%li.hidden
= link_to project_builds_path(@project), title: 'Builds', class: 'shortcuts-builds' do
Builds
-# Shortcut to commits page
- if project_nav_tab? :commits
%li.hidden
= link_to project_commits_path(@project), title: 'Commits', class: 'shortcuts-commits' do
Commits
.fade-right .fade-right
...@@ -2,4 +2,4 @@ ...@@ -2,4 +2,4 @@
%div %div
#{link_to @note.author_name, user_url(@note.author)} wrote: #{link_to @note.author_name, user_url(@note.author)} wrote:
%div %div
= markdown(@note.note, pipeline: :email) = markdown(@note.note, pipeline: :email, author: @note.author)
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
%div %div
#{link_to @issue.author_name, user_url(@issue.author)} wrote: #{link_to @issue.author_name, user_url(@issue.author)} wrote:
-if @issue.description -if @issue.description
= markdown(@issue.description, pipeline: :email) = markdown(@issue.description, pipeline: :email, author: @issue.author)
- if @issue.assignee_id.present? - if @issue.assignee_id.present?
%p %p
......
...@@ -9,4 +9,4 @@ ...@@ -9,4 +9,4 @@
Assignee: #{@merge_request.author_name} &rarr; #{@merge_request.assignee_name} Assignee: #{@merge_request.author_name} &rarr; #{@merge_request.assignee_name}
-if @merge_request.description -if @merge_request.description
= markdown(@merge_request.description, pipeline: :email) = markdown(@merge_request.description, pipeline: :email, author: @merge_request.author)
$('.js-totalbranch-count').html("#{@repository.branch_count}")
- page_title "Builds" - page_title "Builds"
= render "projects/pipelines/head"
.top-area .top-area
%ul.nav-links %ul.nav-links
......
...@@ -63,9 +63,9 @@ ...@@ -63,9 +63,9 @@
%span #{build.name} %span #{build.name}
- if can?(current_user, :update_pipeline, @project) - if can?(current_user, :update_pipeline, @project)
- if commit.retryable? && commit.builds.failed.any? - if commit.retryable?
= link_to retry_namespace_project_pipeline_path(@project.namespace, @project, commit.id), class: 'btn has-tooltip', title: "Retry", method: :post do = link_to retry_namespace_project_pipeline_path(@project.namespace, @project, commit.id), class: 'btn has-tooltip', title: "Retry", method: :post do
= icon("repeat") = icon("repeat")
- if commit.active? - if commit.cancelable?
= link_to cancel_namespace_project_pipeline_path(@project.namespace, @project, commit.id), class: 'btn btn-remove has-tooltip', title: "Cancel", method: :post do = link_to cancel_namespace_project_pipeline_path(@project.namespace, @project, commit.id), class: 'btn btn-remove has-tooltip', title: "Cancel", method: :post do
= icon("remove") = icon("remove")
.row-content-block.build-content.middle-block .row-content-block.build-content.middle-block
.pull-right .pull-right
- if can?(current_user, :update_pipeline, @project) - if can?(current_user, :update_pipeline, ci_commit.project)
- if ci_commit.builds.latest.failed.any?(&:retryable?) - if ci_commit.builds.latest.failed.any?(&:retryable?)
= link_to "Retry failed", retry_namespace_project_pipeline_path(@project.namespace, @project, ci_commit.id), class: 'btn btn-grouped btn-primary', method: :post = link_to "Retry failed", retry_namespace_project_pipeline_path(ci_commit.project.namespace, ci_commit.project, ci_commit.id), class: 'btn btn-grouped btn-primary', method: :post
- if ci_commit.builds.running_or_pending.any? - if ci_commit.builds.running_or_pending.any?
= link_to "Cancel running", cancel_namespace_project_pipeline_path(@project.namespace, @project, ci_commit.id), data: { confirm: 'Are you sure?' }, class: 'btn btn-grouped btn-danger', method: :post = link_to "Cancel running", cancel_namespace_project_pipeline_path(ci_commit.project.namespace, ci_commit.project, ci_commit.id), data: { confirm: 'Are you sure?' }, class: 'btn btn-grouped btn-danger', method: :post
.oneline.clearfix .oneline.clearfix
- if defined?(pipeline_details) && pipeline_details - if defined?(pipeline_details) && pipeline_details
Pipeline Pipeline
= link_to "##{ci_commit.id}", namespace_project_pipeline_path(@project.namespace, @project, ci_commit.id), class: "monospace" = link_to "##{ci_commit.id}", namespace_project_pipeline_path(ci_commit.project.namespace, ci_commit.project, ci_commit.id), class: "monospace"
with with
= pluralize ci_commit.statuses.count(:id), "build" = pluralize ci_commit.statuses.count(:id), "build"
- if ci_commit.ref - if ci_commit.ref
for for
= link_to ci_commit.ref, namespace_project_commits_path(@project.namespace, @project, ci_commit.ref), class: "monospace" = link_to ci_commit.ref, namespace_project_commits_path(ci_commit.project.namespace, ci_commit.project, ci_commit.ref), class: "monospace"
- if defined?(link_to_commit) && link_to_commit - if defined?(link_to_commit) && link_to_commit
for commit for commit
= link_to ci_commit.short_sha, namespace_project_commit_path(@project.namespace, @project, ci_commit.sha), class: "monospace" = link_to ci_commit.short_sha, namespace_project_commit_path(ci_commit.project.namespace, ci_commit.project, ci_commit.sha), class: "monospace"
- if ci_commit.duration - if ci_commit.duration
in in
= time_interval_in_words ci_commit.duration = time_interval_in_words ci_commit.duration
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
%li= error %li= error
You can also test your .gitlab-ci.yml in the #{link_to "Lint", ci_lint_path} You can also test your .gitlab-ci.yml in the #{link_to "Lint", ci_lint_path}
- if @project.builds_enabled? && !ci_commit.ci_yaml_file - if ci_commit.project.builds_enabled? && !ci_commit.ci_yaml_file
.bs-callout.bs-callout-warning .bs-callout.bs-callout-warning
\.gitlab-ci.yml not found in this commit \.gitlab-ci.yml not found in this commit
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
%th Tags %th Tags
%th Duration %th Duration
%th Finished at %th Finished at
- if @project.build_coverage_enabled? - if ci_commit.project.build_coverage_enabled?
%th Coverage %th Coverage
%th %th
- ci_commit.statuses.stages.each do |stage| - ci_commit.statuses.stages.each do |stage|
......
...@@ -63,10 +63,10 @@ ...@@ -63,10 +63,10 @@
.commit-box.content-block .commit-box.content-block
%h3.commit-title %h3.commit-title
= markdown escape_once(@commit.title), pipeline: :single_line = markdown escape_once(@commit.title), pipeline: :single_line, author: @commit.author
- if @commit.description.present? - if @commit.description.present?
%pre.commit-description %pre.commit-description
= preserve(markdown(escape_once(@commit.description), pipeline: :single_line)) = preserve(markdown(escape_once(@commit.description), pipeline: :single_line, author: @commit.author))
:javascript :javascript
$(".commit-info.branches").load("#{branches_namespace_project_commit_path(@project.namespace, @project, @commit.id)}"); $(".commit-info.branches").load("#{branches_namespace_project_commit_path(@project.namespace, @project, @commit.id)}");
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
- if commit.description? - if commit.description?
.commit-row-description.js-toggle-content .commit-row-description.js-toggle-content
%pre %pre
= preserve(markdown(escape_once(commit.description), pipeline: :single_line)) = preserve(markdown(escape_once(commit.description), pipeline: :single_line, author: commit.author))
.commit-row-info .commit-row-info
by by
......
%ul.nav-links %ul.nav-links
= nav_link(controller: %w(tree blob blame edit_tree new_tree find_file)) do
= link_to project_files_path(@project) do
Files
= nav_link(controller: [:commit, :commits]) do = nav_link(controller: [:commit, :commits]) do
= link_to namespace_project_commits_path(@project.namespace, @project, current_ref) do = link_to namespace_project_commits_path(@project.namespace, @project, current_ref) do
Commits Commits
%span.badge
= number_with_delimiter(@repository.commit_count)
= nav_link(controller: %w(network)) do = nav_link(controller: %w(network)) do
= link_to namespace_project_network_path(@project.namespace, @project, current_ref) do = link_to namespace_project_network_path(@project.namespace, @project, current_ref) do
...@@ -16,9 +18,7 @@ ...@@ -16,9 +18,7 @@
= nav_link(html_options: {class: branches_tab_class}) do = nav_link(html_options: {class: branches_tab_class}) do
= link_to namespace_project_branches_path(@project.namespace, @project) do = link_to namespace_project_branches_path(@project.namespace, @project) do
Branches Branches
%span.badge.js-totalbranch-count= @repository.branch_count
= nav_link(controller: [:tags, :releases]) do = nav_link(controller: [:tags, :releases]) do
= link_to namespace_project_tags_path(@project.namespace, @project) do = link_to namespace_project_tags_path(@project.namespace, @project) do
Tags Tags
%span.badge.js-totaltags-count= @repository.tag_count
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment