Merge branch 'master' into ide-staged-changes
This commit is contained in:
		
						commit
						74b77ebf50
					
				
							
								
								
									
										26
									
								
								.babelrc
								
								
								
								
							
							
						
						
									
										26
									
								
								.babelrc
								
								
								
								
							| 
						 | 
				
			
			@ -1,20 +1,20 @@
 | 
			
		|||
{
 | 
			
		||||
  "presets": [
 | 
			
		||||
    ["latest", { "es2015": { "modules": false } }],
 | 
			
		||||
    "stage-2"
 | 
			
		||||
  ],
 | 
			
		||||
  "presets": [["latest", { "es2015": { "modules": false } }], "stage-2"],
 | 
			
		||||
  "env": {
 | 
			
		||||
    "coverage": {
 | 
			
		||||
      "plugins": [
 | 
			
		||||
        ["istanbul", {
 | 
			
		||||
          "exclude": [
 | 
			
		||||
            "spec/javascripts/**/*",
 | 
			
		||||
            "app/assets/javascripts/locale/**/app.js"
 | 
			
		||||
          ]
 | 
			
		||||
        }],
 | 
			
		||||
        ["transform-define", {
 | 
			
		||||
          "process.env.BABEL_ENV": "coverage"
 | 
			
		||||
        }]
 | 
			
		||||
        [
 | 
			
		||||
          "istanbul",
 | 
			
		||||
          {
 | 
			
		||||
            "exclude": ["spec/javascripts/**/*", "app/assets/javascripts/locale/**/app.js"]
 | 
			
		||||
          }
 | 
			
		||||
        ],
 | 
			
		||||
        [
 | 
			
		||||
          "transform-define",
 | 
			
		||||
          {
 | 
			
		||||
            "process.env.BABEL_ENV": "coverage"
 | 
			
		||||
          }
 | 
			
		||||
        ]
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,11 +1,12 @@
 | 
			
		|||
/app/assets/javascripts/locale/**/app.js
 | 
			
		||||
/config/
 | 
			
		||||
/builds/
 | 
			
		||||
/coverage/
 | 
			
		||||
/coverage-javascript/
 | 
			
		||||
/node_modules/
 | 
			
		||||
/public/
 | 
			
		||||
/scripts/
 | 
			
		||||
/tmp/
 | 
			
		||||
/vendor/
 | 
			
		||||
karma.config.js
 | 
			
		||||
webpack.config.js
 | 
			
		||||
svg.config.js
 | 
			
		||||
/app/assets/javascripts/locale/**/app.js
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -544,7 +544,7 @@ migration:path-mysql:
 | 
			
		|||
.db-rollback: &db-rollback
 | 
			
		||||
  <<: *dedicated-no-docs-pull-cache-job
 | 
			
		||||
  script:
 | 
			
		||||
    - bundle exec rake db:rollback STEP=119
 | 
			
		||||
    - bundle exec rake db:migrate VERSION=20170523121229
 | 
			
		||||
    - bundle exec rake db:migrate
 | 
			
		||||
 | 
			
		||||
db:rollback-pg:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
/app/assets/javascripts/locale/**/app.js
 | 
			
		||||
/node_modules/
 | 
			
		||||
/public/
 | 
			
		||||
/vendor/
 | 
			
		||||
/tmp/
 | 
			
		||||
							
								
								
									
										11
									
								
								.prettierrc
								
								
								
								
							
							
						
						
									
										11
									
								
								.prettierrc
								
								
								
								
							| 
						 | 
				
			
			@ -1,4 +1,13 @@
 | 
			
		|||
{
 | 
			
		||||
  "printWidth": 100,
 | 
			
		||||
  "singleQuote": true,
 | 
			
		||||
  "trailingComma": "all"
 | 
			
		||||
  "trailingComma": "es5",
 | 
			
		||||
  "overrides": [
 | 
			
		||||
    {
 | 
			
		||||
      "files": ["**/app/**/*", "**/spec/**/*"],
 | 
			
		||||
      "options": {
 | 
			
		||||
        "trailingComma": "all"
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -118,6 +118,9 @@ Gitlab/ModuleWithInstanceVariables:
 | 
			
		|||
    - spec/support/**/*.rb
 | 
			
		||||
    - features/steps/**/*.rb
 | 
			
		||||
 | 
			
		||||
Gitlab/HTTParty:
 | 
			
		||||
  Enabled: true
 | 
			
		||||
 | 
			
		||||
GitlabSecurity/PublicSend:
 | 
			
		||||
  Enabled: true
 | 
			
		||||
  Exclude:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -168,13 +168,17 @@ entry.
 | 
			
		|||
- Add one group board to Libre.
 | 
			
		||||
- Add support for filtering by source and target branch to merge requests API.
 | 
			
		||||
 | 
			
		||||
### Other (14 changes, 3 of them are from the community)
 | 
			
		||||
### Other (18 changes, 7 of them are from the community)
 | 
			
		||||
 | 
			
		||||
- Group MRs on issue page by project and namespace. !8494 (Jeff Stubler)
 | 
			
		||||
- Make oauth provider login generic. !8809 (Horatiu Eugen Vlad)
 | 
			
		||||
- Add email button to new issue by email. !10942 (Islam Wazery)
 | 
			
		||||
- Update vue component naming guidelines. !17018 (George Tsiolis)
 | 
			
		||||
- Added new design for promotion modals. !17197
 | 
			
		||||
- Update to github-linguist 5.3.x. !17241 (Ken Ding)
 | 
			
		||||
- update toml-rb to 1.0.0. !17259 (Ken Ding)
 | 
			
		||||
- Keep track of projects a user interacted with. !17327
 | 
			
		||||
- Moved o_auth/saml/ldap modules under gitlab/auth. !17359 (Horatiu Eugen Vlad)
 | 
			
		||||
- Enables eslint in codeclimate job. !17392
 | 
			
		||||
- Port Labels Select dropdown to Vue. !17411
 | 
			
		||||
- Add NOT NULL constraint to projects.namespace_id. !17448
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +1 @@
 | 
			
		|||
7.1.0
 | 
			
		||||
7.1.1
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										9
									
								
								Gemfile
								
								
								
								
							
							
						
						
									
										9
									
								
								Gemfile
								
								
								
								
							| 
						 | 
				
			
			@ -38,7 +38,7 @@ gem 'devise', '~> 4.2'
 | 
			
		|||
gem 'doorkeeper', '~> 4.3'
 | 
			
		||||
gem 'doorkeeper-openid_connect', '~> 1.3'
 | 
			
		||||
gem 'omniauth', '~> 1.8'
 | 
			
		||||
gem 'omniauth-auth0', '~> 1.4.1'
 | 
			
		||||
gem 'omniauth-auth0', '~> 2.0.0'
 | 
			
		||||
gem 'omniauth-azure-oauth2', '~> 0.0.9'
 | 
			
		||||
gem 'omniauth-cas3', '~> 1.1.4'
 | 
			
		||||
gem 'omniauth-facebook', '~> 4.0.0'
 | 
			
		||||
| 
						 | 
				
			
			@ -49,9 +49,10 @@ gem 'omniauth-kerberos', '~> 0.3.0', group: :kerberos
 | 
			
		|||
gem 'omniauth-oauth2-generic', '~> 0.2.2'
 | 
			
		||||
gem 'omniauth-saml', '~> 1.10'
 | 
			
		||||
gem 'omniauth-shibboleth', '~> 1.2.0'
 | 
			
		||||
gem 'omniauth-twitter', '~> 1.2.0'
 | 
			
		||||
gem 'omniauth-twitter', '~> 1.4'
 | 
			
		||||
gem 'omniauth_crowd', '~> 2.2.0'
 | 
			
		||||
gem 'omniauth-authentiq', '~> 0.3.1'
 | 
			
		||||
gem 'omniauth-jwt', '~> 0.0.2'
 | 
			
		||||
gem 'rack-oauth2', '~> 1.2.1'
 | 
			
		||||
gem 'jwt', '~> 1.5.6'
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -162,7 +163,7 @@ group :unicorn do
 | 
			
		|||
end
 | 
			
		||||
 | 
			
		||||
# State machine
 | 
			
		||||
gem 'state_machines-activerecord', '~> 0.4.0'
 | 
			
		||||
gem 'state_machines-activerecord', '~> 0.5.1'
 | 
			
		||||
 | 
			
		||||
# Issue tags
 | 
			
		||||
gem 'acts-as-taggable-on', '~> 5.0'
 | 
			
		||||
| 
						 | 
				
			
			@ -231,7 +232,7 @@ gem 'sanitize', '~> 2.0'
 | 
			
		|||
gem 'babosa', '~> 1.0.2'
 | 
			
		||||
 | 
			
		||||
# Sanitizes SVG input
 | 
			
		||||
gem 'loofah', '~> 2.0.3'
 | 
			
		||||
gem 'loofah', '~> 2.2'
 | 
			
		||||
 | 
			
		||||
# Working with license
 | 
			
		||||
gem 'licensee', '~> 8.9'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										48
									
								
								Gemfile.lock
								
								
								
								
							
							
						
						
									
										48
									
								
								Gemfile.lock
								
								
								
								
							| 
						 | 
				
			
			@ -143,6 +143,7 @@ GEM
 | 
			
		|||
    connection_pool (2.2.1)
 | 
			
		||||
    crack (0.4.3)
 | 
			
		||||
      safe_yaml (~> 1.0.0)
 | 
			
		||||
    crass (1.0.3)
 | 
			
		||||
    creole (0.5.0)
 | 
			
		||||
    css_parser (1.5.0)
 | 
			
		||||
      addressable
 | 
			
		||||
| 
						 | 
				
			
			@ -356,7 +357,7 @@ GEM
 | 
			
		|||
      signet (~> 0.7)
 | 
			
		||||
    gpgme (2.0.13)
 | 
			
		||||
      mini_portile2 (~> 2.1)
 | 
			
		||||
    grape (1.0.0)
 | 
			
		||||
    grape (1.0.2)
 | 
			
		||||
      activesupport
 | 
			
		||||
      builder
 | 
			
		||||
      mustermann-grape (~> 1.0.0)
 | 
			
		||||
| 
						 | 
				
			
			@ -485,7 +486,8 @@ GEM
 | 
			
		|||
      actionpack (>= 4, < 5.2)
 | 
			
		||||
      activesupport (>= 4, < 5.2)
 | 
			
		||||
      railties (>= 4, < 5.2)
 | 
			
		||||
    loofah (2.0.3)
 | 
			
		||||
    loofah (2.2.2)
 | 
			
		||||
      crass (~> 1.0.2)
 | 
			
		||||
      nokogiri (>= 1.5.9)
 | 
			
		||||
    mail (2.7.0)
 | 
			
		||||
      mini_mime (>= 0.1.1)
 | 
			
		||||
| 
						 | 
				
			
			@ -505,7 +507,7 @@ GEM
 | 
			
		|||
    multi_json (1.13.1)
 | 
			
		||||
    multi_xml (0.6.0)
 | 
			
		||||
    multipart-post (2.0.0)
 | 
			
		||||
    mustermann (1.0.0)
 | 
			
		||||
    mustermann (1.0.2)
 | 
			
		||||
    mustermann-grape (1.0.0)
 | 
			
		||||
      mustermann (~> 1.0.0)
 | 
			
		||||
    mysql2 (0.4.10)
 | 
			
		||||
| 
						 | 
				
			
			@ -515,7 +517,7 @@ GEM
 | 
			
		|||
    nokogiri (1.8.2)
 | 
			
		||||
      mini_portile2 (~> 2.3.0)
 | 
			
		||||
    numerizer (0.1.1)
 | 
			
		||||
    oauth (0.5.1)
 | 
			
		||||
    oauth (0.5.4)
 | 
			
		||||
    oauth2 (1.4.0)
 | 
			
		||||
      faraday (>= 0.8, < 0.13)
 | 
			
		||||
      jwt (~> 1.0)
 | 
			
		||||
| 
						 | 
				
			
			@ -527,8 +529,8 @@ GEM
 | 
			
		|||
    omniauth (1.8.1)
 | 
			
		||||
      hashie (>= 3.4.6, < 3.6.0)
 | 
			
		||||
      rack (>= 1.6.2, < 3)
 | 
			
		||||
    omniauth-auth0 (1.4.1)
 | 
			
		||||
      omniauth-oauth2 (~> 1.1)
 | 
			
		||||
    omniauth-auth0 (2.0.0)
 | 
			
		||||
      omniauth-oauth2 (~> 1.4)
 | 
			
		||||
    omniauth-authentiq (0.3.1)
 | 
			
		||||
      omniauth-oauth2 (~> 1.3, >= 1.3.1)
 | 
			
		||||
    omniauth-azure-oauth2 (0.0.9)
 | 
			
		||||
| 
						 | 
				
			
			@ -552,6 +554,9 @@ GEM
 | 
			
		|||
      multi_json (~> 1.3)
 | 
			
		||||
      omniauth (>= 1.1.1)
 | 
			
		||||
      omniauth-oauth2 (>= 1.3.1)
 | 
			
		||||
    omniauth-jwt (0.0.2)
 | 
			
		||||
      jwt
 | 
			
		||||
      omniauth (~> 1.1)
 | 
			
		||||
    omniauth-kerberos (0.3.0)
 | 
			
		||||
      omniauth-multipassword
 | 
			
		||||
      timfel-krb5-auth (~> 0.8)
 | 
			
		||||
| 
						 | 
				
			
			@ -570,9 +575,9 @@ GEM
 | 
			
		|||
      ruby-saml (~> 1.7)
 | 
			
		||||
    omniauth-shibboleth (1.2.1)
 | 
			
		||||
      omniauth (>= 1.0.0)
 | 
			
		||||
    omniauth-twitter (1.2.1)
 | 
			
		||||
      json (~> 1.3)
 | 
			
		||||
    omniauth-twitter (1.4.0)
 | 
			
		||||
      omniauth-oauth (~> 1.1)
 | 
			
		||||
      rack
 | 
			
		||||
    omniauth_crowd (2.2.3)
 | 
			
		||||
      activesupport
 | 
			
		||||
      nokogiri (>= 1.4.4)
 | 
			
		||||
| 
						 | 
				
			
			@ -679,8 +684,8 @@ GEM
 | 
			
		|||
      activesupport (>= 4.2.0, < 5.0)
 | 
			
		||||
      nokogiri (~> 1.6)
 | 
			
		||||
      rails-deprecated_sanitizer (>= 1.0.1)
 | 
			
		||||
    rails-html-sanitizer (1.0.3)
 | 
			
		||||
      loofah (~> 2.0)
 | 
			
		||||
    rails-html-sanitizer (1.0.4)
 | 
			
		||||
      loofah (~> 2.2, >= 2.2.2)
 | 
			
		||||
    rails-i18n (4.0.9)
 | 
			
		||||
      i18n (~> 0.7)
 | 
			
		||||
      railties (~> 4.0)
 | 
			
		||||
| 
						 | 
				
			
			@ -895,13 +900,13 @@ GEM
 | 
			
		|||
    sqlite3 (1.3.13)
 | 
			
		||||
    sshkey (1.9.0)
 | 
			
		||||
    stackprof (0.2.10)
 | 
			
		||||
    state_machines (0.4.0)
 | 
			
		||||
    state_machines-activemodel (0.4.0)
 | 
			
		||||
      activemodel (>= 4.1, < 5.1)
 | 
			
		||||
      state_machines (>= 0.4.0)
 | 
			
		||||
    state_machines-activerecord (0.4.0)
 | 
			
		||||
      activerecord (>= 4.1, < 5.1)
 | 
			
		||||
      state_machines-activemodel (>= 0.3.0)
 | 
			
		||||
    state_machines (0.5.0)
 | 
			
		||||
    state_machines-activemodel (0.5.1)
 | 
			
		||||
      activemodel (>= 4.1, < 6.0)
 | 
			
		||||
      state_machines (>= 0.5.0)
 | 
			
		||||
    state_machines-activerecord (0.5.1)
 | 
			
		||||
      activerecord (>= 4.1, < 6.0)
 | 
			
		||||
      state_machines-activemodel (>= 0.5.0)
 | 
			
		||||
    stringex (2.7.1)
 | 
			
		||||
    sys-filesystem (1.1.6)
 | 
			
		||||
      ffi
 | 
			
		||||
| 
						 | 
				
			
			@ -1093,7 +1098,7 @@ DEPENDENCIES
 | 
			
		|||
  license_finder (~> 3.1)
 | 
			
		||||
  licensee (~> 8.9)
 | 
			
		||||
  lograge (~> 0.5)
 | 
			
		||||
  loofah (~> 2.0.3)
 | 
			
		||||
  loofah (~> 2.2)
 | 
			
		||||
  mail_room (~> 0.9.1)
 | 
			
		||||
  method_source (~> 0.8)
 | 
			
		||||
  minitest (~> 5.7.0)
 | 
			
		||||
| 
						 | 
				
			
			@ -1105,7 +1110,7 @@ DEPENDENCIES
 | 
			
		|||
  oauth2 (~> 1.4)
 | 
			
		||||
  octokit (~> 4.8)
 | 
			
		||||
  omniauth (~> 1.8)
 | 
			
		||||
  omniauth-auth0 (~> 1.4.1)
 | 
			
		||||
  omniauth-auth0 (~> 2.0.0)
 | 
			
		||||
  omniauth-authentiq (~> 0.3.1)
 | 
			
		||||
  omniauth-azure-oauth2 (~> 0.0.9)
 | 
			
		||||
  omniauth-cas3 (~> 1.1.4)
 | 
			
		||||
| 
						 | 
				
			
			@ -1113,11 +1118,12 @@ DEPENDENCIES
 | 
			
		|||
  omniauth-github (~> 1.1.1)
 | 
			
		||||
  omniauth-gitlab (~> 1.0.2)
 | 
			
		||||
  omniauth-google-oauth2 (~> 0.5.2)
 | 
			
		||||
  omniauth-jwt (~> 0.0.2)
 | 
			
		||||
  omniauth-kerberos (~> 0.3.0)
 | 
			
		||||
  omniauth-oauth2-generic (~> 0.2.2)
 | 
			
		||||
  omniauth-saml (~> 1.10)
 | 
			
		||||
  omniauth-shibboleth (~> 1.2.0)
 | 
			
		||||
  omniauth-twitter (~> 1.2.0)
 | 
			
		||||
  omniauth-twitter (~> 1.4)
 | 
			
		||||
  omniauth_crowd (~> 2.2.0)
 | 
			
		||||
  org-ruby (~> 0.9.12)
 | 
			
		||||
  peek (~> 1.0.1)
 | 
			
		||||
| 
						 | 
				
			
			@ -1192,7 +1198,7 @@ DEPENDENCIES
 | 
			
		|||
  sprockets (~> 3.7.0)
 | 
			
		||||
  sshkey (~> 1.9.0)
 | 
			
		||||
  stackprof (~> 0.2.10)
 | 
			
		||||
  state_machines-activerecord (~> 0.4.0)
 | 
			
		||||
  state_machines-activerecord (~> 0.5.1)
 | 
			
		||||
  sys-filesystem (~> 1.1.6)
 | 
			
		||||
  test-prof (~> 0.2.5)
 | 
			
		||||
  test_after_commit (~> 1.1)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,8 +43,8 @@ GEM
 | 
			
		|||
      i18n (~> 0.7)
 | 
			
		||||
      minitest (~> 5.1)
 | 
			
		||||
      tzinfo (~> 1.1)
 | 
			
		||||
    acts-as-taggable-on (4.0.0)
 | 
			
		||||
      activerecord (>= 4.0)
 | 
			
		||||
    acts-as-taggable-on (5.0.0)
 | 
			
		||||
      activerecord (>= 4.2.8)
 | 
			
		||||
    adamantium (0.2.0)
 | 
			
		||||
      ice_nine (~> 0.11.0)
 | 
			
		||||
      memoizable (~> 0.4.0)
 | 
			
		||||
| 
						 | 
				
			
			@ -178,10 +178,10 @@ GEM
 | 
			
		|||
    docile (1.1.5)
 | 
			
		||||
    domain_name (0.5.20170404)
 | 
			
		||||
      unf (>= 0.0.5, < 1.0.0)
 | 
			
		||||
    doorkeeper (4.2.6)
 | 
			
		||||
    doorkeeper (4.3.1)
 | 
			
		||||
      railties (>= 4.2)
 | 
			
		||||
    doorkeeper-openid_connect (1.2.0)
 | 
			
		||||
      doorkeeper (~> 4.0)
 | 
			
		||||
    doorkeeper-openid_connect (1.3.0)
 | 
			
		||||
      doorkeeper (~> 4.3)
 | 
			
		||||
      json-jwt (~> 1.6)
 | 
			
		||||
    dropzonejs-rails (0.7.4)
 | 
			
		||||
      rails (> 3.1)
 | 
			
		||||
| 
						 | 
				
			
			@ -220,13 +220,13 @@ GEM
 | 
			
		|||
      path_expander (~> 1.0)
 | 
			
		||||
      ruby_parser (~> 3.0)
 | 
			
		||||
      sexp_processor (~> 4.0)
 | 
			
		||||
    flipper (0.11.0)
 | 
			
		||||
    flipper-active_record (0.11.0)
 | 
			
		||||
    flipper (0.13.0)
 | 
			
		||||
    flipper-active_record (0.13.0)
 | 
			
		||||
      activerecord (>= 3.2, < 6)
 | 
			
		||||
      flipper (~> 0.11.0)
 | 
			
		||||
    flipper-active_support_cache_store (0.11.0)
 | 
			
		||||
      flipper (~> 0.13.0)
 | 
			
		||||
    flipper-active_support_cache_store (0.13.0)
 | 
			
		||||
      activesupport (>= 3.2, < 6)
 | 
			
		||||
      flipper (~> 0.11.0)
 | 
			
		||||
      flipper (~> 0.13.0)
 | 
			
		||||
    flowdock (0.7.1)
 | 
			
		||||
      httparty (~> 0.7)
 | 
			
		||||
      multi_json
 | 
			
		||||
| 
						 | 
				
			
			@ -235,7 +235,7 @@ GEM
 | 
			
		|||
      fog-json (~> 1.0)
 | 
			
		||||
      ipaddress (~> 0.8)
 | 
			
		||||
      xml-simple (~> 1.1)
 | 
			
		||||
    fog-aws (1.4.1)
 | 
			
		||||
    fog-aws (2.0.1)
 | 
			
		||||
      fog-core (~> 1.38)
 | 
			
		||||
      fog-json (~> 1.0)
 | 
			
		||||
      fog-xml (~> 0.1)
 | 
			
		||||
| 
						 | 
				
			
			@ -267,7 +267,7 @@ GEM
 | 
			
		|||
      nokogiri (>= 1.5.11, < 2.0.0)
 | 
			
		||||
    font-awesome-rails (4.7.0.3)
 | 
			
		||||
      railties (>= 3.2, < 5.2)
 | 
			
		||||
    foreman (0.78.0)
 | 
			
		||||
    foreman (0.84.0)
 | 
			
		||||
      thor (~> 0.19.1)
 | 
			
		||||
    formatador (0.2.5)
 | 
			
		||||
    fuubar (2.2.0)
 | 
			
		||||
| 
						 | 
				
			
			@ -283,7 +283,7 @@ GEM
 | 
			
		|||
      text (>= 1.3.0)
 | 
			
		||||
    gettext_i18n_rails (1.8.0)
 | 
			
		||||
      fast_gettext (>= 0.9.0)
 | 
			
		||||
    gettext_i18n_rails_js (1.2.0)
 | 
			
		||||
    gettext_i18n_rails_js (1.3.0)
 | 
			
		||||
      gettext (>= 3.0.2)
 | 
			
		||||
      gettext_i18n_rails (>= 0.7.1)
 | 
			
		||||
      po_to_json (>= 1.0.0)
 | 
			
		||||
| 
						 | 
				
			
			@ -337,9 +337,9 @@ GEM
 | 
			
		|||
      json
 | 
			
		||||
      multi_json
 | 
			
		||||
      request_store (>= 1.0)
 | 
			
		||||
    google-api-client (0.13.6)
 | 
			
		||||
    google-api-client (0.19.8)
 | 
			
		||||
      addressable (~> 2.5, >= 2.5.1)
 | 
			
		||||
      googleauth (~> 0.5)
 | 
			
		||||
      googleauth (>= 0.5, < 0.7.0)
 | 
			
		||||
      httpclient (>= 2.8.1, < 3.0)
 | 
			
		||||
      mime-types (~> 3.0)
 | 
			
		||||
      representable (~> 3.0)
 | 
			
		||||
| 
						 | 
				
			
			@ -404,7 +404,7 @@ GEM
 | 
			
		|||
    html2text (0.2.1)
 | 
			
		||||
      nokogiri (~> 1.6)
 | 
			
		||||
    htmlentities (4.3.4)
 | 
			
		||||
    http (0.9.8)
 | 
			
		||||
    http (2.2.2)
 | 
			
		||||
      addressable (~> 2.3)
 | 
			
		||||
      http-cookie (~> 1.0)
 | 
			
		||||
      http-form_data (~> 1.0.1)
 | 
			
		||||
| 
						 | 
				
			
			@ -427,10 +427,6 @@ GEM
 | 
			
		|||
      multipart-post
 | 
			
		||||
      oauth (~> 0.5, >= 0.5.0)
 | 
			
		||||
    jquery-atwho-rails (1.3.2)
 | 
			
		||||
    jquery-rails (4.3.1)
 | 
			
		||||
      rails-dom-testing (>= 1, < 3)
 | 
			
		||||
      railties (>= 4.2.0)
 | 
			
		||||
      thor (>= 0.14, < 2.0)
 | 
			
		||||
    json (1.8.6)
 | 
			
		||||
    json-jwt (1.9.2)
 | 
			
		||||
      activesupport
 | 
			
		||||
| 
						 | 
				
			
			@ -454,13 +450,12 @@ GEM
 | 
			
		|||
      kaminari-core (= 1.1.1)
 | 
			
		||||
    kaminari-core (1.1.1)
 | 
			
		||||
    kgio (2.11.2)
 | 
			
		||||
    knapsack (1.11.1)
 | 
			
		||||
    knapsack (1.16.0)
 | 
			
		||||
      rake
 | 
			
		||||
      timecop (>= 0.1.0)
 | 
			
		||||
    kubeclient (2.2.0)
 | 
			
		||||
      http (= 0.9.8)
 | 
			
		||||
      recursive-open-struct (= 1.0.0)
 | 
			
		||||
      rest-client
 | 
			
		||||
    kubeclient (3.0.0)
 | 
			
		||||
      http (~> 2.2.2)
 | 
			
		||||
      recursive-open-struct (~> 1.0.4)
 | 
			
		||||
      rest-client (~> 2.0)
 | 
			
		||||
    launchy (2.4.3)
 | 
			
		||||
      addressable (~> 2.3)
 | 
			
		||||
    letter_opener (1.6.0)
 | 
			
		||||
| 
						 | 
				
			
			@ -477,7 +472,7 @@ GEM
 | 
			
		|||
      toml (= 0.1.2)
 | 
			
		||||
      with_env (> 1.0)
 | 
			
		||||
      xml-simple
 | 
			
		||||
    licensee (8.7.0)
 | 
			
		||||
    licensee (8.9.2)
 | 
			
		||||
      rugged (~> 0.24)
 | 
			
		||||
    little-plugger (1.1.4)
 | 
			
		||||
    locale (2.1.2)
 | 
			
		||||
| 
						 | 
				
			
			@ -514,7 +509,7 @@ GEM
 | 
			
		|||
      mustermann (~> 1.0.0)
 | 
			
		||||
    mysql2 (0.4.10)
 | 
			
		||||
    net-ldap (0.16.1)
 | 
			
		||||
    net-ssh (4.1.0)
 | 
			
		||||
    net-ssh (4.2.0)
 | 
			
		||||
    netrc (0.11.0)
 | 
			
		||||
    nio4r (2.2.0)
 | 
			
		||||
    nokogiri (1.8.2)
 | 
			
		||||
| 
						 | 
				
			
			@ -527,11 +522,10 @@ GEM
 | 
			
		|||
      multi_json (~> 1.3)
 | 
			
		||||
      multi_xml (~> 0.5)
 | 
			
		||||
      rack (>= 1.2, < 3)
 | 
			
		||||
    octokit (4.6.2)
 | 
			
		||||
    octokit (4.8.0)
 | 
			
		||||
      sawyer (~> 0.8.0, >= 0.5.3)
 | 
			
		||||
    oj (2.17.5)
 | 
			
		||||
    omniauth (1.4.3)
 | 
			
		||||
      hashie (>= 1.2, < 4)
 | 
			
		||||
    omniauth (1.8.1)
 | 
			
		||||
      hashie (>= 3.4.6, < 3.6.0)
 | 
			
		||||
      rack (>= 1.6.2, < 3)
 | 
			
		||||
    omniauth-auth0 (1.4.2)
 | 
			
		||||
      omniauth-oauth2 (~> 1.1)
 | 
			
		||||
| 
						 | 
				
			
			@ -570,9 +564,9 @@ GEM
 | 
			
		|||
      omniauth (~> 1.2)
 | 
			
		||||
    omniauth-oauth2-generic (0.2.4)
 | 
			
		||||
      omniauth-oauth2 (~> 1.0)
 | 
			
		||||
    omniauth-saml (1.7.0)
 | 
			
		||||
      omniauth (~> 1.3)
 | 
			
		||||
      ruby-saml (~> 1.4)
 | 
			
		||||
    omniauth-saml (1.10.0)
 | 
			
		||||
      omniauth (~> 1.3, >= 1.3.2)
 | 
			
		||||
      ruby-saml (~> 1.7)
 | 
			
		||||
    omniauth-shibboleth (1.2.1)
 | 
			
		||||
      omniauth (>= 1.0.0)
 | 
			
		||||
    omniauth-twitter (1.2.1)
 | 
			
		||||
| 
						 | 
				
			
			@ -598,8 +592,6 @@ GEM
 | 
			
		|||
      railties (>= 4.0.0)
 | 
			
		||||
    peek-gc (0.0.2)
 | 
			
		||||
      peek
 | 
			
		||||
    peek-host (1.0.0)
 | 
			
		||||
      peek
 | 
			
		||||
    peek-mysql2 (1.1.0)
 | 
			
		||||
      atomic (>= 1.0.0)
 | 
			
		||||
      mysql2
 | 
			
		||||
| 
						 | 
				
			
			@ -713,7 +705,7 @@ GEM
 | 
			
		|||
    re2 (1.1.1)
 | 
			
		||||
    recaptcha (3.4.0)
 | 
			
		||||
      json
 | 
			
		||||
    recursive-open-struct (1.0.0)
 | 
			
		||||
    recursive-open-struct (1.0.5)
 | 
			
		||||
    redcarpet (3.4.0)
 | 
			
		||||
    redis (3.3.5)
 | 
			
		||||
    redis-actionpack (5.0.2)
 | 
			
		||||
| 
						 | 
				
			
			@ -805,7 +797,7 @@ GEM
 | 
			
		|||
      i18n
 | 
			
		||||
    ruby-fogbugz (0.2.1)
 | 
			
		||||
      crack (~> 0.4)
 | 
			
		||||
    ruby-prof (0.16.2)
 | 
			
		||||
    ruby-prof (0.17.0)
 | 
			
		||||
    ruby-progressbar (1.9.0)
 | 
			
		||||
    ruby-saml (1.7.2)
 | 
			
		||||
      nokogiri (>= 1.5.10)
 | 
			
		||||
| 
						 | 
				
			
			@ -846,7 +838,7 @@ GEM
 | 
			
		|||
    selenium-webdriver (3.11.0)
 | 
			
		||||
      childprocess (~> 0.5)
 | 
			
		||||
      rubyzip (~> 1.2)
 | 
			
		||||
    sentry-raven (2.5.3)
 | 
			
		||||
    sentry-raven (2.7.2)
 | 
			
		||||
      faraday (>= 0.7.6, < 1.0)
 | 
			
		||||
    settingslogic (2.0.9)
 | 
			
		||||
    sexp_processor (4.10.1)
 | 
			
		||||
| 
						 | 
				
			
			@ -903,12 +895,12 @@ GEM
 | 
			
		|||
    sshkey (1.9.0)
 | 
			
		||||
    stackprof (0.2.11)
 | 
			
		||||
    state_machines (0.5.0)
 | 
			
		||||
    state_machines-activemodel (0.5.0)
 | 
			
		||||
      activemodel (>= 4.1, < 5.2)
 | 
			
		||||
    state_machines-activemodel (0.5.1)
 | 
			
		||||
      activemodel (>= 4.1, < 6.0)
 | 
			
		||||
      state_machines (>= 0.5.0)
 | 
			
		||||
    state_machines-activerecord (0.4.1)
 | 
			
		||||
      activerecord (>= 4.1, < 5.2)
 | 
			
		||||
      state_machines-activemodel (>= 0.3.0)
 | 
			
		||||
    state_machines-activerecord (0.5.1)
 | 
			
		||||
      activerecord (>= 4.1, < 6.0)
 | 
			
		||||
      state_machines-activemodel (>= 0.5.0)
 | 
			
		||||
    stringex (2.8.4)
 | 
			
		||||
    sys-filesystem (1.1.9)
 | 
			
		||||
      ffi
 | 
			
		||||
| 
						 | 
				
			
			@ -998,7 +990,7 @@ DEPENDENCIES
 | 
			
		|||
  RedCloth (~> 4.3.2)
 | 
			
		||||
  ace-rails-ap (~> 4.1.0)
 | 
			
		||||
  activerecord_sane_schema_dumper (= 1.0)
 | 
			
		||||
  acts-as-taggable-on (~> 4.0)
 | 
			
		||||
  acts-as-taggable-on (~> 5.0)
 | 
			
		||||
  addressable (~> 2.5.2)
 | 
			
		||||
  akismet (~> 2.0)
 | 
			
		||||
  allocations (~> 1.0)
 | 
			
		||||
| 
						 | 
				
			
			@ -1038,8 +1030,8 @@ DEPENDENCIES
 | 
			
		|||
  devise (~> 4.2)
 | 
			
		||||
  devise-two-factor (~> 3.0.0)
 | 
			
		||||
  diffy (~> 3.1.0)
 | 
			
		||||
  doorkeeper (~> 4.2.0)
 | 
			
		||||
  doorkeeper-openid_connect (~> 1.2.0)
 | 
			
		||||
  doorkeeper (~> 4.3)
 | 
			
		||||
  doorkeeper-openid_connect (~> 1.3)
 | 
			
		||||
  dropzonejs-rails (~> 0.7.1)
 | 
			
		||||
  email_reply_trimmer (~> 0.1)
 | 
			
		||||
  email_spec (~> 1.6.0)
 | 
			
		||||
| 
						 | 
				
			
			@ -1048,24 +1040,24 @@ DEPENDENCIES
 | 
			
		|||
  fast_blank
 | 
			
		||||
  ffaker (~> 2.4)
 | 
			
		||||
  flay (~> 2.10.0)
 | 
			
		||||
  flipper (~> 0.11.0)
 | 
			
		||||
  flipper-active_record (~> 0.11.0)
 | 
			
		||||
  flipper-active_support_cache_store (~> 0.11.0)
 | 
			
		||||
  flipper (~> 0.13.0)
 | 
			
		||||
  flipper-active_record (~> 0.13.0)
 | 
			
		||||
  flipper-active_support_cache_store (~> 0.13.0)
 | 
			
		||||
  fog-aliyun (~> 0.2.0)
 | 
			
		||||
  fog-aws (~> 1.4)
 | 
			
		||||
  fog-aws (~> 2.0)
 | 
			
		||||
  fog-core (~> 1.44)
 | 
			
		||||
  fog-google (~> 0.5)
 | 
			
		||||
  fog-local (~> 0.3)
 | 
			
		||||
  fog-openstack (~> 0.1)
 | 
			
		||||
  fog-rackspace (~> 0.1.1)
 | 
			
		||||
  font-awesome-rails (~> 4.7)
 | 
			
		||||
  foreman (~> 0.78.0)
 | 
			
		||||
  foreman (~> 0.84.0)
 | 
			
		||||
  fuubar (~> 2.2.0)
 | 
			
		||||
  gemnasium-gitlab-service (~> 0.2)
 | 
			
		||||
  gemojione (~> 3.3)
 | 
			
		||||
  gettext (~> 3.2.2)
 | 
			
		||||
  gettext_i18n_rails (~> 1.8.0)
 | 
			
		||||
  gettext_i18n_rails_js (~> 1.2.0)
 | 
			
		||||
  gettext_i18n_rails_js (~> 1.3)
 | 
			
		||||
  gitaly-proto (~> 0.88.0)
 | 
			
		||||
  github-linguist (~> 5.3.3)
 | 
			
		||||
  gitlab-flowdock-git-hook (~> 1.0.1)
 | 
			
		||||
| 
						 | 
				
			
			@ -1075,7 +1067,7 @@ DEPENDENCIES
 | 
			
		|||
  gollum-lib (~> 4.2)
 | 
			
		||||
  gollum-rugged_adapter (~> 0.4.4)
 | 
			
		||||
  gon (~> 6.1.0)
 | 
			
		||||
  google-api-client (~> 0.13.6)
 | 
			
		||||
  google-api-client (~> 0.19.8)
 | 
			
		||||
  google-protobuf (= 3.5.1)
 | 
			
		||||
  gpgme
 | 
			
		||||
  grape (~> 1.0)
 | 
			
		||||
| 
						 | 
				
			
			@ -1094,15 +1086,14 @@ DEPENDENCIES
 | 
			
		|||
  influxdb (~> 0.2)
 | 
			
		||||
  jira-ruby (~> 1.4)
 | 
			
		||||
  jquery-atwho-rails (~> 1.3.2)
 | 
			
		||||
  jquery-rails (~> 4.3.1)
 | 
			
		||||
  json-schema (~> 2.8.0)
 | 
			
		||||
  jwt (~> 1.5.6)
 | 
			
		||||
  kaminari (~> 1.0)
 | 
			
		||||
  knapsack (~> 1.11.0)
 | 
			
		||||
  kubeclient (~> 2.2.0)
 | 
			
		||||
  knapsack (~> 1.16)
 | 
			
		||||
  kubeclient (~> 3.0)
 | 
			
		||||
  letter_opener_web (~> 1.3.0)
 | 
			
		||||
  license_finder (~> 3.1)
 | 
			
		||||
  licensee (~> 8.7.0)
 | 
			
		||||
  licensee (~> 8.9)
 | 
			
		||||
  lograge (~> 0.5)
 | 
			
		||||
  loofah (~> 2.0.3)
 | 
			
		||||
  mail_room (~> 0.9.1)
 | 
			
		||||
| 
						 | 
				
			
			@ -1111,12 +1102,11 @@ DEPENDENCIES
 | 
			
		|||
  mousetrap-rails (~> 1.4.6)
 | 
			
		||||
  mysql2 (~> 0.4.10)
 | 
			
		||||
  net-ldap
 | 
			
		||||
  net-ssh (~> 4.1.0)
 | 
			
		||||
  net-ssh (~> 4.2.0)
 | 
			
		||||
  nokogiri (~> 1.8.2)
 | 
			
		||||
  oauth2 (~> 1.4)
 | 
			
		||||
  octokit (~> 4.6.2)
 | 
			
		||||
  oj (~> 2.17.4)
 | 
			
		||||
  omniauth (~> 1.4.2)
 | 
			
		||||
  octokit (~> 4.8)
 | 
			
		||||
  omniauth (~> 1.8)
 | 
			
		||||
  omniauth-auth0 (~> 1.4.1)
 | 
			
		||||
  omniauth-authentiq (~> 0.3.1)
 | 
			
		||||
  omniauth-azure-oauth2 (~> 0.0.9)
 | 
			
		||||
| 
						 | 
				
			
			@ -1127,14 +1117,13 @@ DEPENDENCIES
 | 
			
		|||
  omniauth-google-oauth2 (~> 0.5.2)
 | 
			
		||||
  omniauth-kerberos (~> 0.3.0)
 | 
			
		||||
  omniauth-oauth2-generic (~> 0.2.2)
 | 
			
		||||
  omniauth-saml (~> 1.7.0)
 | 
			
		||||
  omniauth-saml (~> 1.10)
 | 
			
		||||
  omniauth-shibboleth (~> 1.2.0)
 | 
			
		||||
  omniauth-twitter (~> 1.2.0)
 | 
			
		||||
  omniauth_crowd (~> 2.2.0)
 | 
			
		||||
  org-ruby (~> 0.9.12)
 | 
			
		||||
  peek (~> 1.0.1)
 | 
			
		||||
  peek-gc (~> 0.0.2)
 | 
			
		||||
  peek-host (~> 1.0.0)
 | 
			
		||||
  peek-mysql2 (~> 1.1.0)
 | 
			
		||||
  peek-performance_bar (~> 1.3.0)
 | 
			
		||||
  peek-pg (~> 1.3.0)
 | 
			
		||||
| 
						 | 
				
			
			@ -1177,7 +1166,7 @@ DEPENDENCIES
 | 
			
		|||
  rubocop (~> 0.52.1)
 | 
			
		||||
  rubocop-rspec (~> 1.22.1)
 | 
			
		||||
  ruby-fogbugz (~> 0.2.1)
 | 
			
		||||
  ruby-prof (~> 0.16.2)
 | 
			
		||||
  ruby-prof (~> 0.17.0)
 | 
			
		||||
  ruby_parser (~> 3.8)
 | 
			
		||||
  rufus-scheduler (~> 3.4)
 | 
			
		||||
  rugged (~> 0.26.0)
 | 
			
		||||
| 
						 | 
				
			
			@ -1187,7 +1176,7 @@ DEPENDENCIES
 | 
			
		|||
  seed-fu (~> 2.3.7)
 | 
			
		||||
  select2-rails (~> 3.5.9)
 | 
			
		||||
  selenium-webdriver (~> 3.5)
 | 
			
		||||
  sentry-raven (~> 2.5.3)
 | 
			
		||||
  sentry-raven (~> 2.7)
 | 
			
		||||
  settingslogic (~> 2.0.9)
 | 
			
		||||
  sham_rack (~> 1.3.6)
 | 
			
		||||
  shoulda-matchers (~> 3.1.2)
 | 
			
		||||
| 
						 | 
				
			
			@ -1205,7 +1194,7 @@ DEPENDENCIES
 | 
			
		|||
  sprockets (~> 3.7.0)
 | 
			
		||||
  sshkey (~> 1.9.0)
 | 
			
		||||
  stackprof (~> 0.2.10)
 | 
			
		||||
  state_machines-activerecord (~> 0.4.0)
 | 
			
		||||
  state_machines-activerecord (~> 0.5.1)
 | 
			
		||||
  sys-filesystem (~> 1.1.6)
 | 
			
		||||
  test-prof (~> 0.2.5)
 | 
			
		||||
  test_after_commit (~> 1.1)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
import $ from 'jquery';
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
 | 
			
		||||
import UserAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
 | 
			
		||||
import eventHub from '../eventhub';
 | 
			
		||||
 | 
			
		||||
const Store = gl.issueBoards.BoardsStore;
 | 
			
		||||
| 
						 | 
				
			
			@ -45,7 +45,7 @@ gl.issueBoards.IssueCardInner = Vue.extend({
 | 
			
		|||
    };
 | 
			
		||||
  },
 | 
			
		||||
  components: {
 | 
			
		||||
    userAvatarLink,
 | 
			
		||||
    UserAvatarLink,
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    numberOverLimit() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,7 +33,7 @@ export default class VariableList {
 | 
			
		|||
        selector: '.js-ci-variable-input-key',
 | 
			
		||||
        default: '',
 | 
			
		||||
      },
 | 
			
		||||
      value: {
 | 
			
		||||
      secret_value: {
 | 
			
		||||
        selector: '.js-ci-variable-input-value',
 | 
			
		||||
        default: '',
 | 
			
		||||
      },
 | 
			
		||||
| 
						 | 
				
			
			@ -105,7 +105,7 @@ export default class VariableList {
 | 
			
		|||
    setupToggleButtons($row[0]);
 | 
			
		||||
 | 
			
		||||
    // Reset the resizable textarea
 | 
			
		||||
    $row.find(this.inputMap.value.selector).css('height', '');
 | 
			
		||||
    $row.find(this.inputMap.secret_value.selector).css('height', '');
 | 
			
		||||
 | 
			
		||||
    const $environmentSelect = $row.find('.js-variable-environment-toggle');
 | 
			
		||||
    if ($environmentSelect.length) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
// ECMAScript polyfills
 | 
			
		||||
import 'core-js/fn/array/fill';
 | 
			
		||||
import 'core-js/fn/array/find';
 | 
			
		||||
import 'core-js/fn/array/find-index';
 | 
			
		||||
import 'core-js/fn/array/from';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,7 @@
 | 
			
		|||
import $ from 'jquery';
 | 
			
		||||
import { s__ } from '~/locale';
 | 
			
		||||
import loadingIcon from '~/vue_shared/components/loading_icon.vue';
 | 
			
		||||
import modal from '~/vue_shared/components/modal.vue';
 | 
			
		||||
import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
 | 
			
		||||
import { getParameterByName } from '~/lib/utils/common_utils';
 | 
			
		||||
import { mergeUrlParams } from '~/lib/utils/url_utility';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -15,7 +15,7 @@ import groupsComponent from './groups.vue';
 | 
			
		|||
export default {
 | 
			
		||||
  components: {
 | 
			
		||||
    loadingIcon,
 | 
			
		||||
    modal,
 | 
			
		||||
    DeprecatedModal,
 | 
			
		||||
    groupsComponent,
 | 
			
		||||
  },
 | 
			
		||||
  props: {
 | 
			
		||||
| 
						 | 
				
			
			@ -52,8 +52,9 @@ export default {
 | 
			
		|||
    },
 | 
			
		||||
  },
 | 
			
		||||
  created() {
 | 
			
		||||
    this.searchEmptyMessage = this.hideProjects ?
 | 
			
		||||
      COMMON_STR.GROUP_SEARCH_EMPTY : COMMON_STR.GROUP_PROJECT_SEARCH_EMPTY;
 | 
			
		||||
    this.searchEmptyMessage = this.hideProjects
 | 
			
		||||
      ? COMMON_STR.GROUP_SEARCH_EMPTY
 | 
			
		||||
      : COMMON_STR.GROUP_PROJECT_SEARCH_EMPTY;
 | 
			
		||||
 | 
			
		||||
    eventHub.$on('fetchPage', this.fetchPage);
 | 
			
		||||
    eventHub.$on('toggleChildren', this.toggleChildren);
 | 
			
		||||
| 
						 | 
				
			
			@ -72,22 +73,30 @@ export default {
 | 
			
		|||
    eventHub.$off('updateGroups', this.updateGroups);
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    fetchGroups({ parentId, page, filterGroupsBy, sortBy, archived, updatePagination }) {
 | 
			
		||||
      return this.service.getGroups(parentId, page, filterGroupsBy, sortBy, archived)
 | 
			
		||||
                .then((res) => {
 | 
			
		||||
                  if (updatePagination) {
 | 
			
		||||
                    this.updatePagination(res.headers);
 | 
			
		||||
                  }
 | 
			
		||||
    fetchGroups({
 | 
			
		||||
      parentId,
 | 
			
		||||
      page,
 | 
			
		||||
      filterGroupsBy,
 | 
			
		||||
      sortBy,
 | 
			
		||||
      archived,
 | 
			
		||||
      updatePagination,
 | 
			
		||||
    }) {
 | 
			
		||||
      return this.service
 | 
			
		||||
        .getGroups(parentId, page, filterGroupsBy, sortBy, archived)
 | 
			
		||||
        .then(res => {
 | 
			
		||||
          if (updatePagination) {
 | 
			
		||||
            this.updatePagination(res.headers);
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
                  return res;
 | 
			
		||||
                })
 | 
			
		||||
                .then(res => res.json())
 | 
			
		||||
                .catch(() => {
 | 
			
		||||
                  this.isLoading = false;
 | 
			
		||||
                  $.scrollTo(0);
 | 
			
		||||
          return res;
 | 
			
		||||
        })
 | 
			
		||||
        .then(res => res.json())
 | 
			
		||||
        .catch(() => {
 | 
			
		||||
          this.isLoading = false;
 | 
			
		||||
          $.scrollTo(0);
 | 
			
		||||
 | 
			
		||||
                  Flash(COMMON_STR.FAILURE);
 | 
			
		||||
                });
 | 
			
		||||
          Flash(COMMON_STR.FAILURE);
 | 
			
		||||
        });
 | 
			
		||||
    },
 | 
			
		||||
    fetchAllGroups() {
 | 
			
		||||
      const page = getParameterByName('page') || null;
 | 
			
		||||
| 
						 | 
				
			
			@ -103,7 +112,7 @@ export default {
 | 
			
		|||
        sortBy,
 | 
			
		||||
        archived,
 | 
			
		||||
        updatePagination: true,
 | 
			
		||||
      }).then((res) => {
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        this.isLoading = false;
 | 
			
		||||
        this.updateGroups(res, Boolean(filterGroupsBy));
 | 
			
		||||
      });
 | 
			
		||||
| 
						 | 
				
			
			@ -118,14 +127,18 @@ export default {
 | 
			
		|||
        sortBy,
 | 
			
		||||
        archived,
 | 
			
		||||
        updatePagination: true,
 | 
			
		||||
      }).then((res) => {
 | 
			
		||||
      }).then(res => {
 | 
			
		||||
        this.isLoading = false;
 | 
			
		||||
        $.scrollTo(0);
 | 
			
		||||
 | 
			
		||||
        const currentPath = mergeUrlParams({ page }, window.location.href);
 | 
			
		||||
        window.history.replaceState({
 | 
			
		||||
          page: currentPath,
 | 
			
		||||
        }, document.title, currentPath);
 | 
			
		||||
        window.history.replaceState(
 | 
			
		||||
          {
 | 
			
		||||
            page: currentPath,
 | 
			
		||||
          },
 | 
			
		||||
          document.title,
 | 
			
		||||
          currentPath,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        this.updateGroups(res);
 | 
			
		||||
      });
 | 
			
		||||
| 
						 | 
				
			
			@ -138,11 +151,13 @@ export default {
 | 
			
		|||
          // eslint-disable-next-line promise/catch-or-return
 | 
			
		||||
          this.fetchGroups({
 | 
			
		||||
            parentId: parentGroup.id,
 | 
			
		||||
          }).then((res) => {
 | 
			
		||||
            this.store.setGroupChildren(parentGroup, res);
 | 
			
		||||
          }).catch(() => {
 | 
			
		||||
            parentGroup.isChildrenLoading = false;
 | 
			
		||||
          });
 | 
			
		||||
          })
 | 
			
		||||
            .then(res => {
 | 
			
		||||
              this.store.setGroupChildren(parentGroup, res);
 | 
			
		||||
            })
 | 
			
		||||
            .catch(() => {
 | 
			
		||||
              parentGroup.isChildrenLoading = false;
 | 
			
		||||
            });
 | 
			
		||||
        } else {
 | 
			
		||||
          parentGroup.isOpen = true;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -154,7 +169,11 @@ export default {
 | 
			
		|||
      this.targetGroup = group;
 | 
			
		||||
      this.targetParentGroup = parentGroup;
 | 
			
		||||
      this.showModal = true;
 | 
			
		||||
      this.groupLeaveConfirmationMessage = s__(`GroupsTree|Are you sure you want to leave the "${group.fullName}" group?`);
 | 
			
		||||
      this.groupLeaveConfirmationMessage = s__(
 | 
			
		||||
        `GroupsTree|Are you sure you want to leave the "${
 | 
			
		||||
          group.fullName
 | 
			
		||||
        }" group?`,
 | 
			
		||||
      );
 | 
			
		||||
    },
 | 
			
		||||
    hideLeaveGroupModal() {
 | 
			
		||||
      this.showModal = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -162,14 +181,15 @@ export default {
 | 
			
		|||
    leaveGroup() {
 | 
			
		||||
      this.showModal = false;
 | 
			
		||||
      this.targetGroup.isBeingRemoved = true;
 | 
			
		||||
      this.service.leaveGroup(this.targetGroup.leavePath)
 | 
			
		||||
      this.service
 | 
			
		||||
        .leaveGroup(this.targetGroup.leavePath)
 | 
			
		||||
        .then(res => res.json())
 | 
			
		||||
        .then((res) => {
 | 
			
		||||
        .then(res => {
 | 
			
		||||
          $.scrollTo(0);
 | 
			
		||||
          this.store.removeGroup(this.targetGroup, this.targetParentGroup);
 | 
			
		||||
          Flash(res.notice, 'notice');
 | 
			
		||||
        })
 | 
			
		||||
        .catch((err) => {
 | 
			
		||||
        .catch(err => {
 | 
			
		||||
          let message = COMMON_STR.FAILURE;
 | 
			
		||||
          if (err.status === 403) {
 | 
			
		||||
            message = COMMON_STR.LEAVE_FORBIDDEN;
 | 
			
		||||
| 
						 | 
				
			
			@ -208,8 +228,8 @@ export default {
 | 
			
		|||
      :search-empty-message="searchEmptyMessage"
 | 
			
		||||
      :page-info="pageInfo"
 | 
			
		||||
    />
 | 
			
		||||
    <modal
 | 
			
		||||
      v-if="showModal"
 | 
			
		||||
    <deprecated-modal
 | 
			
		||||
      v-show="showModal"
 | 
			
		||||
      kind="warning"
 | 
			
		||||
      :primary-button-label="__('Leave')"
 | 
			
		||||
      :title="__('Are you sure?')"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,75 +1,75 @@
 | 
			
		|||
<script>
 | 
			
		||||
  import { __ } from '~/locale';
 | 
			
		||||
  import modal from '~/vue_shared/components/modal.vue';
 | 
			
		||||
import { __ } from '~/locale';
 | 
			
		||||
import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    components: {
 | 
			
		||||
      modal,
 | 
			
		||||
export default {
 | 
			
		||||
  components: {
 | 
			
		||||
    DeprecatedModal,
 | 
			
		||||
  },
 | 
			
		||||
  props: {
 | 
			
		||||
    branchId: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      required: true,
 | 
			
		||||
    },
 | 
			
		||||
    props: {
 | 
			
		||||
      branchId: {
 | 
			
		||||
        type: String,
 | 
			
		||||
        required: true,
 | 
			
		||||
      },
 | 
			
		||||
      type: {
 | 
			
		||||
        type: String,
 | 
			
		||||
        required: true,
 | 
			
		||||
      },
 | 
			
		||||
      path: {
 | 
			
		||||
        type: String,
 | 
			
		||||
        required: true,
 | 
			
		||||
      },
 | 
			
		||||
    type: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      required: true,
 | 
			
		||||
    },
 | 
			
		||||
    data() {
 | 
			
		||||
      return {
 | 
			
		||||
        entryName: this.path !== '' ? `${this.path}/` : '',
 | 
			
		||||
      };
 | 
			
		||||
    path: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      required: true,
 | 
			
		||||
    },
 | 
			
		||||
    computed: {
 | 
			
		||||
      modalTitle() {
 | 
			
		||||
        if (this.type === 'tree') {
 | 
			
		||||
          return __('Create new directory');
 | 
			
		||||
        }
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      entryName: this.path !== '' ? `${this.path}/` : '',
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    modalTitle() {
 | 
			
		||||
      if (this.type === 'tree') {
 | 
			
		||||
        return __('Create new directory');
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
        return __('Create new file');
 | 
			
		||||
      },
 | 
			
		||||
      buttonLabel() {
 | 
			
		||||
        if (this.type === 'tree') {
 | 
			
		||||
          return __('Create directory');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return __('Create file');
 | 
			
		||||
      },
 | 
			
		||||
      formLabelName() {
 | 
			
		||||
        if (this.type === 'tree') {
 | 
			
		||||
          return __('Directory name');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return __('File name');
 | 
			
		||||
      },
 | 
			
		||||
      return __('Create new file');
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
      this.$refs.fieldName.focus();
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
      createEntryInStore() {
 | 
			
		||||
        this.$emit('create', {
 | 
			
		||||
          branchId: this.branchId,
 | 
			
		||||
          name: this.entryName,
 | 
			
		||||
          type: this.type,
 | 
			
		||||
        });
 | 
			
		||||
    buttonLabel() {
 | 
			
		||||
      if (this.type === 'tree') {
 | 
			
		||||
        return __('Create directory');
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
        this.hideModal();
 | 
			
		||||
      },
 | 
			
		||||
      hideModal() {
 | 
			
		||||
        this.$emit('hide');
 | 
			
		||||
      },
 | 
			
		||||
      return __('Create file');
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
    formLabelName() {
 | 
			
		||||
      if (this.type === 'tree') {
 | 
			
		||||
        return __('Directory name');
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return __('File name');
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  mounted() {
 | 
			
		||||
    this.$refs.fieldName.focus();
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    createEntryInStore() {
 | 
			
		||||
      this.$emit('create', {
 | 
			
		||||
        branchId: this.branchId,
 | 
			
		||||
        name: this.entryName,
 | 
			
		||||
        type: this.type,
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      this.hideModal();
 | 
			
		||||
    },
 | 
			
		||||
    hideModal() {
 | 
			
		||||
      this.$emit('hide');
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <modal
 | 
			
		||||
  <deprecated-modal
 | 
			
		||||
    :title="modalTitle"
 | 
			
		||||
    :primary-button-label="buttonLabel"
 | 
			
		||||
    kind="success"
 | 
			
		||||
| 
						 | 
				
			
			@ -95,5 +95,5 @@
 | 
			
		|||
        </div>
 | 
			
		||||
      </fieldset>
 | 
			
		||||
    </form>
 | 
			
		||||
  </modal>
 | 
			
		||||
  </deprecated-modal>
 | 
			
		||||
</template>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
import { mapState, mapActions, mapGetters } from 'vuex';
 | 
			
		||||
import tooltip from '~/vue_shared/directives/tooltip';
 | 
			
		||||
import icon from '~/vue_shared/components/icon.vue';
 | 
			
		||||
import modal from '~/vue_shared/components/modal.vue';
 | 
			
		||||
import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
 | 
			
		||||
import LoadingButton from '~/vue_shared/components/loading_button.vue';
 | 
			
		||||
import commitFilesList from './commit_sidebar/list.vue';
 | 
			
		||||
import EmptyState from './commit_sidebar/empty_state.vue';
 | 
			
		||||
| 
						 | 
				
			
			@ -11,7 +11,7 @@ import * as consts from '../stores/modules/commit/constants';
 | 
			
		|||
 | 
			
		||||
export default {
 | 
			
		||||
  components: {
 | 
			
		||||
    modal,
 | 
			
		||||
    DeprecatedModal,
 | 
			
		||||
    icon,
 | 
			
		||||
    commitFilesList,
 | 
			
		||||
    EmptyState,
 | 
			
		||||
| 
						 | 
				
			
			@ -34,11 +34,7 @@ export default {
 | 
			
		|||
  computed: {
 | 
			
		||||
    ...mapState(['changedFiles', 'stagedFiles', 'rightPanelCollapsed']),
 | 
			
		||||
    ...mapState('commit', ['commitMessage', 'submitCommitLoading']),
 | 
			
		||||
    ...mapGetters('commit', [
 | 
			
		||||
      'commitButtonDisabled',
 | 
			
		||||
      'discardDraftButtonDisabled',
 | 
			
		||||
      'branchName',
 | 
			
		||||
    ]),
 | 
			
		||||
    ...mapGetters('commit', ['commitButtonDisabled', 'discardDraftButtonDisabled', 'branchName']),
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    ...mapActions('commit', [
 | 
			
		||||
| 
						 | 
				
			
			@ -48,9 +44,7 @@ export default {
 | 
			
		|||
      'updateCommitAction',
 | 
			
		||||
    ]),
 | 
			
		||||
    forceCreateNewBranch() {
 | 
			
		||||
      return this.updateCommitAction(consts.COMMIT_TO_NEW_BRANCH).then(() =>
 | 
			
		||||
        this.commitChanges(),
 | 
			
		||||
      );
 | 
			
		||||
      return this.updateCommitAction(consts.COMMIT_TO_NEW_BRANCH).then(() => this.commitChanges());
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -60,7 +54,7 @@ export default {
 | 
			
		|||
  <div
 | 
			
		||||
    class="multi-file-commit-panel-section"
 | 
			
		||||
  >
 | 
			
		||||
    <modal
 | 
			
		||||
    <deprecated-modal
 | 
			
		||||
      id="ide-create-branch-modal"
 | 
			
		||||
      :primary-button-label="__('Create new branch')"
 | 
			
		||||
      kind="success"
 | 
			
		||||
| 
						 | 
				
			
			@ -71,7 +65,7 @@ export default {
 | 
			
		|||
        {{ __(`This branch has changed since you started editing.
 | 
			
		||||
          Would you like to create a new branch?`) }}
 | 
			
		||||
      </template>
 | 
			
		||||
    </modal>
 | 
			
		||||
    </deprecated-modal>
 | 
			
		||||
    <template
 | 
			
		||||
      v-if="changedFiles.length || stagedFiles.length"
 | 
			
		||||
    >
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -65,6 +65,10 @@ export default class Editor {
 | 
			
		|||
        (this.instance = this.monaco.editor.createDiffEditor(domElement, {
 | 
			
		||||
          ...defaultEditorOptions,
 | 
			
		||||
          readOnly: true,
 | 
			
		||||
          quickSuggestions: false,
 | 
			
		||||
          occurrencesHighlight: false,
 | 
			
		||||
          renderLineHighlight: 'none',
 | 
			
		||||
          hideCursorInOverviewRuler: true,
 | 
			
		||||
        })),
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1809,9 +1809,11 @@ export default class Notes {
 | 
			
		|||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $closeBtn.text($closeBtn.data('originalText'));
 | 
			
		||||
 | 
			
		||||
    /* eslint-disable promise/catch-or-return */
 | 
			
		||||
    // Make request to submit comment on server
 | 
			
		||||
    axios
 | 
			
		||||
    return axios
 | 
			
		||||
      .post(`${formAction}?html=true`, formData)
 | 
			
		||||
      .then(res => {
 | 
			
		||||
        const note = res.data;
 | 
			
		||||
| 
						 | 
				
			
			@ -1928,8 +1930,6 @@ export default class Notes {
 | 
			
		|||
        this.reenableTargetFormSubmitButton(e);
 | 
			
		||||
        this.addNoteError($form);
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
    return $closeBtn.text($closeBtn.data('originalText'));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
import initSettingsPanels from '~/settings_panels';
 | 
			
		||||
 | 
			
		||||
document.addEventListener('DOMContentLoaded', () => {
 | 
			
		||||
  // Initialize expandable settings panels
 | 
			
		||||
  initSettingsPanels();
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -1,11 +1,11 @@
 | 
			
		|||
<script>
 | 
			
		||||
  import _ from 'underscore';
 | 
			
		||||
  import modal from '~/vue_shared/components/modal.vue';
 | 
			
		||||
  import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
 | 
			
		||||
  import { s__, sprintf } from '~/locale';
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    components: {
 | 
			
		||||
      modal,
 | 
			
		||||
      DeprecatedModal,
 | 
			
		||||
    },
 | 
			
		||||
    props: {
 | 
			
		||||
      deleteProjectUrl: {
 | 
			
		||||
| 
						 | 
				
			
			@ -79,7 +79,7 @@
 | 
			
		|||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <modal
 | 
			
		||||
  <deprecated-modal
 | 
			
		||||
    id="delete-project-modal"
 | 
			
		||||
    :title="title"
 | 
			
		||||
    :text="text"
 | 
			
		||||
| 
						 | 
				
			
			@ -121,5 +121,5 @@
 | 
			
		|||
        />
 | 
			
		||||
      </form>
 | 
			
		||||
    </template>
 | 
			
		||||
  </modal>
 | 
			
		||||
  </deprecated-modal>
 | 
			
		||||
</template>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,11 +1,11 @@
 | 
			
		|||
<script>
 | 
			
		||||
  import _ from 'underscore';
 | 
			
		||||
  import modal from '~/vue_shared/components/modal.vue';
 | 
			
		||||
  import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
 | 
			
		||||
  import { s__, sprintf } from '~/locale';
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    components: {
 | 
			
		||||
      modal,
 | 
			
		||||
      DeprecatedModal,
 | 
			
		||||
    },
 | 
			
		||||
    props: {
 | 
			
		||||
      deleteUserUrl: {
 | 
			
		||||
| 
						 | 
				
			
			@ -113,7 +113,7 @@
 | 
			
		|||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <modal
 | 
			
		||||
  <deprecated-modal
 | 
			
		||||
    id="delete-user-modal"
 | 
			
		||||
    :title="title"
 | 
			
		||||
    :text="text"
 | 
			
		||||
| 
						 | 
				
			
			@ -170,5 +170,5 @@
 | 
			
		|||
        {{ secondaryButtonLabel }}
 | 
			
		||||
      </button>
 | 
			
		||||
    </template>
 | 
			
		||||
  </modal>
 | 
			
		||||
  </deprecated-modal>
 | 
			
		||||
</template>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,14 +2,14 @@
 | 
			
		|||
  import axios from '~/lib/utils/axios_utils';
 | 
			
		||||
 | 
			
		||||
  import Flash from '~/flash';
 | 
			
		||||
  import modal from '~/vue_shared/components/modal.vue';
 | 
			
		||||
  import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
 | 
			
		||||
  import { n__, s__, sprintf } from '~/locale';
 | 
			
		||||
  import { redirectTo } from '~/lib/utils/url_utility';
 | 
			
		||||
  import eventHub from '../event_hub';
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    components: {
 | 
			
		||||
      modal,
 | 
			
		||||
      DeprecatedModal,
 | 
			
		||||
    },
 | 
			
		||||
    props: {
 | 
			
		||||
      issueCount: {
 | 
			
		||||
| 
						 | 
				
			
			@ -92,7 +92,7 @@ Once deleted, it cannot be undone or recovered.`),
 | 
			
		|||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <modal
 | 
			
		||||
  <deprecated-modal
 | 
			
		||||
    id="delete-milestone-modal"
 | 
			
		||||
    :title="title"
 | 
			
		||||
    :text="text"
 | 
			
		||||
| 
						 | 
				
			
			@ -106,5 +106,5 @@ Once deleted, it cannot be undone or recovered.`),
 | 
			
		|||
      <p v-html="props.text"></p>
 | 
			
		||||
    </template>
 | 
			
		||||
 | 
			
		||||
  </modal>
 | 
			
		||||
  </deprecated-modal>
 | 
			
		||||
</template>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -70,6 +70,7 @@ export default {
 | 
			
		|||
            <td
 | 
			
		||||
              v-for="key in keys"
 | 
			
		||||
              :key="key"
 | 
			
		||||
              class="break-word"
 | 
			
		||||
            >
 | 
			
		||||
              {{ item[key] }}
 | 
			
		||||
            </td>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,11 +1,28 @@
 | 
			
		|||
import Vue from 'vue';
 | 
			
		||||
import _ from 'underscore';
 | 
			
		||||
import axios from '../../lib/utils/axios_utils';
 | 
			
		||||
 | 
			
		||||
let vueResourceInterceptor;
 | 
			
		||||
 | 
			
		||||
export default class PerformanceBarService {
 | 
			
		||||
  static fetchRequestDetails(peekUrl, requestId) {
 | 
			
		||||
    return axios.get(peekUrl, { params: { request_id: requestId } });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static registerInterceptor(peekUrl, callback) {
 | 
			
		||||
    vueResourceInterceptor = (request, next) => {
 | 
			
		||||
      next(response => {
 | 
			
		||||
        const requestId = response.headers['x-request-id'];
 | 
			
		||||
        const requestUrl = response.url;
 | 
			
		||||
 | 
			
		||||
        if (requestUrl !== peekUrl && requestId) {
 | 
			
		||||
          callback(requestId, requestUrl);
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    Vue.http.interceptors.push(vueResourceInterceptor);
 | 
			
		||||
 | 
			
		||||
    return axios.interceptors.response.use(response => {
 | 
			
		||||
      const requestId = response.headers['x-request-id'];
 | 
			
		||||
      const requestUrl = response.config.url;
 | 
			
		||||
| 
						 | 
				
			
			@ -20,5 +37,9 @@ export default class PerformanceBarService {
 | 
			
		|||
 | 
			
		||||
  static removeInterceptor(interceptor) {
 | 
			
		||||
    axios.interceptors.response.eject(interceptor);
 | 
			
		||||
    Vue.http.interceptors = _.without(
 | 
			
		||||
      Vue.http.interceptors,
 | 
			
		||||
      vueResourceInterceptor,
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
<script>
 | 
			
		||||
  import modal from '~/vue_shared/components/modal.vue';
 | 
			
		||||
  import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
 | 
			
		||||
  import { s__, sprintf } from '~/locale';
 | 
			
		||||
  import pipelinesTableRowComponent from './pipelines_table_row.vue';
 | 
			
		||||
  import eventHub from '../event_hub';
 | 
			
		||||
| 
						 | 
				
			
			@ -12,7 +12,7 @@
 | 
			
		|||
  export default {
 | 
			
		||||
    components: {
 | 
			
		||||
      pipelinesTableRowComponent,
 | 
			
		||||
      modal,
 | 
			
		||||
      DeprecatedModal,
 | 
			
		||||
    },
 | 
			
		||||
    props: {
 | 
			
		||||
      pipelines: {
 | 
			
		||||
| 
						 | 
				
			
			@ -120,7 +120,7 @@
 | 
			
		|||
      :auto-devops-help-path="autoDevopsHelpPath"
 | 
			
		||||
      :view-type="viewType"
 | 
			
		||||
    />
 | 
			
		||||
    <modal
 | 
			
		||||
    <deprecated-modal
 | 
			
		||||
      id="confirmation-modal"
 | 
			
		||||
      :title="modalTitle"
 | 
			
		||||
      :text="modalText"
 | 
			
		||||
| 
						 | 
				
			
			@ -134,6 +134,6 @@
 | 
			
		|||
      >
 | 
			
		||||
        <p v-html="props.text"></p>
 | 
			
		||||
      </template>
 | 
			
		||||
    </modal>
 | 
			
		||||
    </deprecated-modal>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,11 +1,11 @@
 | 
			
		|||
<script>
 | 
			
		||||
  import modal from '~/vue_shared/components/modal.vue';
 | 
			
		||||
  import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
 | 
			
		||||
  import { __, s__, sprintf } from '~/locale';
 | 
			
		||||
  import csrf from '~/lib/utils/csrf';
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    components: {
 | 
			
		||||
      modal,
 | 
			
		||||
      DeprecatedModal,
 | 
			
		||||
    },
 | 
			
		||||
    props: {
 | 
			
		||||
      actionUrl: {
 | 
			
		||||
| 
						 | 
				
			
			@ -76,7 +76,7 @@ Once you confirm %{deleteAccount}, it cannot be undone or recovered.`),
 | 
			
		|||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <modal
 | 
			
		||||
  <deprecated-modal
 | 
			
		||||
    id="delete-account-modal"
 | 
			
		||||
    :title="s__('Profiles|Delete your account?')"
 | 
			
		||||
    :text="text"
 | 
			
		||||
| 
						 | 
				
			
			@ -131,5 +131,5 @@ Once you confirm %{deleteAccount}, it cannot be undone or recovered.`),
 | 
			
		|||
      </form>
 | 
			
		||||
    </template>
 | 
			
		||||
 | 
			
		||||
  </modal>
 | 
			
		||||
  </deprecated-modal>
 | 
			
		||||
</template>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
<script>
 | 
			
		||||
import { sprintf, s__ } from '~/locale';
 | 
			
		||||
import statusCodes from '../../lib/utils/http_status';
 | 
			
		||||
import { bytesToMiB } from '../../lib/utils/number_utils';
 | 
			
		||||
import { backOff } from '../../lib/utils/common_utils';
 | 
			
		||||
| 
						 | 
				
			
			@ -45,17 +46,28 @@ export default {
 | 
			
		|||
    shouldShowMetricsUnavailable() {
 | 
			
		||||
      return !this.loadingMetrics && !this.hasMetrics && !this.loadFailed;
 | 
			
		||||
    },
 | 
			
		||||
    memoryChangeType() {
 | 
			
		||||
    memoryChangeMessage() {
 | 
			
		||||
      const messageProps = {
 | 
			
		||||
        memoryFrom: this.memoryFrom,
 | 
			
		||||
        memoryTo: this.memoryTo,
 | 
			
		||||
        metricsLinkStart: `<a href="${this.metricsMonitoringUrl}">`,
 | 
			
		||||
        metricsLinkEnd: '</a>',
 | 
			
		||||
        emphasisStart: '<b>',
 | 
			
		||||
        emphasisEnd: '</b>',
 | 
			
		||||
      };
 | 
			
		||||
      const memoryTo = Number(this.memoryTo);
 | 
			
		||||
      const memoryFrom = Number(this.memoryFrom);
 | 
			
		||||
      let memoryUsageMsg = '';
 | 
			
		||||
 | 
			
		||||
      if (memoryTo > memoryFrom) {
 | 
			
		||||
        return 'increased';
 | 
			
		||||
        memoryUsageMsg = sprintf(s__('mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage %{emphasisStart} increased %{emphasisEnd} from %{memoryFrom}MB to %{memoryTo}MB'), messageProps, false);
 | 
			
		||||
      } else if (memoryTo < memoryFrom) {
 | 
			
		||||
        return 'decreased';
 | 
			
		||||
        memoryUsageMsg = sprintf(s__('mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage %{emphasisStart} decreased %{emphasisEnd} from %{memoryFrom}MB to %{memoryTo}MB'), messageProps, false);
 | 
			
		||||
      } else {
 | 
			
		||||
        memoryUsageMsg = sprintf(s__('mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB'), messageProps, false);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return 'unchanged';
 | 
			
		||||
      return memoryUsageMsg;
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  mounted() {
 | 
			
		||||
| 
						 | 
				
			
			@ -130,24 +142,22 @@ export default {
 | 
			
		|||
      <i
 | 
			
		||||
        class="fa fa-spinner fa-spin usage-info-load-spinner"
 | 
			
		||||
        aria-hidden="true">
 | 
			
		||||
      </i>Loading deployment statistics
 | 
			
		||||
      </i>{{ s__('mrWidget|Loading deployment statistics') }}
 | 
			
		||||
    </p>
 | 
			
		||||
    <p
 | 
			
		||||
      v-if="shouldShowMemoryGraph"
 | 
			
		||||
      class="usage-info js-usage-info">
 | 
			
		||||
      <a
 | 
			
		||||
        :href="metricsMonitoringUrl"
 | 
			
		||||
      >Memory</a> usage <b>{{ memoryChangeType }}</b> from {{ memoryFrom }}MB to {{ memoryTo }}MB
 | 
			
		||||
      {{ memoryChangeMessage }}
 | 
			
		||||
    </p>
 | 
			
		||||
    <p
 | 
			
		||||
      v-if="shouldShowLoadFailure"
 | 
			
		||||
      class="usage-info js-usage-info usage-info-failed">
 | 
			
		||||
      Failed to load deployment statistics
 | 
			
		||||
      {{ s__('mrWidget|Failed to load deployment statistics') }}
 | 
			
		||||
    </p>
 | 
			
		||||
    <p
 | 
			
		||||
      v-if="shouldShowMetricsUnavailable"
 | 
			
		||||
      class="usage-info js-usage-info usage-info-unavailable">
 | 
			
		||||
      Deployment statistics are not available currently
 | 
			
		||||
      {{ s__('mrWidget|Deployment statistics are not available currently') }}
 | 
			
		||||
    </p>
 | 
			
		||||
    <memory-graph
 | 
			
		||||
      v-if="shouldShowMemoryGraph"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
<script>
 | 
			
		||||
  /* eslint-disable vue/require-default-prop */
 | 
			
		||||
  export default {
 | 
			
		||||
    name: 'Modal',
 | 
			
		||||
    name: 'DeprecatedModal', // use GlModal instead
 | 
			
		||||
 | 
			
		||||
    props: {
 | 
			
		||||
      id: {
 | 
			
		||||
| 
						 | 
				
			
			@ -1,11 +1,11 @@
 | 
			
		|||
<script>
 | 
			
		||||
  import modal from './modal.vue';
 | 
			
		||||
  import DeprecatedModal from './deprecated_modal.vue';
 | 
			
		||||
 | 
			
		||||
  export default {
 | 
			
		||||
    name: 'RecaptchaModal',
 | 
			
		||||
 | 
			
		||||
    components: {
 | 
			
		||||
      modal,
 | 
			
		||||
      DeprecatedModal,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    props: {
 | 
			
		||||
| 
						 | 
				
			
			@ -65,7 +65,7 @@
 | 
			
		|||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <modal
 | 
			
		||||
  <deprecated-modal
 | 
			
		||||
    kind="warning"
 | 
			
		||||
    class="recaptcha-modal js-recaptcha-modal"
 | 
			
		||||
    :hide-footer="true"
 | 
			
		||||
| 
						 | 
				
			
			@ -82,5 +82,5 @@
 | 
			
		|||
      >
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </modal>
 | 
			
		||||
  </deprecated-modal>
 | 
			
		||||
</template>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -446,6 +446,10 @@ img.emoji {
 | 
			
		|||
  opacity: .5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.break-word {
 | 
			
		||||
  word-wrap: break-word;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** COMMON CLASSES **/
 | 
			
		||||
.prepend-top-0 { margin-top: 0; }
 | 
			
		||||
.prepend-top-5 { margin-top: 5px; }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -622,7 +622,7 @@
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
.dropdown-content {
 | 
			
		||||
  max-height: $dropdown-max-height;
 | 
			
		||||
  max-height: 252px;
 | 
			
		||||
  overflow-y: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -699,6 +699,31 @@
 | 
			
		|||
  border-radius: $border-radius-base;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.git-revision-dropdown {
 | 
			
		||||
  .dropdown-content {
 | 
			
		||||
    max-height: 215px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sidebar-move-issue-dropdown {
 | 
			
		||||
  .dropdown-content {
 | 
			
		||||
    max-height: 160px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dropdown-menu-author {
 | 
			
		||||
  .dropdown-content {
 | 
			
		||||
    max-height: 215px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dropdown-menu-labels {
 | 
			
		||||
  .dropdown-content {
 | 
			
		||||
    max-height: 128px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.dropdown-menu-due-date {
 | 
			
		||||
  .dropdown-content {
 | 
			
		||||
    max-height: 230px;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -152,3 +152,4 @@
 | 
			
		|||
.sidebar-collapsed-icon .sidebar-collapsed-value {
 | 
			
		||||
  font-size: 12px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,8 +31,12 @@
 | 
			
		|||
.dropdown-menu-issues-board-new {
 | 
			
		||||
  width: 320px;
 | 
			
		||||
 | 
			
		||||
  .open & {
 | 
			
		||||
    max-height: 400px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .dropdown-content {
 | 
			
		||||
    max-height: 150px;
 | 
			
		||||
    max-height: 162px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,17 @@
 | 
			
		|||
.content-list > .branch-item,
 | 
			
		||||
.branch-title {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.branch-info {
 | 
			
		||||
  flex: auto;
 | 
			
		||||
  min-width: 0;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.divergence-graph {
 | 
			
		||||
  padding: 12px 12px 0 0;
 | 
			
		||||
  float: right;
 | 
			
		||||
  padding: 0 6px;
 | 
			
		||||
 | 
			
		||||
  .graph-side {
 | 
			
		||||
    position: relative;
 | 
			
		||||
| 
						 | 
				
			
			@ -53,3 +64,9 @@
 | 
			
		|||
    background-color: $divergence-graph-separator-bg;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.divergence-graph,
 | 
			
		||||
.branch-item .controls {
 | 
			
		||||
  flex: 0 0 auto;
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -162,17 +162,14 @@
 | 
			
		|||
 * Last push widget
 | 
			
		||||
 */
 | 
			
		||||
.event-last-push {
 | 
			
		||||
  overflow: auto;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
 | 
			
		||||
  .event-last-push-text {
 | 
			
		||||
    @include str-truncated(100%);
 | 
			
		||||
    padding: 4px 0;
 | 
			
		||||
    font-size: 13px;
 | 
			
		||||
    float: left;
 | 
			
		||||
    margin-right: -150px;
 | 
			
		||||
    padding-right: 150px;
 | 
			
		||||
    line-height: 20px;
 | 
			
		||||
    margin-right: $gl-padding;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,9 +26,15 @@
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dropdown-menu-labels {
 | 
			
		||||
  .dropdown-content {
 | 
			
		||||
    max-height: 135px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dropdown-new-label {
 | 
			
		||||
  .dropdown-content {
 | 
			
		||||
    max-height: 260px;
 | 
			
		||||
    max-height: 136px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,7 +9,6 @@
 | 
			
		|||
.new_project,
 | 
			
		||||
.edit-project,
 | 
			
		||||
.import-project {
 | 
			
		||||
 | 
			
		||||
  .help-block {
 | 
			
		||||
    margin-bottom: 10px;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -18,18 +17,25 @@
 | 
			
		|||
    border-radius: $border-radius-base;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .input-group > div {
 | 
			
		||||
  .input-group {
 | 
			
		||||
    display: flex;
 | 
			
		||||
 | 
			
		||||
    &:last-child {
 | 
			
		||||
      padding-right: 0;
 | 
			
		||||
    .select2-container {
 | 
			
		||||
      display: unset;
 | 
			
		||||
      max-width: unset;
 | 
			
		||||
      width: unset !important;
 | 
			
		||||
      flex-grow: 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    > div {
 | 
			
		||||
      &:last-child {
 | 
			
		||||
        padding-right: 0;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @media (max-width: $screen-xs-max) {
 | 
			
		||||
    .input-group > div {
 | 
			
		||||
 | 
			
		||||
      margin-bottom: 14px;
 | 
			
		||||
 | 
			
		||||
      &:last-child {
 | 
			
		||||
        margin-bottom: 0;
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			@ -41,17 +47,24 @@
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  .input-group-addon {
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    text-overflow: ellipsis;
 | 
			
		||||
    line-height: unset;
 | 
			
		||||
    width: unset;
 | 
			
		||||
    max-width: 50%;
 | 
			
		||||
    text-align: left;
 | 
			
		||||
 | 
			
		||||
    &.static-namespace {
 | 
			
		||||
      height: 35px;
 | 
			
		||||
      border-radius: 3px;
 | 
			
		||||
      border: 1px solid $border-color;
 | 
			
		||||
      max-width: 100%;
 | 
			
		||||
      flex-grow: 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    + .select2 a,
 | 
			
		||||
    + .btn-default {
 | 
			
		||||
      border-top-left-radius: 0;
 | 
			
		||||
      border-bottom-left-radius: 0;
 | 
			
		||||
      border-radius: 0 $border-radius-base $border-radius-base 0;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -290,7 +303,7 @@
 | 
			
		|||
      font-size: 13px;
 | 
			
		||||
      font-weight: $gl-font-weight-bold;
 | 
			
		||||
      line-height: 13px;
 | 
			
		||||
      letter-spacing: .4px;
 | 
			
		||||
      letter-spacing: 0.4px;
 | 
			
		||||
      padding: 6px 14px;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
      vertical-align: middle;
 | 
			
		||||
| 
						 | 
				
			
			@ -443,7 +456,7 @@ a.deploy-project-label {
 | 
			
		|||
    text-decoration: none;
 | 
			
		||||
 | 
			
		||||
    &.disabled {
 | 
			
		||||
      opacity: .3;
 | 
			
		||||
      opacity: 0.3;
 | 
			
		||||
      cursor: not-allowed;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -600,26 +613,26 @@ a.deploy-project-label {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  .first-column {
 | 
			
		||||
    @media(min-width: $screen-xs-min) {
 | 
			
		||||
    @media (min-width: $screen-xs-min) {
 | 
			
		||||
      max-width: 50%;
 | 
			
		||||
      padding-right: 30px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @media(max-width: $screen-xs-max) {
 | 
			
		||||
    @media (max-width: $screen-xs-max) {
 | 
			
		||||
      max-width: 100%;
 | 
			
		||||
      width: 100%;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .second-column {
 | 
			
		||||
    @media(min-width: $screen-xs-min) {
 | 
			
		||||
    @media (min-width: $screen-xs-min) {
 | 
			
		||||
      width: 50%;
 | 
			
		||||
      flex: 1;
 | 
			
		||||
      padding-left: 30px;
 | 
			
		||||
      position: relative;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @media(max-width: $screen-xs-max) {
 | 
			
		||||
    @media (max-width: $screen-xs-max) {
 | 
			
		||||
      max-width: 100%;
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      padding-left: 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -632,7 +645,7 @@ a.deploy-project-label {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    &::before {
 | 
			
		||||
      content: "OR";
 | 
			
		||||
      content: 'OR';
 | 
			
		||||
      position: absolute;
 | 
			
		||||
      left: -10px;
 | 
			
		||||
      top: 50%;
 | 
			
		||||
| 
						 | 
				
			
			@ -656,7 +669,7 @@ a.deploy-project-label {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    &::after {
 | 
			
		||||
      content: "";
 | 
			
		||||
      content: '';
 | 
			
		||||
      position: absolute;
 | 
			
		||||
      background-color: $border-color;
 | 
			
		||||
      bottom: 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -921,10 +934,7 @@ pre.light-well {
 | 
			
		|||
      border-right: solid 1px transparent;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.protected-tags-list,
 | 
			
		||||
.protected-branches-list {
 | 
			
		||||
  .dropdown-menu-toggle {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    max-width: 300px;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -294,6 +294,10 @@
 | 
			
		|||
    .margin-view-overlays .delete-sign {
 | 
			
		||||
      opacity: 0.4;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .cursors-layer {
 | 
			
		||||
      display: none;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -112,7 +112,7 @@ input[type="checkbox"]:hover {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    .dropdown-content {
 | 
			
		||||
      max-height: 350px;
 | 
			
		||||
      max-height: 302px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -15,6 +15,10 @@
 | 
			
		|||
  line-height: $performance-bar-height;
 | 
			
		||||
  color: $perf-bar-text;
 | 
			
		||||
 | 
			
		||||
  select {
 | 
			
		||||
    width: 200px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &.disabled {
 | 
			
		||||
    display: none;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -102,8 +106,14 @@
 | 
			
		|||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .performance-bar-modal .modal-footer {
 | 
			
		||||
    display: none;
 | 
			
		||||
  .performance-bar-modal {
 | 
			
		||||
    .modal-footer {
 | 
			
		||||
      display: none;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .modal-dialog {
 | 
			
		||||
      width: 860px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,23 +3,9 @@
 | 
			
		|||
# Automatically sets the layout and ensures an administrator is logged in
 | 
			
		||||
class Admin::ApplicationController < ApplicationController
 | 
			
		||||
  before_action :authenticate_admin!
 | 
			
		||||
  before_action :display_read_only_information
 | 
			
		||||
  layout 'admin'
 | 
			
		||||
 | 
			
		||||
  def authenticate_admin!
 | 
			
		||||
    render_404 unless current_user.admin?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def display_read_only_information
 | 
			
		||||
    return unless Gitlab::Database.read_only?
 | 
			
		||||
 | 
			
		||||
    flash.now[:notice] = read_only_message
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  # Overridden in EE
 | 
			
		||||
  def read_only_message
 | 
			
		||||
    _('You are on a read-only GitLab instance.')
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
module SendFileUpload
 | 
			
		||||
  def send_upload(file_upload, send_params: {}, redirect_params: {}, attachment: nil, disposition: 'attachment')
 | 
			
		||||
    if attachment
 | 
			
		||||
      redirect_params[:query] = { "response-content-disposition" => "#{disposition};filename=#{attachment.inspect}" }
 | 
			
		||||
      send_params.merge!(filename: attachment, disposition: disposition)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    if file_upload.file_storage?
 | 
			
		||||
      send_file file_upload.path, send_params
 | 
			
		||||
    elsif file_upload.class.proxy_download_enabled?
 | 
			
		||||
      headers.store(*Gitlab::Workhorse.send_url(file_upload.url(**redirect_params)))
 | 
			
		||||
      head :ok
 | 
			
		||||
    else
 | 
			
		||||
      redirect_to file_upload.url(**redirect_params)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
module UploadsActions
 | 
			
		||||
  include Gitlab::Utils::StrongMemoize
 | 
			
		||||
  include SendFileUpload
 | 
			
		||||
 | 
			
		||||
  UPLOAD_MOUNTS = %w(avatar attachment file logo header_logo).freeze
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -26,14 +27,11 @@ module UploadsActions
 | 
			
		|||
  def show
 | 
			
		||||
    return render_404 unless uploader&.exists?
 | 
			
		||||
 | 
			
		||||
    if uploader.file_storage?
 | 
			
		||||
      disposition = uploader.image_or_video? ? 'inline' : 'attachment'
 | 
			
		||||
      expires_in 0.seconds, must_revalidate: true, private: true
 | 
			
		||||
    expires_in 0.seconds, must_revalidate: true, private: true
 | 
			
		||||
 | 
			
		||||
      send_file uploader.file.path, disposition: disposition
 | 
			
		||||
    else
 | 
			
		||||
      redirect_to uploader.url
 | 
			
		||||
    end
 | 
			
		||||
    disposition = uploader.image_or_video? ? 'inline' : 'attachment'
 | 
			
		||||
 | 
			
		||||
    send_upload(uploader, attachment: uploader.filename, disposition: disposition)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
| 
						 | 
				
			
			@ -62,22 +60,30 @@ module UploadsActions
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def build_uploader_from_upload
 | 
			
		||||
    return nil unless params[:secret] && params[:filename]
 | 
			
		||||
    return unless uploader = build_uploader
 | 
			
		||||
 | 
			
		||||
    upload_path = uploader_class.upload_path(params[:secret], params[:filename])
 | 
			
		||||
    upload = Upload.find_by(uploader: uploader_class.to_s, path: upload_path)
 | 
			
		||||
    upload_paths = uploader.upload_paths(params[:filename])
 | 
			
		||||
    upload = Upload.find_by(uploader: uploader_class.to_s, path: upload_paths)
 | 
			
		||||
    upload&.build_uploader
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def build_uploader_from_params
 | 
			
		||||
    uploader = uploader_class.new(model, secret: params[:secret])
 | 
			
		||||
 | 
			
		||||
    return nil unless uploader.model_valid?
 | 
			
		||||
    return unless uploader = build_uploader
 | 
			
		||||
 | 
			
		||||
    uploader.retrieve_from_store!(params[:filename])
 | 
			
		||||
    uploader
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def build_uploader
 | 
			
		||||
    return unless params[:secret] && params[:filename]
 | 
			
		||||
 | 
			
		||||
    uploader = uploader_class.new(model, secret: params[:secret])
 | 
			
		||||
 | 
			
		||||
    return unless uploader.model_valid?
 | 
			
		||||
 | 
			
		||||
    uploader
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def image_or_video?
 | 
			
		||||
    uploader && uploader.exists? && uploader.image_or_video?
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,7 +39,7 @@ module Groups
 | 
			
		|||
    end
 | 
			
		||||
 | 
			
		||||
    def variable_params_attributes
 | 
			
		||||
      %i[id key value protected _destroy]
 | 
			
		||||
      %i[id key secret_value protected _destroy]
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def authorize_admin_build!
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,6 +18,18 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
 | 
			
		|||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Extend the standard implementation to also increment
 | 
			
		||||
  # the number of failed sign in attempts
 | 
			
		||||
  def failure
 | 
			
		||||
    if params[:username].present? && AuthHelper.form_based_provider?(failed_strategy.name)
 | 
			
		||||
      user = User.by_login(params[:username])
 | 
			
		||||
 | 
			
		||||
      user&.increment_failed_attempts!
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    super
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Extend the standard message generation to accept our custom exception
 | 
			
		||||
  def failure_message
 | 
			
		||||
    exception = env["omniauth.error"]
 | 
			
		||||
| 
						 | 
				
			
			@ -95,6 +107,14 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
 | 
			
		|||
    handle_omniauth
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def auth0
 | 
			
		||||
    if oauth['uid'].blank?
 | 
			
		||||
      fail_auth0_login
 | 
			
		||||
    else
 | 
			
		||||
      handle_omniauth
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def handle_omniauth
 | 
			
		||||
| 
						 | 
				
			
			@ -170,6 +190,12 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
 | 
			
		|||
    redirect_to new_user_session_path
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def fail_auth0_login
 | 
			
		||||
    flash[:alert] = 'Wrong extern UID provided. Make sure Auth0 is configured correctly.'
 | 
			
		||||
 | 
			
		||||
    redirect_to new_user_session_path
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def handle_disabled_provider
 | 
			
		||||
    label = Gitlab::Auth::OAuth::Provider.label_for(oauth['provider'])
 | 
			
		||||
    flash[:alert] = "Signing in using #{label} has been disabled"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
class Projects::ArtifactsController < Projects::ApplicationController
 | 
			
		||||
  include ExtractsPath
 | 
			
		||||
  include RendersBlob
 | 
			
		||||
  include SendFileUpload
 | 
			
		||||
 | 
			
		||||
  layout 'project'
 | 
			
		||||
  before_action :authorize_read_build!
 | 
			
		||||
| 
						 | 
				
			
			@ -10,11 +11,7 @@ class Projects::ArtifactsController < Projects::ApplicationController
 | 
			
		|||
  before_action :entry, only: [:file]
 | 
			
		||||
 | 
			
		||||
  def download
 | 
			
		||||
    if artifacts_file.file_storage?
 | 
			
		||||
      send_file artifacts_file.path, disposition: 'attachment'
 | 
			
		||||
    else
 | 
			
		||||
      redirect_to artifacts_file.url
 | 
			
		||||
    end
 | 
			
		||||
    send_upload(artifacts_file, attachment: artifacts_file.filename)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def browse
 | 
			
		||||
| 
						 | 
				
			
			@ -45,8 +42,7 @@ class Projects::ArtifactsController < Projects::ApplicationController
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def raw
 | 
			
		||||
    path = Gitlab::Ci::Build::Artifacts::Path
 | 
			
		||||
      .new(params[:path])
 | 
			
		||||
    path = Gitlab::Ci::Build::Artifacts::Path.new(params[:path])
 | 
			
		||||
 | 
			
		||||
    send_artifacts_entry(build, path)
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			@ -75,7 +71,7 @@ class Projects::ArtifactsController < Projects::ApplicationController
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def validate_artifacts!
 | 
			
		||||
    render_404 unless build && build.artifacts?
 | 
			
		||||
    render_404 unless build&.artifacts?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def build
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,6 @@
 | 
			
		|||
class Projects::JobsController < Projects::ApplicationController
 | 
			
		||||
  include SendFileUpload
 | 
			
		||||
 | 
			
		||||
  before_action :build, except: [:index, :cancel_all]
 | 
			
		||||
 | 
			
		||||
  before_action :authorize_read_build!,
 | 
			
		||||
| 
						 | 
				
			
			@ -117,11 +119,17 @@ class Projects::JobsController < Projects::ApplicationController
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def raw
 | 
			
		||||
    build.trace.read do |stream|
 | 
			
		||||
      if stream.file?
 | 
			
		||||
        send_file stream.path, type: 'text/plain; charset=utf-8', disposition: 'inline'
 | 
			
		||||
      else
 | 
			
		||||
        render_404
 | 
			
		||||
    if trace_artifact_file
 | 
			
		||||
      send_upload(trace_artifact_file,
 | 
			
		||||
                  send_params: raw_send_params,
 | 
			
		||||
                  redirect_params: raw_redirect_params)
 | 
			
		||||
    else
 | 
			
		||||
      build.trace.read do |stream|
 | 
			
		||||
        if stream.file?
 | 
			
		||||
          send_file stream.path, type: 'text/plain; charset=utf-8', disposition: 'inline'
 | 
			
		||||
        else
 | 
			
		||||
          render_404
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			@ -136,9 +144,21 @@ class Projects::JobsController < Projects::ApplicationController
 | 
			
		|||
    return access_denied! unless can?(current_user, :erase_build, build)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def raw_send_params
 | 
			
		||||
    { type: 'text/plain; charset=utf-8', disposition: 'inline' }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def raw_redirect_params
 | 
			
		||||
    { query: { 'response-content-type' => 'text/plain; charset=utf-8', 'response-content-disposition' => 'inline' } }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def trace_artifact_file
 | 
			
		||||
    @trace_artifact_file ||= build.job_artifacts_trace&.file
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def build
 | 
			
		||||
    @build ||= project.builds.find(params[:id])
 | 
			
		||||
      .present(current_user: current_user)
 | 
			
		||||
                 .present(current_user: current_user)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def build_path(build)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
class Projects::LfsStorageController < Projects::GitHttpClientController
 | 
			
		||||
  include LfsRequest
 | 
			
		||||
  include WorkhorseRequest
 | 
			
		||||
  include SendFileUpload
 | 
			
		||||
 | 
			
		||||
  skip_before_action :verify_workhorse_api!, only: [:download, :upload_finalize]
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -11,7 +12,7 @@ class Projects::LfsStorageController < Projects::GitHttpClientController
 | 
			
		|||
      return
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    send_file lfs_object.file.path, content_type: "application/octet-stream"
 | 
			
		||||
    send_upload(lfs_object.file, send_params: { content_type: "application/octet-stream" })
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def upload_authorize
 | 
			
		||||
| 
						 | 
				
			
			@ -70,10 +71,7 @@ class Projects::LfsStorageController < Projects::GitHttpClientController
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def move_tmp_file_to_storage(object, path)
 | 
			
		||||
    File.open(path) do |f|
 | 
			
		||||
      object.file = f
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    object.file = File.open(path)
 | 
			
		||||
    object.file.store!
 | 
			
		||||
    object.save
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,4 +21,26 @@ class Projects::PagesController < Projects::ApplicationController
 | 
			
		|||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def update
 | 
			
		||||
    result = Projects::UpdateService.new(@project, current_user, project_params).execute
 | 
			
		||||
 | 
			
		||||
    respond_to do |format|
 | 
			
		||||
      format.html do
 | 
			
		||||
        if result[:status] == :success
 | 
			
		||||
          flash[:notice] = 'Your changes have been saved'
 | 
			
		||||
        else
 | 
			
		||||
          flash[:alert] = 'Something went wrong on our end'
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        redirect_to project_pages_path(@project)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def project_params
 | 
			
		||||
    params.require(:project).permit(:pages_https_only)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -92,7 +92,7 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController
 | 
			
		|||
  def schedule_params
 | 
			
		||||
    params.require(:schedule)
 | 
			
		||||
      .permit(:description, :cron, :cron_timezone, :ref, :active,
 | 
			
		||||
        variables_attributes: [:id, :key, :value, :_destroy] )
 | 
			
		||||
        variables_attributes: [:id, :key, :secret_value, :_destroy] )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def authorize_play_pipeline_schedule!
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,10 +10,7 @@ class Projects::PipelinesSettingsController < Projects::ApplicationController
 | 
			
		|||
      if service.execute
 | 
			
		||||
        flash[:notice] = "Pipelines settings for '#{@project.name}' were successfully updated."
 | 
			
		||||
 | 
			
		||||
        if service.run_auto_devops_pipeline?
 | 
			
		||||
          CreatePipelineWorker.perform_async(project.id, current_user.id, project.default_branch, :web, ignore_skip_ci: true, save_on_errors: false)
 | 
			
		||||
          flash[:success] = "A new Auto DevOps pipeline has been created, go to <a href=\"#{project_pipelines_path(@project)}\">Pipelines page</a> for details".html_safe
 | 
			
		||||
        end
 | 
			
		||||
        run_autodevops_pipeline(service)
 | 
			
		||||
 | 
			
		||||
        redirect_to project_settings_ci_cd_path(@project)
 | 
			
		||||
      else
 | 
			
		||||
| 
						 | 
				
			
			@ -24,6 +21,18 @@ class Projects::PipelinesSettingsController < Projects::ApplicationController
 | 
			
		|||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def run_autodevops_pipeline(service)
 | 
			
		||||
    return unless service.run_auto_devops_pipeline?
 | 
			
		||||
 | 
			
		||||
    if @project.empty_repo?
 | 
			
		||||
      flash[:warning] = "This repository is currently empty. A new Auto DevOps pipeline will be created after a new file has been pushed to a branch."
 | 
			
		||||
      return
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    CreatePipelineWorker.perform_async(project.id, current_user.id, project.default_branch, :web, ignore_skip_ci: true, save_on_errors: false)
 | 
			
		||||
    flash[:success] = "A new Auto DevOps pipeline has been created, go to <a href=\"#{project_pipelines_path(@project)}\">Pipelines page</a> for details".html_safe
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def update_params
 | 
			
		||||
    params.require(:project).permit(
 | 
			
		||||
      :runners_token, :builds_enabled, :build_allow_git_fetch,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@
 | 
			
		|||
class Projects::RawController < Projects::ApplicationController
 | 
			
		||||
  include ExtractsPath
 | 
			
		||||
  include BlobHelper
 | 
			
		||||
  include SendFileUpload
 | 
			
		||||
 | 
			
		||||
  before_action :require_non_empty_project
 | 
			
		||||
  before_action :assign_ref_vars
 | 
			
		||||
| 
						 | 
				
			
			@ -31,7 +32,7 @@ class Projects::RawController < Projects::ApplicationController
 | 
			
		|||
    lfs_object = find_lfs_object
 | 
			
		||||
 | 
			
		||||
    if lfs_object && lfs_object.project_allowed_access?(@project)
 | 
			
		||||
      send_file lfs_object.file.path, filename: @blob.name, disposition: 'attachment'
 | 
			
		||||
      send_upload(lfs_object.file, attachment: @blob.name)
 | 
			
		||||
    else
 | 
			
		||||
      render_404
 | 
			
		||||
    end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,6 +36,6 @@ class Projects::VariablesController < Projects::ApplicationController
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def variable_params_attributes
 | 
			
		||||
    %i[id key value protected _destroy]
 | 
			
		||||
    %i[id key secret_value protected _destroy]
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -323,4 +323,11 @@ module ApplicationHelper
 | 
			
		|||
  def locale_path
 | 
			
		||||
    asset_path("locale/#{Gitlab::I18n.locale}/app.js")
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Overridden in EE
 | 
			
		||||
  def read_only_message
 | 
			
		||||
    return unless Gitlab::Database.read_only?
 | 
			
		||||
 | 
			
		||||
    _('You are on a read-only GitLab instance.')
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -96,7 +96,7 @@ module ApplicationSettingsHelper
 | 
			
		|||
 | 
			
		||||
  def repository_storages_options_for_select(selected)
 | 
			
		||||
    options = Gitlab.config.repositories.storages.map do |name, storage|
 | 
			
		||||
      ["#{name} - #{storage['path']}", name]
 | 
			
		||||
      ["#{name} - #{storage['gitaly_address']}", name]
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    options_for_select(options, selected)
 | 
			
		||||
| 
						 | 
				
			
			@ -245,7 +245,8 @@ module ApplicationSettingsHelper
 | 
			
		|||
      :usage_ping_enabled,
 | 
			
		||||
      :user_default_external,
 | 
			
		||||
      :user_oauth_applications,
 | 
			
		||||
      :version_check_enabled
 | 
			
		||||
      :version_check_enabled,
 | 
			
		||||
      :allow_local_requests_from_hooks_and_services
 | 
			
		||||
    ]
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -531,4 +531,22 @@ module ProjectsHelper
 | 
			
		|||
  def can_show_last_commit_in_list?(project)
 | 
			
		||||
    can?(current_user, :read_cross_project) && project.commit
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def pages_https_only_disabled?
 | 
			
		||||
    !@project.pages_domains.all?(&:https?)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def pages_https_only_title
 | 
			
		||||
    return unless pages_https_only_disabled?
 | 
			
		||||
 | 
			
		||||
    "You must enable HTTPS for all your domains first"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def pages_https_only_label_class
 | 
			
		||||
    if pages_https_only_disabled?
 | 
			
		||||
      "list-label disabled"
 | 
			
		||||
    else
 | 
			
		||||
      "list-label"
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,14 @@ module Emails
 | 
			
		|||
      mail_answer_thread(@merge_request, merge_request_thread_options(updated_by_user_id, recipient_id, reason))
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def push_to_merge_request_email(recipient_id, merge_request_id, updated_by_user_id, reason = nil, new_commits: [], existing_commits: [])
 | 
			
		||||
      setup_merge_request_mail(merge_request_id, recipient_id)
 | 
			
		||||
      @new_commits = new_commits
 | 
			
		||||
      @existing_commits = existing_commits
 | 
			
		||||
 | 
			
		||||
      mail_answer_thread(@merge_request, merge_request_thread_options(updated_by_user_id, recipient_id, reason))
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id, updated_by_user_id, reason = nil)
 | 
			
		||||
      setup_merge_request_mail(merge_request_id, recipient_id)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,7 @@
 | 
			
		|||
class Appearance < ActiveRecord::Base
 | 
			
		||||
  include CacheMarkdownField
 | 
			
		||||
  include AfterCommitQueue
 | 
			
		||||
  include ObjectStorage::BackgroundMove
 | 
			
		||||
 | 
			
		||||
  cache_markdown_field :description
 | 
			
		||||
  cache_markdown_field :new_project_guidelines
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -330,7 +330,8 @@ class ApplicationSetting < ActiveRecord::Base
 | 
			
		|||
      usage_ping_enabled: Settings.gitlab['usage_ping_enabled'],
 | 
			
		||||
      gitaly_timeout_fast: 10,
 | 
			
		||||
      gitaly_timeout_medium: 30,
 | 
			
		||||
      gitaly_timeout_default: 55
 | 
			
		||||
      gitaly_timeout_default: 55,
 | 
			
		||||
      allow_local_requests_from_hooks_and_services: false
 | 
			
		||||
    }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,7 @@ module Ci
 | 
			
		|||
    prepend ArtifactMigratable
 | 
			
		||||
    include TokenAuthenticatable
 | 
			
		||||
    include AfterCommitQueue
 | 
			
		||||
    include ObjectStorage::BackgroundMove
 | 
			
		||||
    include Presentable
 | 
			
		||||
    include Importable
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -45,6 +46,7 @@ module Ci
 | 
			
		|||
      where('(artifacts_file IS NOT NULL AND artifacts_file <> ?) OR EXISTS (?)',
 | 
			
		||||
        '', Ci::JobArtifact.select(1).where('ci_builds.id = ci_job_artifacts.job_id').archive)
 | 
			
		||||
    end
 | 
			
		||||
    scope :with_artifacts_stored_locally, -> { with_artifacts_archive.where(artifacts_file_store: [nil, LegacyArtifactUploader::Store::LOCAL]) }
 | 
			
		||||
    scope :with_artifacts_not_expired, ->() { with_artifacts_archive.where('artifacts_expire_at IS NULL OR artifacts_expire_at > ?', Time.now) }
 | 
			
		||||
    scope :with_expired_artifacts, ->() { with_artifacts_archive.where('artifacts_expire_at < ?', Time.now) }
 | 
			
		||||
    scope :last_month, ->() { where('created_at > ?', Date.today - 1.month) }
 | 
			
		||||
| 
						 | 
				
			
			@ -365,13 +367,19 @@ module Ci
 | 
			
		|||
      project.running_or_pending_build_count(force: true)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def artifacts_metadata_entry(path, **options)
 | 
			
		||||
      metadata = Gitlab::Ci::Build::Artifacts::Metadata.new(
 | 
			
		||||
        artifacts_metadata.path,
 | 
			
		||||
        path,
 | 
			
		||||
        **options)
 | 
			
		||||
    def browsable_artifacts?
 | 
			
		||||
      artifacts_metadata?
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
      metadata.to_entry
 | 
			
		||||
    def artifacts_metadata_entry(path, **options)
 | 
			
		||||
      artifacts_metadata.use_file do |metadata_path|
 | 
			
		||||
        metadata = Gitlab::Ci::Build::Artifacts::Metadata.new(
 | 
			
		||||
          metadata_path,
 | 
			
		||||
          path,
 | 
			
		||||
          **options)
 | 
			
		||||
 | 
			
		||||
        metadata.to_entry
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def erase_artifacts!
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,8 @@ module Ci
 | 
			
		|||
 | 
			
		||||
    belongs_to :group
 | 
			
		||||
 | 
			
		||||
    alias_attribute :secret_value, :value
 | 
			
		||||
 | 
			
		||||
    validates :key, uniqueness: {
 | 
			
		||||
      scope: :group_id,
 | 
			
		||||
      message: "(%{value}) has already been taken"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,7 @@
 | 
			
		|||
module Ci
 | 
			
		||||
  class JobArtifact < ActiveRecord::Base
 | 
			
		||||
    include AfterCommitQueue
 | 
			
		||||
    include ObjectStorage::BackgroundMove
 | 
			
		||||
    extend Gitlab::Ci::Model
 | 
			
		||||
 | 
			
		||||
    belongs_to :project
 | 
			
		||||
| 
						 | 
				
			
			@ -7,9 +9,11 @@ module Ci
 | 
			
		|||
 | 
			
		||||
    before_save :set_size, if: :file_changed?
 | 
			
		||||
 | 
			
		||||
    scope :with_files_stored_locally, -> { where(file_store: [nil, ::JobArtifactUploader::Store::LOCAL]) }
 | 
			
		||||
 | 
			
		||||
    mount_uploader :file, JobArtifactUploader
 | 
			
		||||
 | 
			
		||||
    delegate :open, :exists?, to: :file
 | 
			
		||||
    delegate :exists?, :open, to: :file
 | 
			
		||||
 | 
			
		||||
    enum file_type: {
 | 
			
		||||
      archive: 1,
 | 
			
		||||
| 
						 | 
				
			
			@ -21,6 +25,10 @@ module Ci
 | 
			
		|||
      self.where(project: project).sum(:size)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def local_store?
 | 
			
		||||
      [nil, ::JobArtifactUploader::Store::LOCAL].include?(self.file_store)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def set_size
 | 
			
		||||
      self.size = file.size
 | 
			
		||||
    end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@ module Ci
 | 
			
		|||
    include AfterCommitQueue
 | 
			
		||||
    include Presentable
 | 
			
		||||
    include Gitlab::OptimisticLocking
 | 
			
		||||
    include Gitlab::Utils::StrongMemoize
 | 
			
		||||
 | 
			
		||||
    belongs_to :project, inverse_of: :pipelines
 | 
			
		||||
    belongs_to :user
 | 
			
		||||
| 
						 | 
				
			
			@ -14,7 +15,7 @@ module Ci
 | 
			
		|||
 | 
			
		||||
    has_many :stages
 | 
			
		||||
    has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline
 | 
			
		||||
    has_many :builds, foreign_key: :commit_id
 | 
			
		||||
    has_many :builds, foreign_key: :commit_id, inverse_of: :pipeline
 | 
			
		||||
    has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id # rubocop:disable Cop/ActiveRecordDependent
 | 
			
		||||
    has_many :variables, class_name: 'Ci::PipelineVariable'
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -361,21 +362,23 @@ module Ci
 | 
			
		|||
    def stage_seeds
 | 
			
		||||
      return [] unless config_processor
 | 
			
		||||
 | 
			
		||||
      @stage_seeds ||= config_processor.stage_seeds(self)
 | 
			
		||||
      strong_memoize(:stage_seeds) do
 | 
			
		||||
        seeds = config_processor.stages_attributes.map do |attributes|
 | 
			
		||||
          Gitlab::Ci::Pipeline::Seed::Stage.new(self, attributes)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        seeds.select(&:included?)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def seeds_size
 | 
			
		||||
      @seeds_size ||= stage_seeds.sum(&:size)
 | 
			
		||||
      stage_seeds.sum(&:size)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def has_kubernetes_active?
 | 
			
		||||
      project.deployment_platform&.active?
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def has_stage_seeds?
 | 
			
		||||
      stage_seeds.any?
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def has_warnings?
 | 
			
		||||
      builds.latest.failed_but_allowed.any?
 | 
			
		||||
    end
 | 
			
		||||
| 
						 | 
				
			
			@ -388,6 +391,9 @@ module Ci
 | 
			
		|||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    ##
 | 
			
		||||
    # TODO, setting yaml_errors should be moved to the pipeline creation chain.
 | 
			
		||||
    #
 | 
			
		||||
    def config_processor
 | 
			
		||||
      return unless ci_yaml_file
 | 
			
		||||
      return @config_processor if defined?(@config_processor)
 | 
			
		||||
| 
						 | 
				
			
			@ -472,6 +478,14 @@ module Ci
 | 
			
		|||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def protected_ref?
 | 
			
		||||
      strong_memoize(:protected_ref) { project.protected_for?(ref) }
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def legacy_trigger
 | 
			
		||||
      strong_memoize(:legacy_trigger) { trigger_requests.first }
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def predefined_variables
 | 
			
		||||
      Gitlab::Ci::Variables::Collection.new
 | 
			
		||||
        .append(key: 'CI_PIPELINE_ID', value: id.to_s)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,8 @@ module Ci
 | 
			
		|||
 | 
			
		||||
    belongs_to :pipeline_schedule
 | 
			
		||||
 | 
			
		||||
    alias_attribute :secret_value, :value
 | 
			
		||||
 | 
			
		||||
    validates :key, uniqueness: { scope: :pipeline_schedule_id }
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,8 @@ module Ci
 | 
			
		|||
 | 
			
		||||
    belongs_to :project
 | 
			
		||||
 | 
			
		||||
    alias_attribute :secret_value, :value
 | 
			
		||||
 | 
			
		||||
    validates :key, uniqueness: {
 | 
			
		||||
      scope: [:project_id, :environment_scope],
 | 
			
		||||
      message: "(%{value}) has already been taken"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,7 @@ module Clusters
 | 
			
		|||
      Applications::Prometheus.application_name => Applications::Prometheus,
 | 
			
		||||
      Applications::Runner.application_name => Applications::Runner
 | 
			
		||||
    }.freeze
 | 
			
		||||
    DEFAULT_ENVIRONMENT = '*'.freeze
 | 
			
		||||
 | 
			
		||||
    belongs_to :user
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -50,6 +51,7 @@ module Clusters
 | 
			
		|||
 | 
			
		||||
    scope :enabled, -> { where(enabled: true) }
 | 
			
		||||
    scope :disabled, -> { where(enabled: false) }
 | 
			
		||||
    scope :default_environment, -> { where(environment_scope: DEFAULT_ENVIRONMENT) }
 | 
			
		||||
 | 
			
		||||
    def status_name
 | 
			
		||||
      if provider
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -175,7 +175,7 @@ class Commit
 | 
			
		|||
      if safe_message.blank?
 | 
			
		||||
        no_commit_message
 | 
			
		||||
      else
 | 
			
		||||
        safe_message.split("\n", 2).first
 | 
			
		||||
        safe_message.split(/[\r\n]/, 2).first
 | 
			
		||||
      end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,7 @@ module Avatarable
 | 
			
		|||
 | 
			
		||||
  included do
 | 
			
		||||
    prepend ShadowMethods
 | 
			
		||||
    include ObjectStorage::BackgroundMove
 | 
			
		||||
 | 
			
		||||
    validate :avatar_type, if: ->(user) { user.avatar.present? && user.avatar_changed? }
 | 
			
		||||
    validates :avatar, file_size: { maximum: 200.kilobytes.to_i }
 | 
			
		||||
| 
						 | 
				
			
			@ -21,7 +22,7 @@ module Avatarable
 | 
			
		|||
 | 
			
		||||
  def avatar_type
 | 
			
		||||
    unless self.avatar.image?
 | 
			
		||||
      self.errors.add :avatar, "only images allowed"
 | 
			
		||||
      errors.add :avatar, "file format is not supported. Please try one of the following supported formats: #{AvatarUploader::IMAGE_EXT.join(', ')}"
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,16 +1,24 @@
 | 
			
		|||
module DeploymentPlatform
 | 
			
		||||
  # EE would override this and utilize the extra argument
 | 
			
		||||
  # EE would override this and utilize environment argument
 | 
			
		||||
  # rubocop:disable Gitlab/ModuleWithInstanceVariables
 | 
			
		||||
  def deployment_platform(environment: nil)
 | 
			
		||||
    @deployment_platform ||=
 | 
			
		||||
      find_cluster_platform_kubernetes ||
 | 
			
		||||
      find_kubernetes_service_integration ||
 | 
			
		||||
      build_cluster_and_deployment_platform
 | 
			
		||||
    @deployment_platform ||= {}
 | 
			
		||||
 | 
			
		||||
    @deployment_platform[environment] ||= find_deployment_platform(environment)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def find_cluster_platform_kubernetes
 | 
			
		||||
    clusters.find_by(enabled: true)&.platform_kubernetes
 | 
			
		||||
  def find_deployment_platform(environment)
 | 
			
		||||
    find_cluster_platform_kubernetes(environment: environment) ||
 | 
			
		||||
      find_kubernetes_service_integration ||
 | 
			
		||||
      build_cluster_and_deployment_platform
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # EE would override this and utilize environment argument
 | 
			
		||||
  def find_cluster_platform_kubernetes(environment: nil)
 | 
			
		||||
    clusters.enabled.default_environment
 | 
			
		||||
      .last&.platform_kubernetes
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def find_kubernetes_service_integration
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -52,12 +52,12 @@ class Event < ActiveRecord::Base
 | 
			
		|||
  belongs_to :target, -> {
 | 
			
		||||
    # If the association for "target" defines an "author" association we want to
 | 
			
		||||
    # eager-load this so Banzai & friends don't end up performing N+1 queries to
 | 
			
		||||
    # get the authors of notes, issues, etc.
 | 
			
		||||
    if reflections['events'].active_record.reflect_on_association(:author)
 | 
			
		||||
      includes(:author)
 | 
			
		||||
    else
 | 
			
		||||
      self
 | 
			
		||||
    # get the authors of notes, issues, etc. (likewise for "noteable").
 | 
			
		||||
    incs = %i(author noteable).select do |a|
 | 
			
		||||
      reflections['events'].active_record.reflect_on_association(a)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    incs.reduce(self) { |obj, a| obj.includes(a) }
 | 
			
		||||
  }, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
 | 
			
		||||
 | 
			
		||||
  has_one :push_event_payload
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -189,12 +189,6 @@ class Group < Namespace
 | 
			
		|||
    owners.include?(user) && owners.size == 1
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def avatar_type
 | 
			
		||||
    unless self.avatar.image?
 | 
			
		||||
      self.errors.add :avatar, "only images allowed"
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def post_create_hook
 | 
			
		||||
    Gitlab::AppLogger.info("Group \"#{name}\" was created")
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,12 @@
 | 
			
		|||
class LfsObject < ActiveRecord::Base
 | 
			
		||||
  include AfterCommitQueue
 | 
			
		||||
  include ObjectStorage::BackgroundMove
 | 
			
		||||
 | 
			
		||||
  has_many :lfs_objects_projects, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
 | 
			
		||||
  has_many :projects, through: :lfs_objects_projects
 | 
			
		||||
 | 
			
		||||
  scope :with_files_stored_locally, -> { where(file_store: [nil, LfsObjectUploader::Store::LOCAL]) }
 | 
			
		||||
 | 
			
		||||
  validates :oid, presence: true, uniqueness: true
 | 
			
		||||
 | 
			
		||||
  mount_uploader :file, LfsObjectUploader
 | 
			
		||||
| 
						 | 
				
			
			@ -10,6 +15,10 @@ class LfsObject < ActiveRecord::Base
 | 
			
		|||
    projects.exists?(project.lfs_storage_project.id)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def local_store?
 | 
			
		||||
    [nil, LfsObjectUploader::Store::LOCAL].include?(self.file_store)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def self.destroy_unreferenced
 | 
			
		||||
    joins("LEFT JOIN lfs_objects_projects ON lfs_objects_projects.lfs_object_id = #{table_name}.id")
 | 
			
		||||
        .where(lfs_objects_projects: { id: nil })
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,7 +48,7 @@ class NotificationRecipient
 | 
			
		|||
    when :custom
 | 
			
		||||
      custom_enabled? || %i[participating mention].include?(@type)
 | 
			
		||||
    when :watch, :participating
 | 
			
		||||
      !excluded_watcher_action?
 | 
			
		||||
      !action_excluded?
 | 
			
		||||
    when :mention
 | 
			
		||||
      @type == :mention
 | 
			
		||||
    else
 | 
			
		||||
| 
						 | 
				
			
			@ -96,13 +96,22 @@ class NotificationRecipient
 | 
			
		|||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def action_excluded?
 | 
			
		||||
    excluded_watcher_action? || excluded_participating_action?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def excluded_watcher_action?
 | 
			
		||||
    return false unless @custom_action
 | 
			
		||||
    return false if notification_level == :custom
 | 
			
		||||
    return false unless @custom_action && notification_level == :watch
 | 
			
		||||
 | 
			
		||||
    NotificationSetting::EXCLUDED_WATCHER_EVENTS.include?(@custom_action)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def excluded_participating_action?
 | 
			
		||||
    return false unless @custom_action && notification_level == :participating
 | 
			
		||||
 | 
			
		||||
    NotificationSetting::EXCLUDED_PARTICIPATING_EVENTS.include?(@custom_action)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def read_ability
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,6 +33,7 @@ class NotificationSetting < ActiveRecord::Base
 | 
			
		|||
    :close_issue,
 | 
			
		||||
    :reassign_issue,
 | 
			
		||||
    :new_merge_request,
 | 
			
		||||
    :push_to_merge_request,
 | 
			
		||||
    :reopen_merge_request,
 | 
			
		||||
    :close_merge_request,
 | 
			
		||||
    :reassign_merge_request,
 | 
			
		||||
| 
						 | 
				
			
			@ -41,10 +42,14 @@ class NotificationSetting < ActiveRecord::Base
 | 
			
		|||
    :success_pipeline
 | 
			
		||||
  ].freeze
 | 
			
		||||
 | 
			
		||||
  EXCLUDED_WATCHER_EVENTS = [
 | 
			
		||||
  EXCLUDED_PARTICIPATING_EVENTS = [
 | 
			
		||||
    :success_pipeline
 | 
			
		||||
  ].freeze
 | 
			
		||||
 | 
			
		||||
  EXCLUDED_WATCHER_EVENTS = [
 | 
			
		||||
    :push_to_merge_request
 | 
			
		||||
  ].push(*EXCLUDED_PARTICIPATING_EVENTS).freeze
 | 
			
		||||
 | 
			
		||||
  def self.find_or_create_for(source)
 | 
			
		||||
    setting = find_or_initialize_by(source: source)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,8 +6,10 @@ class PagesDomain < ActiveRecord::Base
 | 
			
		|||
 | 
			
		||||
  validates :domain, hostname: { allow_numeric_hostname: true }
 | 
			
		||||
  validates :domain, uniqueness: { case_sensitive: false }
 | 
			
		||||
  validates :certificate, certificate: true, allow_nil: true, allow_blank: true
 | 
			
		||||
  validates :key, certificate_key: true, allow_nil: true, allow_blank: true
 | 
			
		||||
  validates :certificate, presence: { message: 'must be present if HTTPS-only is enabled' }, if: ->(domain) { domain.project&.pages_https_only? }
 | 
			
		||||
  validates :certificate, certificate: true, if: ->(domain) { domain.certificate.present? }
 | 
			
		||||
  validates :key, presence: { message: 'must be present if HTTPS-only is enabled' }, if: ->(domain) { domain.project&.pages_https_only? }
 | 
			
		||||
  validates :key, certificate_key: true, if: ->(domain) { domain.key.present? }
 | 
			
		||||
  validates :verification_code, presence: true, allow_blank: false
 | 
			
		||||
 | 
			
		||||
  validate :validate_pages_domain
 | 
			
		||||
| 
						 | 
				
			
			@ -46,6 +48,10 @@ class PagesDomain < ActiveRecord::Base
 | 
			
		|||
    !Gitlab::CurrentSettings.pages_domain_verification_enabled? || enabled_until.present?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def https?
 | 
			
		||||
    certificate.present?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def to_param
 | 
			
		||||
    domain
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,6 +38,9 @@ class Project < ActiveRecord::Base
 | 
			
		|||
    attachments: 2
 | 
			
		||||
  }.freeze
 | 
			
		||||
 | 
			
		||||
  # Valids ports to import from
 | 
			
		||||
  VALID_IMPORT_PORTS = [22, 80, 443].freeze
 | 
			
		||||
 | 
			
		||||
  cache_markdown_field :description, pipeline: :description
 | 
			
		||||
 | 
			
		||||
  delegate :feature_available?, :builds_enabled?, :wiki_enabled?,
 | 
			
		||||
| 
						 | 
				
			
			@ -264,6 +267,7 @@ class Project < ActiveRecord::Base
 | 
			
		|||
  validate :visibility_level_allowed_by_group
 | 
			
		||||
  validate :visibility_level_allowed_as_fork
 | 
			
		||||
  validate :check_wiki_path_conflict
 | 
			
		||||
  validate :validate_pages_https_only, if: -> { changes.has_key?(:pages_https_only) }
 | 
			
		||||
  validates :repository_storage,
 | 
			
		||||
    presence: true,
 | 
			
		||||
    inclusion: { in: ->(_object) { Gitlab.config.repositories.storages.keys } }
 | 
			
		||||
| 
						 | 
				
			
			@ -500,7 +504,7 @@ class Project < ActiveRecord::Base
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def repository_storage_path
 | 
			
		||||
    Gitlab.config.repositories.storages[repository_storage].try(:[], 'path')
 | 
			
		||||
    Gitlab.config.repositories.storages[repository_storage]&.legacy_disk_path
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def team
 | 
			
		||||
| 
						 | 
				
			
			@ -734,6 +738,26 @@ class Project < ActiveRecord::Base
 | 
			
		|||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def pages_https_only
 | 
			
		||||
    return false unless Gitlab.config.pages.external_https
 | 
			
		||||
 | 
			
		||||
    super
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def pages_https_only?
 | 
			
		||||
    return false unless Gitlab.config.pages.external_https
 | 
			
		||||
 | 
			
		||||
    super
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def validate_pages_https_only
 | 
			
		||||
    return unless pages_https_only?
 | 
			
		||||
 | 
			
		||||
    unless pages_domains.all?(&:https?)
 | 
			
		||||
      errors.add(:pages_https_only, "cannot be enabled unless all domains have TLS certificates")
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def to_param
 | 
			
		||||
    if persisted? && errors.include?(:path)
 | 
			
		||||
      path_was
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,4 @@
 | 
			
		|||
class AssemblaService < Service
 | 
			
		||||
  include HTTParty
 | 
			
		||||
 | 
			
		||||
  prop_accessor :token, :subdomain
 | 
			
		||||
  validates :token, presence: true, if: :activated?
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -31,6 +29,6 @@ class AssemblaService < Service
 | 
			
		|||
    return unless supported_events.include?(data[:object_kind])
 | 
			
		||||
 | 
			
		||||
    url = "https://atlas.assembla.com/spaces/#{subdomain}/github_tool?secret_key=#{token}"
 | 
			
		||||
    AssemblaService.post(url, body: { payload: data }.to_json, headers: { 'Content-Type' => 'application/json' })
 | 
			
		||||
    Gitlab::HTTP.post(url, body: { payload: data }.to_json, headers: { 'Content-Type' => 'application/json' })
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -117,14 +117,14 @@ class BambooService < CiService
 | 
			
		|||
    url = build_url(path)
 | 
			
		||||
 | 
			
		||||
    if username.blank? && password.blank?
 | 
			
		||||
      HTTParty.get(url, verify: false)
 | 
			
		||||
      Gitlab::HTTP.get(url, verify: false)
 | 
			
		||||
    else
 | 
			
		||||
      url << '&os_authType=basic'
 | 
			
		||||
      HTTParty.get(url, verify: false,
 | 
			
		||||
                        basic_auth: {
 | 
			
		||||
                          username: username,
 | 
			
		||||
                          password: password
 | 
			
		||||
                        })
 | 
			
		||||
      Gitlab::HTTP.get(url, verify: false,
 | 
			
		||||
                            basic_auth: {
 | 
			
		||||
                              username: username,
 | 
			
		||||
                              password: password
 | 
			
		||||
                            })
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -71,7 +71,7 @@ class BuildkiteService < CiService
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def calculate_reactive_cache(sha, ref)
 | 
			
		||||
    response = HTTParty.get(commit_status_path(sha), verify: false)
 | 
			
		||||
    response = Gitlab::HTTP.get(commit_status_path(sha), verify: false)
 | 
			
		||||
 | 
			
		||||
    status =
 | 
			
		||||
      if response.code == 200 && response['status']
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,4 @@
 | 
			
		|||
class CampfireService < Service
 | 
			
		||||
  include HTTParty
 | 
			
		||||
 | 
			
		||||
  prop_accessor :token, :subdomain, :room
 | 
			
		||||
  validates :token, presence: true, if: :activated?
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -31,7 +29,6 @@ class CampfireService < Service
 | 
			
		|||
  def execute(data)
 | 
			
		||||
    return unless supported_events.include?(data[:object_kind])
 | 
			
		||||
 | 
			
		||||
    self.class.base_uri base_uri
 | 
			
		||||
    message = build_message(data)
 | 
			
		||||
    speak(self.room, message, auth)
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			@ -69,14 +66,14 @@ class CampfireService < Service
 | 
			
		|||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    res = self.class.post(path, auth.merge(body))
 | 
			
		||||
    res = Gitlab::HTTP.post(path, base_uri: base_uri, **auth.merge(body))
 | 
			
		||||
    res.code == 201 ? res : nil
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Returns a list of rooms, or [].
 | 
			
		||||
  # https://github.com/basecamp/campfire-api/blob/master/sections/rooms.md#get-rooms
 | 
			
		||||
  def rooms(auth)
 | 
			
		||||
    res = self.class.get("/rooms.json", auth)
 | 
			
		||||
    res = Gitlab::HTTP.get("/rooms.json", base_uri: base_uri, **auth)
 | 
			
		||||
    res.code == 200 ? res["rooms"] : []
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,7 +49,7 @@ class DroneCiService < CiService
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def calculate_reactive_cache(sha, ref)
 | 
			
		||||
    response = HTTParty.get(commit_status_path(sha, ref), verify: enable_ssl_verification)
 | 
			
		||||
    response = Gitlab::HTTP.get(commit_status_path(sha, ref), verify: enable_ssl_verification)
 | 
			
		||||
 | 
			
		||||
    status =
 | 
			
		||||
      if response.code == 200 && response['status']
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,4 @@
 | 
			
		|||
class ExternalWikiService < Service
 | 
			
		||||
  include HTTParty
 | 
			
		||||
 | 
			
		||||
  prop_accessor :external_wiki_url
 | 
			
		||||
 | 
			
		||||
  validates :external_wiki_url, presence: true, url: true, if: :activated?
 | 
			
		||||
| 
						 | 
				
			
			@ -24,7 +22,7 @@ class ExternalWikiService < Service
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def execute(_data)
 | 
			
		||||
    @response = HTTParty.get(properties['external_wiki_url'], verify: true) rescue nil
 | 
			
		||||
    @response = Gitlab::HTTP.get(properties['external_wiki_url'], verify: true) rescue nil
 | 
			
		||||
    if @response != 200
 | 
			
		||||
      nil
 | 
			
		||||
    end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -77,13 +77,13 @@ class IssueTrackerService < Service
 | 
			
		|||
    result = false
 | 
			
		||||
 | 
			
		||||
    begin
 | 
			
		||||
      response = HTTParty.head(self.project_url, verify: true)
 | 
			
		||||
      response = Gitlab::HTTP.head(self.project_url, verify: true)
 | 
			
		||||
 | 
			
		||||
      if response
 | 
			
		||||
        message = "#{self.type} received response #{response.code} when attempting to connect to #{self.project_url}"
 | 
			
		||||
        result = true
 | 
			
		||||
      end
 | 
			
		||||
    rescue HTTParty::Error, Timeout::Error, SocketError, Errno::ECONNRESET, Errno::ECONNREFUSED, OpenSSL::SSL::SSLError => error
 | 
			
		||||
    rescue Gitlab::HTTP::Error, Timeout::Error, SocketError, Errno::ECONNRESET, Errno::ECONNREFUSED, OpenSSL::SSL::SSLError => error
 | 
			
		||||
      message = "#{self.type} had an error when trying to connect to #{self.project_url}: #{error.message}"
 | 
			
		||||
    end
 | 
			
		||||
    Rails.logger.info(message)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -52,7 +52,7 @@ class MockCiService < CiService
 | 
			
		|||
  #
 | 
			
		||||
  #
 | 
			
		||||
  def commit_status(sha, ref)
 | 
			
		||||
    response = HTTParty.get(commit_status_path(sha), verify: false)
 | 
			
		||||
    response = Gitlab::HTTP.get(commit_status_path(sha), verify: false)
 | 
			
		||||
    read_commit_status(response)
 | 
			
		||||
  rescue Errno::ECONNREFUSED
 | 
			
		||||
    :error
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,4 @@
 | 
			
		|||
class PackagistService < Service
 | 
			
		||||
  include HTTParty
 | 
			
		||||
 | 
			
		||||
  prop_accessor :username, :token, :server
 | 
			
		||||
 | 
			
		||||
  validates :username, presence: true, if: :activated?
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,4 @@
 | 
			
		|||
class PivotaltrackerService < Service
 | 
			
		||||
  include HTTParty
 | 
			
		||||
 | 
			
		||||
  API_ENDPOINT = 'https://www.pivotaltracker.com/services/v5/source_commits'.freeze
 | 
			
		||||
 | 
			
		||||
  prop_accessor :token, :restrict_to_branch
 | 
			
		||||
| 
						 | 
				
			
			@ -52,7 +50,7 @@ class PivotaltrackerService < Service
 | 
			
		|||
          'message' => commit[:message]
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      PivotaltrackerService.post(
 | 
			
		||||
      Gitlab::HTTP.post(
 | 
			
		||||
        API_ENDPOINT,
 | 
			
		||||
        body: message.to_json,
 | 
			
		||||
        headers: {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,5 @@
 | 
			
		|||
class PushoverService < Service
 | 
			
		||||
  include HTTParty
 | 
			
		||||
  base_uri 'https://api.pushover.net/1'
 | 
			
		||||
  BASE_URI = 'https://api.pushover.net/1'.freeze
 | 
			
		||||
 | 
			
		||||
  prop_accessor :api_key, :user_key, :device, :priority, :sound
 | 
			
		||||
  validates :api_key, :user_key, :priority, presence: true, if: :activated?
 | 
			
		||||
| 
						 | 
				
			
			@ -99,6 +98,6 @@ class PushoverService < Service
 | 
			
		|||
      pushover_data[:sound] = sound
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    PushoverService.post('/messages.json', body: pushover_data)
 | 
			
		||||
    Gitlab::HTTP.post('/messages.json', base_uri: BASE_URI, body: pushover_data)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -83,7 +83,7 @@ class TeamcityService < CiService
 | 
			
		|||
 | 
			
		||||
    branch = Gitlab::Git.ref_name(data[:ref])
 | 
			
		||||
 | 
			
		||||
    HTTParty.post(
 | 
			
		||||
    Gitlab::HTTP.post(
 | 
			
		||||
      build_url('httpAuth/app/rest/buildQueue'),
 | 
			
		||||
      body: "<build branchName=\"#{branch}\">"\
 | 
			
		||||
            "<buildType id=\"#{build_type}\"/>"\
 | 
			
		||||
| 
						 | 
				
			
			@ -134,10 +134,10 @@ class TeamcityService < CiService
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def get_path(path)
 | 
			
		||||
    HTTParty.get(build_url(path), verify: false,
 | 
			
		||||
                                  basic_auth: {
 | 
			
		||||
                                    username: username,
 | 
			
		||||
                                    password: password
 | 
			
		||||
                                  })
 | 
			
		||||
    Gitlab::HTTP.get(build_url(path), verify: false,
 | 
			
		||||
                                      basic_auth: {
 | 
			
		||||
                                        username: username,
 | 
			
		||||
                                        password: password
 | 
			
		||||
                                      })
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,8 @@ class Upload < ActiveRecord::Base
 | 
			
		|||
  validates :model, presence: true
 | 
			
		||||
  validates :uploader, presence: true
 | 
			
		||||
 | 
			
		||||
  scope :with_files_stored_locally, -> { where(store: [nil, ObjectStorage::Store::LOCAL]) }
 | 
			
		||||
 | 
			
		||||
  before_save  :calculate_checksum!, if: :foreground_checksummable?
 | 
			
		||||
  after_commit :schedule_checksum,   if: :checksummable?
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -21,6 +23,7 @@ class Upload < ActiveRecord::Base
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def absolute_path
 | 
			
		||||
    raise ObjectStorage::RemoteStoreError, "Remote object has no absolute path." unless local?
 | 
			
		||||
    return path unless relative_path?
 | 
			
		||||
 | 
			
		||||
    uploader_class.absolute_path(self)
 | 
			
		||||
| 
						 | 
				
			
			@ -30,11 +33,11 @@ class Upload < ActiveRecord::Base
 | 
			
		|||
    self.checksum = nil
 | 
			
		||||
    return unless checksummable?
 | 
			
		||||
 | 
			
		||||
    self.checksum = self.class.hexdigest(absolute_path)
 | 
			
		||||
    self.checksum = Digest::SHA256.file(absolute_path).hexdigest
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def build_uploader
 | 
			
		||||
    uploader_class.new(model, mount_point, **uploader_context).tap do |uploader|
 | 
			
		||||
  def build_uploader(mounted_as = nil)
 | 
			
		||||
    uploader_class.new(model, mounted_as || mount_point).tap do |uploader|
 | 
			
		||||
      uploader.upload = self
 | 
			
		||||
      uploader.retrieve_from_store!(identifier)
 | 
			
		||||
    end
 | 
			
		||||
| 
						 | 
				
			
			@ -51,6 +54,12 @@ class Upload < ActiveRecord::Base
 | 
			
		|||
    }.compact
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def local?
 | 
			
		||||
    return true if store.nil?
 | 
			
		||||
 | 
			
		||||
    store == ObjectStorage::Store::LOCAL
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def delete_file!
 | 
			
		||||
| 
						 | 
				
			
			@ -61,10 +70,6 @@ class Upload < ActiveRecord::Base
 | 
			
		|||
    checksum.nil? && local? && exist?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def local?
 | 
			
		||||
    true
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def foreground_checksummable?
 | 
			
		||||
    checksummable? && size <= CHECKSUM_THRESHOLD
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -623,9 +623,7 @@ class User < ActiveRecord::Base
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def owned_projects
 | 
			
		||||
    @owned_projects ||=
 | 
			
		||||
      Project.where('namespace_id IN (?) OR namespace_id = ?',
 | 
			
		||||
                    owned_groups.select(:id), namespace.id).joins(:namespace)
 | 
			
		||||
    @owned_projects ||= Project.from("(#{owned_projects_union.to_sql}) AS projects")
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # Returns projects which user can admin issues on (for example to move an issue to that project).
 | 
			
		||||
| 
						 | 
				
			
			@ -1196,6 +1194,15 @@ class User < ActiveRecord::Base
 | 
			
		|||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def owned_projects_union
 | 
			
		||||
    Gitlab::SQL::Union.new([
 | 
			
		||||
      Project.where(namespace: namespace),
 | 
			
		||||
      Project.joins(:project_authorizations)
 | 
			
		||||
        .where("projects.namespace_id <> ?", namespace.id)
 | 
			
		||||
        .where(project_authorizations: { user_id: id, access_level: Gitlab::Access::OWNER })
 | 
			
		||||
    ], remove_duplicates: false)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def ci_projects_union
 | 
			
		||||
    scope  = { access_level: [Gitlab::Access::MASTER, Gitlab::Access::OWNER] }
 | 
			
		||||
    groups = groups_projects.where(members: scope)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,7 @@ module Ci
 | 
			
		|||
                Gitlab::Ci::Pipeline::Chain::Validate::Repository,
 | 
			
		||||
                Gitlab::Ci::Pipeline::Chain::Validate::Config,
 | 
			
		||||
                Gitlab::Ci::Pipeline::Chain::Skip,
 | 
			
		||||
                Gitlab::Ci::Pipeline::Chain::Populate,
 | 
			
		||||
                Gitlab::Ci::Pipeline::Chain::Create].freeze
 | 
			
		||||
 | 
			
		||||
    def execute(source, ignore_skip_ci: false, save_on_errors: true, trigger_request: nil, schedule: nil, &block)
 | 
			
		||||
| 
						 | 
				
			
			@ -65,7 +66,7 @@ module Ci
 | 
			
		|||
      project.pipelines
 | 
			
		||||
        .where(ref: pipeline.ref)
 | 
			
		||||
        .where.not(id: pipeline.id)
 | 
			
		||||
        .where.not(sha: project.repository.sha_from_ref(pipeline.ref))
 | 
			
		||||
        .where.not(sha: project.commit(pipeline.ref).try(:id))
 | 
			
		||||
        .created_or_pending
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,20 +0,0 @@
 | 
			
		|||
module Ci
 | 
			
		||||
  class CreatePipelineStagesService < BaseService
 | 
			
		||||
    def execute(pipeline)
 | 
			
		||||
      pipeline.stage_seeds.each do |seed|
 | 
			
		||||
        seed.user = current_user
 | 
			
		||||
 | 
			
		||||
        seed.create! do |build|
 | 
			
		||||
          ##
 | 
			
		||||
          # Create the environment before the build starts. This sets its slug and
 | 
			
		||||
          # makes it available as an environment variable
 | 
			
		||||
          #
 | 
			
		||||
          if build.has_environment?
 | 
			
		||||
            environment_name = build.expanded_environment_name
 | 
			
		||||
            project.environments.find_or_create_by(name: environment_name)
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -16,8 +16,8 @@ module Ci
 | 
			
		|||
 | 
			
		||||
      pipeline = Ci::CreatePipelineService.new(project, trigger.owner, ref: params[:ref])
 | 
			
		||||
        .execute(:trigger, ignore_skip_ci: true) do |pipeline|
 | 
			
		||||
          pipeline.trigger_requests.create!(trigger: trigger)
 | 
			
		||||
          create_pipeline_variables!(pipeline)
 | 
			
		||||
          pipeline.trigger_requests.build(trigger: trigger)
 | 
			
		||||
          pipeline.variables.build(variables)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
      if pipeline.persisted?
 | 
			
		||||
| 
						 | 
				
			
			@ -33,14 +33,10 @@ module Ci
 | 
			
		|||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def create_pipeline_variables!(pipeline)
 | 
			
		||||
      return unless params[:variables]
 | 
			
		||||
 | 
			
		||||
      variables = params[:variables].map do |key, value|
 | 
			
		||||
    def variables
 | 
			
		||||
      params[:variables].to_h.map do |key, value|
 | 
			
		||||
        { key: key, value: value }
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      pipeline.variables.create!(variables)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,7 @@ module MergeRequests
 | 
			
		|||
        comment_mr_branch_presence_changed
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      comment_mr_with_commits
 | 
			
		||||
      notify_about_push
 | 
			
		||||
      mark_mr_as_wip_from_commits
 | 
			
		||||
      execute_mr_web_hooks
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -141,8 +141,8 @@ module MergeRequests
 | 
			
		|||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    # Add comment about pushing new commits to merge requests
 | 
			
		||||
    def comment_mr_with_commits
 | 
			
		||||
    # Add comment about pushing new commits to merge requests and send nofitication emails
 | 
			
		||||
    def notify_about_push
 | 
			
		||||
      return unless @commits.present?
 | 
			
		||||
 | 
			
		||||
      merge_requests_for_source_branch.each do |merge_request|
 | 
			
		||||
| 
						 | 
				
			
			@ -155,6 +155,8 @@ module MergeRequests
 | 
			
		|||
        SystemNoteService.add_commits(merge_request, merge_request.project,
 | 
			
		||||
                                      @current_user, new_commits,
 | 
			
		||||
                                      existing_commits, @oldrev)
 | 
			
		||||
 | 
			
		||||
        notification_service.push_to_merge_request(merge_request, @current_user, new_commits: new_commits, existing_commits: existing_commits)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -113,6 +113,16 @@ class NotificationService
 | 
			
		|||
    new_resource_email(merge_request, :new_merge_request_email)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def push_to_merge_request(merge_request, current_user, new_commits: [], existing_commits: [])
 | 
			
		||||
    new_commits = new_commits.map { |c| { short_id: c.short_id, title: c.title } }
 | 
			
		||||
    existing_commits = existing_commits.map { |c| { short_id: c.short_id, title: c.title } }
 | 
			
		||||
    recipients = NotificationRecipientService.build_recipients(merge_request, current_user, action: "push_to")
 | 
			
		||||
 | 
			
		||||
    recipients.each do |recipient|
 | 
			
		||||
      mailer.send(:push_to_merge_request_email, recipient.user.id, merge_request.id, current_user.id, recipient.reason, new_commits: new_commits, existing_commits: existing_commits).deliver_later
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  # When merge request text is updated, we should send an email to:
 | 
			
		||||
  #
 | 
			
		||||
  #  * newly mentioned project team members with notification level higher than Participating
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ module Projects
 | 
			
		|||
 | 
			
		||||
    def add_repository_to_project
 | 
			
		||||
      if project.external_import? && !unknown_url?
 | 
			
		||||
        raise Error, 'Blocked import URL.' if Gitlab::UrlBlocker.blocked_url?(project.import_url)
 | 
			
		||||
        raise Error, 'Blocked import URL.' if Gitlab::UrlBlocker.blocked_url?(project.import_url, valid_ports: Project::VALID_IMPORT_PORTS)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # We should skip the repository for a GitHub import or GitLab project import,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,8 @@ module Projects
 | 
			
		|||
 | 
			
		||||
    def pages_config
 | 
			
		||||
      {
 | 
			
		||||
        domains: pages_domains_config
 | 
			
		||||
        domains: pages_domains_config,
 | 
			
		||||
        https_only: project.pages_https_only?
 | 
			
		||||
      }
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -27,7 +28,8 @@ module Projects
 | 
			
		|||
        {
 | 
			
		||||
          domain: domain.domain,
 | 
			
		||||
          certificate: domain.certificate,
 | 
			
		||||
          key: domain.key
 | 
			
		||||
          key: domain.key,
 | 
			
		||||
          https_only: project.pages_https_only? && domain.https?
 | 
			
		||||
        }
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -81,11 +81,13 @@ module Projects
 | 
			
		|||
    end
 | 
			
		||||
 | 
			
		||||
    def extract_tar_archive!(temp_path)
 | 
			
		||||
      results = Open3.pipeline(%W(gunzip -c #{artifacts}),
 | 
			
		||||
                               %W(dd bs=#{BLOCK_SIZE} count=#{blocks}),
 | 
			
		||||
                               %W(tar -x -C #{temp_path} #{SITE_PATH}),
 | 
			
		||||
                               err: '/dev/null')
 | 
			
		||||
      raise FailedToExtractError, 'pages failed to extract' unless results.compact.all?(&:success?)
 | 
			
		||||
      build.artifacts_file.use_file do |artifacts_path|
 | 
			
		||||
        results = Open3.pipeline(%W(gunzip -c #{artifacts_path}),
 | 
			
		||||
                                %W(dd bs=#{BLOCK_SIZE} count=#{blocks}),
 | 
			
		||||
                                %W(tar -x -C #{temp_path} #{SITE_PATH}),
 | 
			
		||||
                                err: '/dev/null')
 | 
			
		||||
        raise FailedToExtractError, 'pages failed to extract' unless results.compact.all?(&:success?)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def extract_zip_archive!(temp_path)
 | 
			
		||||
| 
						 | 
				
			
			@ -103,8 +105,10 @@ module Projects
 | 
			
		|||
      # -n  never overwrite existing files
 | 
			
		||||
      # We add * to end of SITE_PATH, because we want to extract SITE_PATH and all subdirectories
 | 
			
		||||
      site_path = File.join(SITE_PATH, '*')
 | 
			
		||||
      unless system(*%W(unzip -qq -n #{artifacts} #{site_path} -d #{temp_path}))
 | 
			
		||||
        raise FailedToExtractError, 'pages failed to extract'
 | 
			
		||||
      build.artifacts_file.use_file do |artifacts_path|
 | 
			
		||||
        unless system(*%W(unzip -n #{artifacts_path} #{site_path} -d #{temp_path}))
 | 
			
		||||
          raise FailedToExtractError, 'pages failed to extract'
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,6 +24,8 @@ module Projects
 | 
			
		|||
          system_hook_service.execute_hooks_for(project, :update)
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        update_pages_config if changing_pages_https_only?
 | 
			
		||||
 | 
			
		||||
        success
 | 
			
		||||
      else
 | 
			
		||||
        model_errors = project.errors.full_messages.to_sentence
 | 
			
		||||
| 
						 | 
				
			
			@ -67,5 +69,13 @@ module Projects
 | 
			
		|||
      log_error("Could not create wiki for #{project.full_name}")
 | 
			
		||||
      Gitlab::Metrics.counter(:wiki_can_not_be_created_total, 'Counts the times we failed to create a wiki')
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def update_pages_config
 | 
			
		||||
      Projects::UpdatePagesConfigurationService.new(project).execute
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def changing_pages_https_only?
 | 
			
		||||
      project.previous_changes.include?(:pages_https_only)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue