Commit 98b294e0 authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'master' into 4310-new-components-rows

* master: (61 commits)
  Update CHANGELOG.md for 10.6.1
  Update CHANGELOG-EE.md for 10.6.1-ee
  Put forms from expandable sections into fieldset to ensure proper animation
  Remove gray background from app setting expandable sections
  Improve application settings page according to feedback
  Fix failing spec in ee/spec/controllers/projects/variables_controller_spec.rb
  Prevent unnecessary, excessive updates
  Re-arrange deployment_platform to avoid cop complainments
  Make #base_pipeline returning the latest available pipeline for MR's base commit
  fix conflict
  Bump `state_machines-activerecord` to `0.5.1`
  Docs organize main page by product category
  ProtectedBranch API omits empty declared params
  Fix deployment_platform not memoizing values in correct way
  Move UI of several application settings to expandable block
  add SHA1 fingerprint requirement
  Make stage seed instance variables less ambiguous
  Remove outdates TODOs from pipeline class
  Remove N+1 query for Noteable association.
  Disable cursor for review mode in the IDE
  ...
parents 7bed22b0 1aec54db
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
## 10.6.1 (2018-03-27)
### Fixed (8 changes)
- Fix LDAP group sync permission override UI. !5003
- Hard failing a mirror no longer fails for a blocked user's personal project. !5063
- Geo - Avoid rescheduling the same project again in a backfill condition. !5069
- Mark disabled wikis as fully synced. !5104
- Fix excessive updates to file_registry when wiki is disabled. !5119
- Geo: Recovery from temporary directory doesn't work if the namespace directory doesn't exist.
- Define a chat responder for the Slack app.
- Resolve "undefined method 'log_transfer_error'".
### Added (1 change)
- Also log Geo Prometheus metrics from primary. !5058
### Other (1 change)
- Update Epic documentation to include labels.
## 10.6.0 (2018-03-22) ## 10.6.0 (2018-03-22)
### Security (2 changes) ### Security (2 changes)
......
...@@ -2,6 +2,27 @@ ...@@ -2,6 +2,27 @@
documentation](doc/development/changelog.md) for instructions on adding your own documentation](doc/development/changelog.md) for instructions on adding your own
entry. entry.
## 10.6.1 (2018-03-27)
### Security (1 change)
- Bump rails-html-sanitizer to 1.0.4.
### Fixed (3 changes)
- Prevent auto-retry AccessDenied error from stopping transition to failed. !17862
- Fix 500 error when trying to resolve non-ASCII conflicts in the editor. !17962
- Don't capture trailing punctuation when autolinking. !17965
### Performance (1 change)
- Add indexes for user activity queries. !17890
### Other (1 change)
- Add documentation for runner IP address (#44232). !17837
## 10.6.0 (2018-03-22) ## 10.6.0 (2018-03-22)
### Security (4 changes) ### Security (4 changes)
......
...@@ -172,7 +172,7 @@ group :unicorn do ...@@ -172,7 +172,7 @@ group :unicorn do
end end
# State machine # State machine
gem 'state_machines-activerecord', '~> 0.4.0' gem 'state_machines-activerecord', '~> 0.5.1'
# Issue tags # Issue tags
gem 'acts-as-taggable-on', '~> 5.0' gem 'acts-as-taggable-on', '~> 5.0'
......
...@@ -927,13 +927,13 @@ GEM ...@@ -927,13 +927,13 @@ GEM
sqlite3 (1.3.13) sqlite3 (1.3.13)
sshkey (1.9.0) sshkey (1.9.0)
stackprof (0.2.10) stackprof (0.2.10)
state_machines (0.4.0) state_machines (0.5.0)
state_machines-activemodel (0.4.0) state_machines-activemodel (0.5.1)
activemodel (>= 4.1, < 5.1) activemodel (>= 4.1, < 6.0)
state_machines (>= 0.4.0) state_machines (>= 0.5.0)
state_machines-activerecord (0.4.0) state_machines-activerecord (0.5.1)
activerecord (>= 4.1, < 5.1) activerecord (>= 4.1, < 6.0)
state_machines-activemodel (>= 0.3.0) state_machines-activemodel (>= 0.5.0)
stringex (2.7.1) stringex (2.7.1)
sys-filesystem (1.1.6) sys-filesystem (1.1.6)
ffi ffi
...@@ -1232,7 +1232,7 @@ DEPENDENCIES ...@@ -1232,7 +1232,7 @@ DEPENDENCIES
sprockets (~> 3.7.0) sprockets (~> 3.7.0)
sshkey (~> 1.9.0) sshkey (~> 1.9.0)
stackprof (~> 0.2.10) stackprof (~> 0.2.10)
state_machines-activerecord (~> 0.4.0) state_machines-activerecord (~> 0.5.1)
sys-filesystem (~> 1.1.6) sys-filesystem (~> 1.1.6)
test-prof (~> 0.2.5) test-prof (~> 0.2.5)
test_after_commit (~> 1.1) test_after_commit (~> 1.1)
......
...@@ -43,8 +43,8 @@ GEM ...@@ -43,8 +43,8 @@ GEM
i18n (~> 0.7) i18n (~> 0.7)
minitest (~> 5.1) minitest (~> 5.1)
tzinfo (~> 1.1) tzinfo (~> 1.1)
acts-as-taggable-on (4.0.0) acts-as-taggable-on (5.0.0)
activerecord (>= 4.0) activerecord (>= 4.2.8)
adamantium (0.2.0) adamantium (0.2.0)
ice_nine (~> 0.11.0) ice_nine (~> 0.11.0)
memoizable (~> 0.4.0) memoizable (~> 0.4.0)
...@@ -178,10 +178,10 @@ GEM ...@@ -178,10 +178,10 @@ GEM
docile (1.1.5) docile (1.1.5)
domain_name (0.5.20170404) domain_name (0.5.20170404)
unf (>= 0.0.5, < 1.0.0) unf (>= 0.0.5, < 1.0.0)
doorkeeper (4.2.6) doorkeeper (4.3.1)
railties (>= 4.2) railties (>= 4.2)
doorkeeper-openid_connect (1.2.0) doorkeeper-openid_connect (1.3.0)
doorkeeper (~> 4.0) doorkeeper (~> 4.3)
json-jwt (~> 1.6) json-jwt (~> 1.6)
dropzonejs-rails (0.7.4) dropzonejs-rails (0.7.4)
rails (> 3.1) rails (> 3.1)
...@@ -220,13 +220,13 @@ GEM ...@@ -220,13 +220,13 @@ GEM
path_expander (~> 1.0) path_expander (~> 1.0)
ruby_parser (~> 3.0) ruby_parser (~> 3.0)
sexp_processor (~> 4.0) sexp_processor (~> 4.0)
flipper (0.11.0) flipper (0.13.0)
flipper-active_record (0.11.0) flipper-active_record (0.13.0)
activerecord (>= 3.2, < 6) activerecord (>= 3.2, < 6)
flipper (~> 0.11.0) flipper (~> 0.13.0)
flipper-active_support_cache_store (0.11.0) flipper-active_support_cache_store (0.13.0)
activesupport (>= 3.2, < 6) activesupport (>= 3.2, < 6)
flipper (~> 0.11.0) flipper (~> 0.13.0)
flowdock (0.7.1) flowdock (0.7.1)
httparty (~> 0.7) httparty (~> 0.7)
multi_json multi_json
...@@ -235,7 +235,7 @@ GEM ...@@ -235,7 +235,7 @@ GEM
fog-json (~> 1.0) fog-json (~> 1.0)
ipaddress (~> 0.8) ipaddress (~> 0.8)
xml-simple (~> 1.1) xml-simple (~> 1.1)
fog-aws (1.4.1) fog-aws (2.0.1)
fog-core (~> 1.38) fog-core (~> 1.38)
fog-json (~> 1.0) fog-json (~> 1.0)
fog-xml (~> 0.1) fog-xml (~> 0.1)
...@@ -267,7 +267,7 @@ GEM ...@@ -267,7 +267,7 @@ GEM
nokogiri (>= 1.5.11, < 2.0.0) nokogiri (>= 1.5.11, < 2.0.0)
font-awesome-rails (4.7.0.3) font-awesome-rails (4.7.0.3)
railties (>= 3.2, < 5.2) railties (>= 3.2, < 5.2)
foreman (0.78.0) foreman (0.84.0)
thor (~> 0.19.1) thor (~> 0.19.1)
formatador (0.2.5) formatador (0.2.5)
fuubar (2.2.0) fuubar (2.2.0)
...@@ -283,7 +283,7 @@ GEM ...@@ -283,7 +283,7 @@ GEM
text (>= 1.3.0) text (>= 1.3.0)
gettext_i18n_rails (1.8.0) gettext_i18n_rails (1.8.0)
fast_gettext (>= 0.9.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 (>= 3.0.2)
gettext_i18n_rails (>= 0.7.1) gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0) po_to_json (>= 1.0.0)
...@@ -337,9 +337,9 @@ GEM ...@@ -337,9 +337,9 @@ GEM
json json
multi_json multi_json
request_store (>= 1.0) request_store (>= 1.0)
google-api-client (0.13.6) google-api-client (0.19.8)
addressable (~> 2.5, >= 2.5.1) addressable (~> 2.5, >= 2.5.1)
googleauth (~> 0.5) googleauth (>= 0.5, < 0.7.0)
httpclient (>= 2.8.1, < 3.0) httpclient (>= 2.8.1, < 3.0)
mime-types (~> 3.0) mime-types (~> 3.0)
representable (~> 3.0) representable (~> 3.0)
...@@ -404,7 +404,7 @@ GEM ...@@ -404,7 +404,7 @@ GEM
html2text (0.2.1) html2text (0.2.1)
nokogiri (~> 1.6) nokogiri (~> 1.6)
htmlentities (4.3.4) htmlentities (4.3.4)
http (0.9.8) http (2.2.2)
addressable (~> 2.3) addressable (~> 2.3)
http-cookie (~> 1.0) http-cookie (~> 1.0)
http-form_data (~> 1.0.1) http-form_data (~> 1.0.1)
...@@ -427,10 +427,6 @@ GEM ...@@ -427,10 +427,6 @@ GEM
multipart-post multipart-post
oauth (~> 0.5, >= 0.5.0) oauth (~> 0.5, >= 0.5.0)
jquery-atwho-rails (1.3.2) 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 (1.8.6)
json-jwt (1.9.2) json-jwt (1.9.2)
activesupport activesupport
...@@ -454,13 +450,12 @@ GEM ...@@ -454,13 +450,12 @@ GEM
kaminari-core (= 1.1.1) kaminari-core (= 1.1.1)
kaminari-core (1.1.1) kaminari-core (1.1.1)
kgio (2.11.2) kgio (2.11.2)
knapsack (1.11.1) knapsack (1.16.0)
rake rake
timecop (>= 0.1.0) kubeclient (3.0.0)
kubeclient (2.2.0) http (~> 2.2.2)
http (= 0.9.8) recursive-open-struct (~> 1.0.4)
recursive-open-struct (= 1.0.0) rest-client (~> 2.0)
rest-client
launchy (2.4.3) launchy (2.4.3)
addressable (~> 2.3) addressable (~> 2.3)
letter_opener (1.6.0) letter_opener (1.6.0)
...@@ -477,7 +472,7 @@ GEM ...@@ -477,7 +472,7 @@ GEM
toml (= 0.1.2) toml (= 0.1.2)
with_env (> 1.0) with_env (> 1.0)
xml-simple xml-simple
licensee (8.7.0) licensee (8.9.2)
rugged (~> 0.24) rugged (~> 0.24)
little-plugger (1.1.4) little-plugger (1.1.4)
locale (2.1.2) locale (2.1.2)
...@@ -514,7 +509,7 @@ GEM ...@@ -514,7 +509,7 @@ GEM
mustermann (~> 1.0.0) mustermann (~> 1.0.0)
mysql2 (0.4.10) mysql2 (0.4.10)
net-ldap (0.16.1) net-ldap (0.16.1)
net-ssh (4.1.0) net-ssh (4.2.0)
netrc (0.11.0) netrc (0.11.0)
nio4r (2.2.0) nio4r (2.2.0)
nokogiri (1.8.2) nokogiri (1.8.2)
...@@ -527,11 +522,10 @@ GEM ...@@ -527,11 +522,10 @@ GEM
multi_json (~> 1.3) multi_json (~> 1.3)
multi_xml (~> 0.5) multi_xml (~> 0.5)
rack (>= 1.2, < 3) rack (>= 1.2, < 3)
octokit (4.6.2) octokit (4.8.0)
sawyer (~> 0.8.0, >= 0.5.3) sawyer (~> 0.8.0, >= 0.5.3)
oj (2.17.5) omniauth (1.8.1)
omniauth (1.4.3) hashie (>= 3.4.6, < 3.6.0)
hashie (>= 1.2, < 4)
rack (>= 1.6.2, < 3) rack (>= 1.6.2, < 3)
omniauth-auth0 (1.4.2) omniauth-auth0 (1.4.2)
omniauth-oauth2 (~> 1.1) omniauth-oauth2 (~> 1.1)
...@@ -570,9 +564,9 @@ GEM ...@@ -570,9 +564,9 @@ GEM
omniauth (~> 1.2) omniauth (~> 1.2)
omniauth-oauth2-generic (0.2.4) omniauth-oauth2-generic (0.2.4)
omniauth-oauth2 (~> 1.0) omniauth-oauth2 (~> 1.0)
omniauth-saml (1.7.0) omniauth-saml (1.10.0)
omniauth (~> 1.3) omniauth (~> 1.3, >= 1.3.2)
ruby-saml (~> 1.4) ruby-saml (~> 1.7)
omniauth-shibboleth (1.2.1) omniauth-shibboleth (1.2.1)
omniauth (>= 1.0.0) omniauth (>= 1.0.0)
omniauth-twitter (1.2.1) omniauth-twitter (1.2.1)
...@@ -598,8 +592,6 @@ GEM ...@@ -598,8 +592,6 @@ GEM
railties (>= 4.0.0) railties (>= 4.0.0)
peek-gc (0.0.2) peek-gc (0.0.2)
peek peek
peek-host (1.0.0)
peek
peek-mysql2 (1.1.0) peek-mysql2 (1.1.0)
atomic (>= 1.0.0) atomic (>= 1.0.0)
mysql2 mysql2
...@@ -713,7 +705,7 @@ GEM ...@@ -713,7 +705,7 @@ GEM
re2 (1.1.1) re2 (1.1.1)
recaptcha (3.4.0) recaptcha (3.4.0)
json json
recursive-open-struct (1.0.0) recursive-open-struct (1.0.5)
redcarpet (3.4.0) redcarpet (3.4.0)
redis (3.3.5) redis (3.3.5)
redis-actionpack (5.0.2) redis-actionpack (5.0.2)
...@@ -805,7 +797,7 @@ GEM ...@@ -805,7 +797,7 @@ GEM
i18n i18n
ruby-fogbugz (0.2.1) ruby-fogbugz (0.2.1)
crack (~> 0.4) crack (~> 0.4)
ruby-prof (0.16.2) ruby-prof (0.17.0)
ruby-progressbar (1.9.0) ruby-progressbar (1.9.0)
ruby-saml (1.7.2) ruby-saml (1.7.2)
nokogiri (>= 1.5.10) nokogiri (>= 1.5.10)
...@@ -846,7 +838,7 @@ GEM ...@@ -846,7 +838,7 @@ GEM
selenium-webdriver (3.11.0) selenium-webdriver (3.11.0)
childprocess (~> 0.5) childprocess (~> 0.5)
rubyzip (~> 1.2) rubyzip (~> 1.2)
sentry-raven (2.5.3) sentry-raven (2.7.2)
faraday (>= 0.7.6, < 1.0) faraday (>= 0.7.6, < 1.0)
settingslogic (2.0.9) settingslogic (2.0.9)
sexp_processor (4.10.1) sexp_processor (4.10.1)
...@@ -903,12 +895,12 @@ GEM ...@@ -903,12 +895,12 @@ GEM
sshkey (1.9.0) sshkey (1.9.0)
stackprof (0.2.11) stackprof (0.2.11)
state_machines (0.5.0) state_machines (0.5.0)
state_machines-activemodel (0.5.0) state_machines-activemodel (0.5.1)
activemodel (>= 4.1, < 5.2) activemodel (>= 4.1, < 6.0)
state_machines (>= 0.5.0) state_machines (>= 0.5.0)
state_machines-activerecord (0.4.1) state_machines-activerecord (0.5.1)
activerecord (>= 4.1, < 5.2) activerecord (>= 4.1, < 6.0)
state_machines-activemodel (>= 0.3.0) state_machines-activemodel (>= 0.5.0)
stringex (2.8.4) stringex (2.8.4)
sys-filesystem (1.1.9) sys-filesystem (1.1.9)
ffi ffi
...@@ -998,7 +990,7 @@ DEPENDENCIES ...@@ -998,7 +990,7 @@ DEPENDENCIES
RedCloth (~> 4.3.2) RedCloth (~> 4.3.2)
ace-rails-ap (~> 4.1.0) ace-rails-ap (~> 4.1.0)
activerecord_sane_schema_dumper (= 1.0) activerecord_sane_schema_dumper (= 1.0)
acts-as-taggable-on (~> 4.0) acts-as-taggable-on (~> 5.0)
addressable (~> 2.5.2) addressable (~> 2.5.2)
akismet (~> 2.0) akismet (~> 2.0)
allocations (~> 1.0) allocations (~> 1.0)
...@@ -1038,8 +1030,8 @@ DEPENDENCIES ...@@ -1038,8 +1030,8 @@ DEPENDENCIES
devise (~> 4.2) devise (~> 4.2)
devise-two-factor (~> 3.0.0) devise-two-factor (~> 3.0.0)
diffy (~> 3.1.0) diffy (~> 3.1.0)
doorkeeper (~> 4.2.0) doorkeeper (~> 4.3)
doorkeeper-openid_connect (~> 1.2.0) doorkeeper-openid_connect (~> 1.3)
dropzonejs-rails (~> 0.7.1) dropzonejs-rails (~> 0.7.1)
email_reply_trimmer (~> 0.1) email_reply_trimmer (~> 0.1)
email_spec (~> 1.6.0) email_spec (~> 1.6.0)
...@@ -1048,24 +1040,24 @@ DEPENDENCIES ...@@ -1048,24 +1040,24 @@ DEPENDENCIES
fast_blank fast_blank
ffaker (~> 2.4) ffaker (~> 2.4)
flay (~> 2.10.0) flay (~> 2.10.0)
flipper (~> 0.11.0) flipper (~> 0.13.0)
flipper-active_record (~> 0.11.0) flipper-active_record (~> 0.13.0)
flipper-active_support_cache_store (~> 0.11.0) flipper-active_support_cache_store (~> 0.13.0)
fog-aliyun (~> 0.2.0) fog-aliyun (~> 0.2.0)
fog-aws (~> 1.4) fog-aws (~> 2.0)
fog-core (~> 1.44) fog-core (~> 1.44)
fog-google (~> 0.5) fog-google (~> 0.5)
fog-local (~> 0.3) fog-local (~> 0.3)
fog-openstack (~> 0.1) fog-openstack (~> 0.1)
fog-rackspace (~> 0.1.1) fog-rackspace (~> 0.1.1)
font-awesome-rails (~> 4.7) font-awesome-rails (~> 4.7)
foreman (~> 0.78.0) foreman (~> 0.84.0)
fuubar (~> 2.2.0) fuubar (~> 2.2.0)
gemnasium-gitlab-service (~> 0.2) gemnasium-gitlab-service (~> 0.2)
gemojione (~> 3.3) gemojione (~> 3.3)
gettext (~> 3.2.2) gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.2.0) gettext_i18n_rails_js (~> 1.3)
gitaly-proto (~> 0.88.0) gitaly-proto (~> 0.88.0)
github-linguist (~> 5.3.3) github-linguist (~> 5.3.3)
gitlab-flowdock-git-hook (~> 1.0.1) gitlab-flowdock-git-hook (~> 1.0.1)
...@@ -1075,7 +1067,7 @@ DEPENDENCIES ...@@ -1075,7 +1067,7 @@ DEPENDENCIES
gollum-lib (~> 4.2) gollum-lib (~> 4.2)
gollum-rugged_adapter (~> 0.4.4) gollum-rugged_adapter (~> 0.4.4)
gon (~> 6.1.0) gon (~> 6.1.0)
google-api-client (~> 0.13.6) google-api-client (~> 0.19.8)
google-protobuf (= 3.5.1) google-protobuf (= 3.5.1)
gpgme gpgme
grape (~> 1.0) grape (~> 1.0)
...@@ -1094,15 +1086,14 @@ DEPENDENCIES ...@@ -1094,15 +1086,14 @@ DEPENDENCIES
influxdb (~> 0.2) influxdb (~> 0.2)
jira-ruby (~> 1.4) jira-ruby (~> 1.4)
jquery-atwho-rails (~> 1.3.2) jquery-atwho-rails (~> 1.3.2)
jquery-rails (~> 4.3.1)
json-schema (~> 2.8.0) json-schema (~> 2.8.0)
jwt (~> 1.5.6) jwt (~> 1.5.6)
kaminari (~> 1.0) kaminari (~> 1.0)
knapsack (~> 1.11.0) knapsack (~> 1.16)
kubeclient (~> 2.2.0) kubeclient (~> 3.0)
letter_opener_web (~> 1.3.0) letter_opener_web (~> 1.3.0)
license_finder (~> 3.1) license_finder (~> 3.1)
licensee (~> 8.7.0) licensee (~> 8.9)
lograge (~> 0.5) lograge (~> 0.5)
loofah (~> 2.0.3) loofah (~> 2.0.3)
mail_room (~> 0.9.1) mail_room (~> 0.9.1)
...@@ -1111,12 +1102,11 @@ DEPENDENCIES ...@@ -1111,12 +1102,11 @@ DEPENDENCIES
mousetrap-rails (~> 1.4.6) mousetrap-rails (~> 1.4.6)
mysql2 (~> 0.4.10) mysql2 (~> 0.4.10)
net-ldap net-ldap
net-ssh (~> 4.1.0) net-ssh (~> 4.2.0)
nokogiri (~> 1.8.2) nokogiri (~> 1.8.2)
oauth2 (~> 1.4) oauth2 (~> 1.4)
octokit (~> 4.6.2) octokit (~> 4.8)
oj (~> 2.17.4) omniauth (~> 1.8)
omniauth (~> 1.4.2)
omniauth-auth0 (~> 1.4.1) omniauth-auth0 (~> 1.4.1)
omniauth-authentiq (~> 0.3.1) omniauth-authentiq (~> 0.3.1)
omniauth-azure-oauth2 (~> 0.0.9) omniauth-azure-oauth2 (~> 0.0.9)
...@@ -1127,14 +1117,13 @@ DEPENDENCIES ...@@ -1127,14 +1117,13 @@ DEPENDENCIES
omniauth-google-oauth2 (~> 0.5.2) omniauth-google-oauth2 (~> 0.5.2)
omniauth-kerberos (~> 0.3.0) omniauth-kerberos (~> 0.3.0)
omniauth-oauth2-generic (~> 0.2.2) omniauth-oauth2-generic (~> 0.2.2)
omniauth-saml (~> 1.7.0) omniauth-saml (~> 1.10)
omniauth-shibboleth (~> 1.2.0) omniauth-shibboleth (~> 1.2.0)
omniauth-twitter (~> 1.2.0) omniauth-twitter (~> 1.2.0)
omniauth_crowd (~> 2.2.0) omniauth_crowd (~> 2.2.0)
org-ruby (~> 0.9.12) org-ruby (~> 0.9.12)
peek (~> 1.0.1) peek (~> 1.0.1)
peek-gc (~> 0.0.2) peek-gc (~> 0.0.2)
peek-host (~> 1.0.0)
peek-mysql2 (~> 1.1.0) peek-mysql2 (~> 1.1.0)
peek-performance_bar (~> 1.3.0) peek-performance_bar (~> 1.3.0)
peek-pg (~> 1.3.0) peek-pg (~> 1.3.0)
...@@ -1177,7 +1166,7 @@ DEPENDENCIES ...@@ -1177,7 +1166,7 @@ DEPENDENCIES
rubocop (~> 0.52.1) rubocop (~> 0.52.1)
rubocop-rspec (~> 1.22.1) rubocop-rspec (~> 1.22.1)
ruby-fogbugz (~> 0.2.1) ruby-fogbugz (~> 0.2.1)
ruby-prof (~> 0.16.2) ruby-prof (~> 0.17.0)
ruby_parser (~> 3.8) ruby_parser (~> 3.8)
rufus-scheduler (~> 3.4) rufus-scheduler (~> 3.4)
rugged (~> 0.26.0) rugged (~> 0.26.0)
...@@ -1187,7 +1176,7 @@ DEPENDENCIES ...@@ -1187,7 +1176,7 @@ DEPENDENCIES
seed-fu (~> 2.3.7) seed-fu (~> 2.3.7)
select2-rails (~> 3.5.9) select2-rails (~> 3.5.9)
selenium-webdriver (~> 3.5) selenium-webdriver (~> 3.5)
sentry-raven (~> 2.5.3) sentry-raven (~> 2.7)
settingslogic (~> 2.0.9) settingslogic (~> 2.0.9)
sham_rack (~> 1.3.6) sham_rack (~> 1.3.6)
shoulda-matchers (~> 3.1.2) shoulda-matchers (~> 3.1.2)
...@@ -1205,7 +1194,7 @@ DEPENDENCIES ...@@ -1205,7 +1194,7 @@ DEPENDENCIES
sprockets (~> 3.7.0) sprockets (~> 3.7.0)
sshkey (~> 1.9.0) sshkey (~> 1.9.0)
stackprof (~> 0.2.10) stackprof (~> 0.2.10)
state_machines-activerecord (~> 0.4.0) state_machines-activerecord (~> 0.5.1)
sys-filesystem (~> 1.1.6) sys-filesystem (~> 1.1.6)
test-prof (~> 0.2.5) test-prof (~> 0.2.5)
test_after_commit (~> 1.1) test_after_commit (~> 1.1)
......
...@@ -33,7 +33,7 @@ export default class VariableList { ...@@ -33,7 +33,7 @@ export default class VariableList {
selector: '.js-ci-variable-input-key', selector: '.js-ci-variable-input-key',
default: '', default: '',
}, },
value: { secret_value: {
selector: '.js-ci-variable-input-value', selector: '.js-ci-variable-input-value',
default: '', default: '',
}, },
...@@ -105,7 +105,7 @@ export default class VariableList { ...@@ -105,7 +105,7 @@ export default class VariableList {
setupToggleButtons($row[0]); setupToggleButtons($row[0]);
// Reset the resizable textarea // 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'); const $environmentSelect = $row.find('.js-variable-environment-toggle');
if ($environmentSelect.length) { if ($environmentSelect.length) {
......
// ECMAScript polyfills // ECMAScript polyfills
import 'core-js/fn/array/fill';
import 'core-js/fn/array/find'; import 'core-js/fn/array/find';
import 'core-js/fn/array/find-index'; import 'core-js/fn/array/find-index';
import 'core-js/fn/array/from'; import 'core-js/fn/array/from';
......
...@@ -65,6 +65,10 @@ export default class Editor { ...@@ -65,6 +65,10 @@ export default class Editor {
(this.instance = this.monaco.editor.createDiffEditor(domElement, { (this.instance = this.monaco.editor.createDiffEditor(domElement, {
...defaultEditorOptions, ...defaultEditorOptions,
readOnly: true, readOnly: true,
quickSuggestions: false,
occurrencesHighlight: false,
renderLineHighlight: 'none',
hideCursorInOverviewRuler: true,
})), })),
); );
......
import initSettingsPanels from '~/settings_panels';
document.addEventListener('DOMContentLoaded', () => {
// Initialize expandable settings panels
initSettingsPanels();
});
...@@ -290,6 +290,10 @@ ...@@ -290,6 +290,10 @@
.margin-view-overlays .delete-sign { .margin-view-overlays .delete-sign {
opacity: 0.4; opacity: 0.4;
} }
.cursors-layer {
display: none;
}
} }
} }
......
...@@ -39,7 +39,7 @@ module Groups ...@@ -39,7 +39,7 @@ module Groups
end end
def variable_params_attributes def variable_params_attributes
%i[id key value protected _destroy] %i[id key secret_value protected _destroy]
end end
def authorize_admin_build! def authorize_admin_build!
......
...@@ -92,7 +92,7 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController ...@@ -92,7 +92,7 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController
def schedule_params def schedule_params
params.require(:schedule) params.require(:schedule)
.permit(:description, :cron, :cron_timezone, :ref, :active, .permit(:description, :cron, :cron_timezone, :ref, :active,
variables_attributes: [:id, :key, :value, :_destroy] ) variables_attributes: [:id, :key, :secret_value, :_destroy] )
end end
def authorize_play_pipeline_schedule! def authorize_play_pipeline_schedule!
......
...@@ -38,6 +38,6 @@ class Projects::VariablesController < Projects::ApplicationController ...@@ -38,6 +38,6 @@ class Projects::VariablesController < Projects::ApplicationController
end end
def variable_params_attributes def variable_params_attributes
%i[id key value protected _destroy] %i[id key secret_value protected _destroy]
end end
end end
...@@ -6,6 +6,8 @@ module Ci ...@@ -6,6 +6,8 @@ module Ci
belongs_to :group belongs_to :group
alias_attribute :secret_value, :value
validates :key, uniqueness: { validates :key, uniqueness: {
scope: :group_id, scope: :group_id,
message: "(%{value}) has already been taken" message: "(%{value}) has already been taken"
......
...@@ -6,6 +6,7 @@ module Ci ...@@ -6,6 +6,7 @@ module Ci
include AfterCommitQueue include AfterCommitQueue
include Presentable include Presentable
include Gitlab::OptimisticLocking include Gitlab::OptimisticLocking
include Gitlab::Utils::StrongMemoize
prepend ::EE::Ci::Pipeline prepend ::EE::Ci::Pipeline
...@@ -375,21 +376,23 @@ module Ci ...@@ -375,21 +376,23 @@ module Ci
def stage_seeds def stage_seeds
return [] unless config_processor 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 end
def seeds_size def seeds_size
@seeds_size ||= stage_seeds.sum(&:size) stage_seeds.sum(&:size)
end end
def has_kubernetes_active? def has_kubernetes_active?
project.deployment_platform&.active? project.deployment_platform&.active?
end end
def has_stage_seeds?
stage_seeds.any?
end
def has_warnings? def has_warnings?
builds.latest.failed_but_allowed.any? builds.latest.failed_but_allowed.any?
end end
...@@ -402,6 +405,9 @@ module Ci ...@@ -402,6 +405,9 @@ module Ci
end end
end end
##
# TODO, setting yaml_errors should be moved to the pipeline creation chain.
#
def config_processor def config_processor
return unless ci_yaml_file return unless ci_yaml_file
return @config_processor if defined?(@config_processor) return @config_processor if defined?(@config_processor)
...@@ -490,6 +496,14 @@ module Ci ...@@ -490,6 +496,14 @@ module Ci
end end
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 def predefined_variables
Gitlab::Ci::Variables::Collection.new Gitlab::Ci::Variables::Collection.new
.append(key: 'CI_PIPELINE_ID', value: id.to_s) .append(key: 'CI_PIPELINE_ID', value: id.to_s)
......
...@@ -5,6 +5,8 @@ module Ci ...@@ -5,6 +5,8 @@ module Ci
belongs_to :pipeline_schedule belongs_to :pipeline_schedule
alias_attribute :secret_value, :value
validates :key, uniqueness: { scope: :pipeline_schedule_id } validates :key, uniqueness: { scope: :pipeline_schedule_id }
end end
end end
...@@ -7,6 +7,8 @@ module Ci ...@@ -7,6 +7,8 @@ module Ci
belongs_to :project belongs_to :project
alias_attribute :secret_value, :value
validates :key, uniqueness: { validates :key, uniqueness: {
scope: [:project_id, :environment_scope], scope: [:project_id, :environment_scope],
message: "(%{value}) has already been taken" message: "(%{value}) has already been taken"
......
...@@ -11,6 +11,7 @@ module Clusters ...@@ -11,6 +11,7 @@ module Clusters
Applications::Prometheus.application_name => Applications::Prometheus, Applications::Prometheus.application_name => Applications::Prometheus,
Applications::Runner.application_name => Applications::Runner Applications::Runner.application_name => Applications::Runner
}.freeze }.freeze
DEFAULT_ENVIRONMENT = '*'.freeze
belongs_to :user belongs_to :user
...@@ -52,6 +53,7 @@ module Clusters ...@@ -52,6 +53,7 @@ module Clusters
scope :enabled, -> { where(enabled: true) } scope :enabled, -> { where(enabled: true) }
scope :disabled, -> { where(enabled: false) } scope :disabled, -> { where(enabled: false) }
scope :default_environment, -> { where(environment_scope: DEFAULT_ENVIRONMENT) }
def status_name def status_name
if provider if provider
......
module DeploymentPlatform 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) def deployment_platform(environment: nil)
@deployment_platform ||= @deployment_platform ||= {}
find_cluster_platform_kubernetes ||
find_kubernetes_service_integration || @deployment_platform[environment] ||= find_deployment_platform(environment)
build_cluster_and_deployment_platform
end end
private private
def find_cluster_platform_kubernetes def find_deployment_platform(environment)
clusters.find_by(enabled: true)&.platform_kubernetes 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 end
def find_kubernetes_service_integration def find_kubernetes_service_integration
......
...@@ -52,12 +52,12 @@ class Event < ActiveRecord::Base ...@@ -52,12 +52,12 @@ class Event < ActiveRecord::Base
belongs_to :target, -> { belongs_to :target, -> {
# If the association for "target" defines an "author" association we want to # 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 # eager-load this so Banzai & friends don't end up performing N+1 queries to
# get the authors of notes, issues, etc. # get the authors of notes, issues, etc. (likewise for "noteable").
if reflections['events'].active_record.reflect_on_association(:author) incs = %i(author noteable).select do |a|
includes(:author) reflections['events'].active_record.reflect_on_association(a)
else
self
end end
incs.reduce(self) { |obj, a| obj.includes(a) }
}, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations }, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
has_one :push_event_payload has_one :push_event_payload
......
...@@ -1107,7 +1107,9 @@ class MergeRequest < ActiveRecord::Base ...@@ -1107,7 +1107,9 @@ class MergeRequest < ActiveRecord::Base
end end
def base_pipeline def base_pipeline
@base_pipeline ||= project.pipelines.find_by(sha: merge_request_diff&.base_commit_sha) @base_pipeline ||= project.pipelines
.order(id: :desc)
.find_by(sha: diff_base_sha)
end end
def update_project_counter_caches def update_project_counter_caches
......
...@@ -9,6 +9,7 @@ module Ci ...@@ -9,6 +9,7 @@ module Ci
Gitlab::Ci::Pipeline::Chain::Validate::Config, Gitlab::Ci::Pipeline::Chain::Validate::Config,
Gitlab::Ci::Pipeline::Chain::Skip, Gitlab::Ci::Pipeline::Chain::Skip,
EE::Gitlab::Ci::Pipeline::Chain::Limit::Size, EE::Gitlab::Ci::Pipeline::Chain::Limit::Size,
Gitlab::Ci::Pipeline::Chain::Populate,
Gitlab::Ci::Pipeline::Chain::Create, Gitlab::Ci::Pipeline::Chain::Create,
EE::Gitlab::Ci::Pipeline::Chain::Limit::Activity].freeze EE::Gitlab::Ci::Pipeline::Chain::Limit::Activity].freeze
......
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
...@@ -18,8 +18,8 @@ module Ci ...@@ -18,8 +18,8 @@ module Ci
pipeline = Ci::CreatePipelineService.new(project, trigger.owner, ref: params[:ref]) pipeline = Ci::CreatePipelineService.new(project, trigger.owner, ref: params[:ref])
.execute(:trigger, ignore_skip_ci: true) do |pipeline| .execute(:trigger, ignore_skip_ci: true) do |pipeline|
pipeline.trigger_requests.create!(trigger: trigger) pipeline.trigger_requests.build(trigger: trigger)
create_pipeline_variables!(pipeline) pipeline.variables.build(variables)
end end
if pipeline.persisted? if pipeline.persisted?
...@@ -37,13 +37,14 @@ module Ci ...@@ -37,13 +37,14 @@ module Ci
pipeline = Ci::CreatePipelineService.new(project, job.user, ref: params[:ref]) pipeline = Ci::CreatePipelineService.new(project, job.user, ref: params[:ref])
.execute(:pipeline, ignore_skip_ci: true) do |pipeline| .execute(:pipeline, ignore_skip_ci: true) do |pipeline|
job.sourced_pipelines.create!( source = job.sourced_pipelines.build(
source_pipeline: job.pipeline, source_pipeline: job.pipeline,
source_project: job.project, source_project: job.project,
pipeline: pipeline, pipeline: pipeline,
project: project) project: project)
create_pipeline_variables!(pipeline) pipeline.source_pipeline = source
pipeline.variables.build(variables)
end end
if pipeline.persisted? if pipeline.persisted?
...@@ -60,19 +61,15 @@ module Ci ...@@ -60,19 +61,15 @@ module Ci
end end
def job_from_token def job_from_token
return @job if defined?(@job) strong_memoize(:job) do
Ci::Build.find_by_token(params[:token].to_s)
@job = Ci::Build.find_by_token(params[:token].to_s) end
end end
def create_pipeline_variables!(pipeline) def variables
return unless params[:variables] params[:variables].to_h.map do |key, value|
variables = params[:variables].map do |key, value|
{ key: key, value: value } { key: key, value: value }
end end
pipeline.variables.create!(variables)
end end
end end
end end
= form_for @application_setting, url: admin_application_settings_path, html: { class: 'form-horizontal fieldset-form' } do |f|
= form_errors(@application_setting)
%fieldset
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :gravatar_enabled do
= f.check_box :gravatar_enabled
Gravatar enabled
.form-group
= f.label :default_projects_limit, class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :default_projects_limit, class: 'form-control'
.form-group
= f.label :max_attachment_size, 'Maximum attachment size (MB)', class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :max_attachment_size, class: 'form-control'
= render 'repository_size_limit_setting', form: f
.form-group
= f.label :session_expire_delay, 'Session duration (minutes)', class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :session_expire_delay, class: 'form-control'
%span.help-block#session_expire_delay_help_block GitLab restart is required to apply changes
.form-group
= f.label :user_oauth_applications, 'User OAuth applications', class: 'control-label col-sm-2'
.col-sm-10
.checkbox
= f.label :user_oauth_applications do
= f.check_box :user_oauth_applications
Allow users to register any application to use GitLab as an OAuth provider
.form-group
= f.label :user_default_external, 'New users set to external', class: 'control-label col-sm-2'
.col-sm-10
.checkbox
= f.label :user_default_external do
= f.check_box :user_default_external
Newly registered users will by default be external
- if ::Gitlab.dev_env_or_com?
.form-group
= f.label :check_namespace_plan, 'Check feature availability on namespace plan', class: 'control-label col-sm-2'
.col-sm-10
.checkbox
= f.label :check_namespace_plan do
= f.check_box :check_namespace_plan
Enabling this will only make licensed EE features available to projects if the project namespace's plan
includes the feature or if the project is public.
= f.submit 'Save changes', class: 'btn btn-success'
= form_for @application_setting, url: admin_application_settings_path, html: { class: 'form-horizontal fieldset-form' } do |f| = form_for @application_setting, url: admin_application_settings_path, html: { class: 'form-horizontal fieldset-form' } do |f|
= form_errors(@application_setting) = form_errors(@application_setting)
%fieldset
%legend Visibility and Access Controls
.form-group
= f.label :default_branch_protection, class: 'control-label col-sm-2'
.col-sm-10
= f.select :default_branch_protection, options_for_select(Gitlab::Access.protection_options, @application_setting.default_branch_protection), {}, class: 'form-control'
= render partial: 'admin/application_settings/ee/project_creation_level', locals: { form: f, application_setting: @application_setting }
.form-group.visibility-level-setting
= f.label :default_project_visibility, class: 'control-label col-sm-2'
.col-sm-10
= render('shared/visibility_radios', model_method: :default_project_visibility, form: f, selected_level: @application_setting.default_project_visibility, form_model: Project.new)
.form-group.visibility-level-setting
= f.label :default_snippet_visibility, class: 'control-label col-sm-2'
.col-sm-10
= render('shared/visibility_radios', model_method: :default_snippet_visibility, form: f, selected_level: @application_setting.default_snippet_visibility, form_model: ProjectSnippet.new)
.form-group.visibility-level-setting
= f.label :default_group_visibility, class: 'control-label col-sm-2'
.col-sm-10
= render('shared/visibility_radios', model_method: :default_group_visibility, form: f, selected_level: @application_setting.default_group_visibility, form_model: Group.new)
.form-group
= f.label :restricted_visibility_levels, class: 'control-label col-sm-2'
.col-sm-10
- checkbox_name = 'application_setting[restricted_visibility_levels][]'
= hidden_field_tag(checkbox_name)
- restricted_level_checkboxes('restricted-visibility-help', checkbox_name).each do |level|
.checkbox
= level
%span.help-block#restricted-visibility-help
Selected levels cannot be used by non-admin users for projects or snippets.
If the public level is restricted, user profiles are only visible to logged in users.
.form-group
= f.label :import_sources, class: 'control-label col-sm-2'
.col-sm-10
- import_sources_checkboxes('import-sources-help').each do |source|
.checkbox= source
%span.help-block#import-sources-help
Enabled sources for code import during project creation. OmniAuth must be configured for GitHub
= link_to "(?)", help_page_path("integration/github")
, Bitbucket
= link_to "(?)", help_page_path("integration/bitbucket")
and GitLab.com
= link_to "(?)", help_page_path("integration/gitlab")
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :project_export_enabled do
= f.check_box :project_export_enabled
Project export enabled
-# EE-only
- if ldap_enabled?
.form-group
= f.label :allow_group_owners_to_manage_ldap, 'LDAP settings', class: 'control-label col-sm-2'
.col-sm-10
.checkbox
= f.label :allow_group_owners_to_manage_ldap do
= f.check_box :allow_group_owners_to_manage_ldap
Allow group owners to manage LDAP-related settings
%span.help-block
If checked, group owners can manage LDAP group links and LDAP member overrides
= link_to icon('question-circle'), help_page_path('administration/auth/ldap-ee')
.form-group
%label.control-label.col-sm-2 Enabled Git access protocols
.col-sm-10
= select(:application_setting, :enabled_git_access_protocol, [['Both SSH and HTTP(S)', nil], ['Only SSH', 'ssh'], ['Only HTTP(S)', 'http']], {}, class: 'form-control')
%span.help-block#clone-protocol-help
Allow only the selected protocols to be used for Git access.
- ApplicationSetting::SUPPORTED_KEY_TYPES.each do |type|
- field_name = :"#{type}_key_restriction"
.form-group
= f.label field_name, "#{type.upcase} SSH keys", class: 'control-label col-sm-2'
.col-sm-10
= f.select field_name, key_restriction_options_for_select(type), {}, class: 'form-control'
%fieldset
%legend Account and Limit Settings
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :gravatar_enabled do
= f.check_box :gravatar_enabled
Gravatar enabled
.form-group
= f.label :default_projects_limit, class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :default_projects_limit, class: 'form-control'
.form-group
= f.label :max_attachment_size, 'Maximum attachment size (MB)', class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :max_attachment_size, class: 'form-control'
= render 'repository_size_limit_setting', form: f
.form-group
= f.label :session_expire_delay, 'Session duration (minutes)', class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :session_expire_delay, class: 'form-control'
%span.help-block#session_expire_delay_help_block GitLab restart is required to apply changes
.form-group
= f.label :user_oauth_applications, 'User OAuth applications', class: 'control-label col-sm-2'
.col-sm-10
.checkbox
= f.label :user_oauth_applications do
= f.check_box :user_oauth_applications
Allow users to register any application to use GitLab as an OAuth provider
.form-group
= f.label :user_default_external, 'New users set to external', class: 'control-label col-sm-2'
.col-sm-10
.checkbox
= f.label :user_default_external do
= f.check_box :user_default_external
Newly registered users will by default be external
- if ::Gitlab.dev_env_or_com?
.form-group
= f.label :check_namespace_plan, 'Check feature availability on namespace plan', class: 'control-label col-sm-2'
.col-sm-10
.checkbox
= f.label :check_namespace_plan do
= f.check_box :check_namespace_plan
Enabling this will only make licensed EE features available to projects if the project namespace's plan
includes the feature or if the project is public.
- if License.feature_available?(:repository_mirrors) - if License.feature_available?(:repository_mirrors)
= render partial: 'repository_mirrors_form', locals: { f: f } = render partial: 'repository_mirrors_form', locals: { f: f }
%fieldset
%legend Sign-up Restrictions
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :signup_enabled do
= f.check_box :signup_enabled
Sign-up enabled
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :send_user_confirmation_email do
= f.check_box :send_user_confirmation_email
Send confirmation email on sign-up
.form-group
= f.label :domain_whitelist, 'Whitelisted domains for sign-ups', class: 'control-label col-sm-2'
.col-sm-10
= f.text_area :domain_whitelist_raw, placeholder: 'domain.com', class: 'form-control', rows: 8
.help-block ONLY users with e-mail addresses that match these domain(s) will be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com
.form-group
= f.label :domain_blacklist_enabled, 'Domain Blacklist', class: 'control-label col-sm-2'
.col-sm-10
.checkbox
= f.label :domain_blacklist_enabled do
= f.check_box :domain_blacklist_enabled
Enable domain blacklist for sign ups
.form-group
.col-sm-offset-2.col-sm-10
.radio
= label_tag :blacklist_type_file do
= radio_button_tag :blacklist_type, :file
.option-title
Upload blacklist file
.radio
= label_tag :blacklist_type_raw do
= radio_button_tag :blacklist_type, :raw, @application_setting.domain_blacklist.present? || @application_setting.domain_blacklist.blank?
.option-title
Enter blacklist manually
.form-group.blacklist-file
= f.label :domain_blacklist_file, 'Blacklist file', class: 'control-label col-sm-2'
.col-sm-10
= f.file_field :domain_blacklist_file, class: 'form-control', accept: '.txt,.conf'
.help-block Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines or commas for multiple entries.
.form-group.blacklist-raw
= f.label :domain_blacklist, 'Blacklisted domains for sign-ups', class: 'control-label col-sm-2'
.col-sm-10
= f.text_area :domain_blacklist_raw, placeholder: 'domain.com', class: 'form-control', rows: 8
.help-block Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com
.form-group
= f.label :after_sign_up_text, class: 'control-label col-sm-2'
.col-sm-10
= f.text_area :after_sign_up_text, class: 'form-control', rows: 4
.help-block Markdown enabled
%fieldset
%legend Sign-in Restrictions
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :password_authentication_enabled_for_web do
= f.check_box :password_authentication_enabled_for_web
Password authentication enabled for web interface
.help-block
When disabled, an external authentication provider must be used.
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :password_authentication_enabled_for_git do
= f.check_box :password_authentication_enabled_for_git
Password authentication enabled for Git over HTTP(S)
.help-block
When disabled, a Personal Access Token
- if Gitlab::Auth::LDAP::Config.enabled?
or LDAP password
must be used to authenticate.
- if omniauth_enabled? && button_based_providers.any?
.form-group
= f.label :enabled_oauth_sign_in_sources, 'Enabled OAuth sign-in sources', class: 'control-label col-sm-2'
.col-sm-10
.btn-group{ data: { toggle: 'buttons' } }
- oauth_providers_checkboxes.each do |source|
= source
.form-group
= f.label :two_factor_authentication, 'Two-factor authentication', class: 'control-label col-sm-2'
.col-sm-10
.checkbox
= f.label :require_two_factor_authentication do
= f.check_box :require_two_factor_authentication
Require all users to setup Two-factor authentication
.form-group
= f.label :two_factor_authentication, 'Two-factor grace period (hours)', class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :two_factor_grace_period, min: 0, class: 'form-control', placeholder: '0'
.help-block Amount of time (in hours) that users are allowed to skip forced configuration of two-factor authentication
.form-group
= f.label :home_page_url, 'Home page URL', class: 'control-label col-sm-2'
.col-sm-10
= f.text_field :home_page_url, class: 'form-control', placeholder: 'http://company.example.com', :'aria-describedby' => 'home_help_block'
%span.help-block#home_help_block We will redirect non-logged in users to this page
.form-group
= f.label :after_sign_out_path, class: 'control-label col-sm-2'
.col-sm-10
= f.text_field :after_sign_out_path, class: 'form-control', placeholder: 'http://company.example.com', :'aria-describedby' => 'after_sign_out_path_help_block'
%span.help-block#after_sign_out_path_help_block We will redirect users to this page after they sign out
.form-group
= f.label :sign_in_text, class: 'control-label col-sm-2'
.col-sm-10
= f.text_area :sign_in_text, class: 'form-control', rows: 4
.help-block Markdown enabled
%fieldset
%legend Help Page
.form-group
= f.label :help_text, class: 'control-label'
.col-sm-10
= f.text_area :help_text, class: 'form-control', rows: 4
.help-block Markdown enabled
.form-group
= f.label :help_page_text, class: 'control-label col-sm-2'
.col-sm-10
= f.text_area :help_page_text, class: 'form-control', rows: 4
.help-block Markdown enabled
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :help_page_hide_commercial_content do
= f.check_box :help_page_hide_commercial_content
Hide marketing-related entries from help
.form-group
= f.label :help_page_support_url, 'Support page URL', class: 'control-label col-sm-2'
.col-sm-10
= f.text_field :help_page_support_url, class: 'form-control', placeholder: 'http://company.example.com/getting-help', :'aria-describedby' => 'support_help_block'
%span.help-block#support_help_block Alternate support URL for help page
%fieldset
%legend Pages
.form-group
= f.label :max_pages_size, 'Maximum size of pages (MB)', class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :max_pages_size, class: 'form-control'
.help-block 0 for unlimited
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :pages_domain_verification_enabled do
= f.check_box :pages_domain_verification_enabled
Require users to prove ownership of custom domains
.help-block
Domain verification is an essential security measure for public GitLab
sites. Users are required to demonstrate they control a domain before
it is enabled
= link_to icon('question-circle'), help_page_path('user/project/pages/getting_started_part_three.md', anchor: 'dns-txt-record')
%fieldset %fieldset
%legend Continuous Integration and Deployment %legend Continuous Integration and Deployment
.form-group .form-group
......
= form_for @application_setting, url: admin_application_settings_path, html: { class: 'form-horizontal fieldset-form' } do |f|
= form_errors(@application_setting)
%fieldset
.form-group
= f.label :help_text, class: 'control-label'
.col-sm-10
= f.text_area :help_text, class: 'form-control', rows: 4
.help-block Markdown enabled
.form-group
= f.label :help_page_text, class: 'control-label col-sm-2'
.col-sm-10
= f.text_area :help_page_text, class: 'form-control', rows: 4
.help-block Markdown enabled
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :help_page_hide_commercial_content do
= f.check_box :help_page_hide_commercial_content
Hide marketing-related entries from help
.form-group
= f.label :help_page_support_url, 'Support page URL', class: 'control-label col-sm-2'
.col-sm-10
= f.text_field :help_page_support_url, class: 'form-control', placeholder: 'http://company.example.com/getting-help', :'aria-describedby' => 'support_help_block'
%span.help-block#support_help_block Alternate support URL for help page
= f.submit 'Save changes', class: "btn btn-success"
= form_for @application_setting, url: admin_application_settings_path, html: { class: 'form-horizontal fieldset-form' } do |f|
= form_errors(@application_setting)
%fieldset
.form-group
= f.label :max_pages_size, 'Maximum size of pages (MB)', class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :max_pages_size, class: 'form-control'
.help-block 0 for unlimited
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :pages_domain_verification_enabled do
= f.check_box :pages_domain_verification_enabled
Require users to prove ownership of custom domains
.help-block
Domain verification is an essential security measure for public GitLab
sites. Users are required to demonstrate they control a domain before
it is enabled
= link_to icon('question-circle'), help_page_path('user/project/pages/getting_started_part_three.md', anchor: 'dns-txt-record')
= f.submit 'Save changes', class: "btn btn-success"
= form_for @application_setting, url: admin_application_settings_path, html: { class: 'form-horizontal fieldset-form' } do |f|
= form_errors(@application_setting)
%fieldset
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :password_authentication_enabled_for_web do
= f.check_box :password_authentication_enabled_for_web
Password authentication enabled for web interface
.help-block
When disabled, an external authentication provider must be used.
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :password_authentication_enabled_for_git do
= f.check_box :password_authentication_enabled_for_git
Password authentication enabled for Git over HTTP(S)
.help-block
When disabled, a Personal Access Token
- if Gitlab::Auth::LDAP::Config.enabled?
or LDAP password
must be used to authenticate.
- if omniauth_enabled? && button_based_providers.any?
.form-group
= f.label :enabled_oauth_sign_in_sources, 'Enabled OAuth sign-in sources', class: 'control-label col-sm-2'
.col-sm-10
.btn-group{ data: { toggle: 'buttons' } }
- oauth_providers_checkboxes.each do |source|
= source
.form-group
= f.label :two_factor_authentication, 'Two-factor authentication', class: 'control-label col-sm-2'
.col-sm-10
.checkbox
= f.label :require_two_factor_authentication do
= f.check_box :require_two_factor_authentication
Require all users to setup Two-factor authentication
.form-group
= f.label :two_factor_authentication, 'Two-factor grace period (hours)', class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :two_factor_grace_period, min: 0, class: 'form-control', placeholder: '0'
.help-block Amount of time (in hours) that users are allowed to skip forced configuration of two-factor authentication
.form-group
= f.label :home_page_url, 'Home page URL', class: 'control-label col-sm-2'
.col-sm-10
= f.text_field :home_page_url, class: 'form-control', placeholder: 'http://company.example.com', :'aria-describedby' => 'home_help_block'
%span.help-block#home_help_block We will redirect non-logged in users to this page
.form-group
= f.label :after_sign_out_path, class: 'control-label col-sm-2'
.col-sm-10
= f.text_field :after_sign_out_path, class: 'form-control', placeholder: 'http://company.example.com', :'aria-describedby' => 'after_sign_out_path_help_block'
%span.help-block#after_sign_out_path_help_block We will redirect users to this page after they sign out
.form-group
= f.label :sign_in_text, class: 'control-label col-sm-2'
.col-sm-10
= f.text_area :sign_in_text, class: 'form-control', rows: 4
.help-block Markdown enabled
= f.submit 'Save changes', class: "btn btn-success"
= form_for @application_setting, url: admin_application_settings_path, html: { class: 'form-horizontal fieldset-form' } do |f|
= form_errors(@application_setting)
%fieldset
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :signup_enabled do
= f.check_box :signup_enabled
Sign-up enabled
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :send_user_confirmation_email do
= f.check_box :send_user_confirmation_email
Send confirmation email on sign-up
.form-group
= f.label :domain_whitelist, 'Whitelisted domains for sign-ups', class: 'control-label col-sm-2'
.col-sm-10
= f.text_area :domain_whitelist_raw, placeholder: 'domain.com', class: 'form-control', rows: 8
.help-block ONLY users with e-mail addresses that match these domain(s) will be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com
.form-group
= f.label :domain_blacklist_enabled, 'Domain Blacklist', class: 'control-label col-sm-2'
.col-sm-10
.checkbox
= f.label :domain_blacklist_enabled do
= f.check_box :domain_blacklist_enabled
Enable domain blacklist for sign ups
.form-group
.col-sm-offset-2.col-sm-10
.radio
= label_tag :blacklist_type_file do
= radio_button_tag :blacklist_type, :file
.option-title
Upload blacklist file
.radio
= label_tag :blacklist_type_raw do
= radio_button_tag :blacklist_type, :raw, @application_setting.domain_blacklist.present? || @application_setting.domain_blacklist.blank?
.option-title
Enter blacklist manually
.form-group.blacklist-file
= f.label :domain_blacklist_file, 'Blacklist file', class: 'control-label col-sm-2'
.col-sm-10
= f.file_field :domain_blacklist_file, class: 'form-control', accept: '.txt,.conf'
.help-block Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines or commas for multiple entries.
.form-group.blacklist-raw
= f.label :domain_blacklist, 'Blacklisted domains for sign-ups', class: 'control-label col-sm-2'
.col-sm-10
= f.text_area :domain_blacklist_raw, placeholder: 'domain.com', class: 'form-control', rows: 8
.help-block Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com
.form-group
= f.label :after_sign_up_text, class: 'control-label col-sm-2'
.col-sm-10
= f.text_area :after_sign_up_text, class: 'form-control', rows: 4
.help-block Markdown enabled
= f.submit 'Save changes', class: "btn btn-success"
= form_for @application_setting, url: admin_application_settings_path, html: { class: 'form-horizontal fieldset-form' } do |f|
= form_errors(@application_setting)
%fieldset
.form-group
= f.label :default_branch_protection, class: 'control-label col-sm-2'
.col-sm-10
= f.select :default_branch_protection, options_for_select(Gitlab::Access.protection_options, @application_setting.default_branch_protection), {}, class: 'form-control'
= render partial: 'admin/application_settings/ee/project_creation_level', locals: { form: f, application_setting: @application_setting }
.form-group.visibility-level-setting
= f.label :default_project_visibility, class: 'control-label col-sm-2'
.col-sm-10
= render('shared/visibility_radios', model_method: :default_project_visibility, form: f, selected_level: @application_setting.default_project_visibility, form_model: Project.new)
.form-group.visibility-level-setting
= f.label :default_snippet_visibility, class: 'control-label col-sm-2'
.col-sm-10
= render('shared/visibility_radios', model_method: :default_snippet_visibility, form: f, selected_level: @application_setting.default_snippet_visibility, form_model: ProjectSnippet.new)
.form-group.visibility-level-setting
= f.label :default_group_visibility, class: 'control-label col-sm-2'
.col-sm-10
= render('shared/visibility_radios', model_method: :default_group_visibility, form: f, selected_level: @application_setting.default_group_visibility, form_model: Group.new)
.form-group
= f.label :restricted_visibility_levels, class: 'control-label col-sm-2'
.col-sm-10
- checkbox_name = 'application_setting[restricted_visibility_levels][]'
= hidden_field_tag(checkbox_name)
- restricted_level_checkboxes('restricted-visibility-help', checkbox_name).each do |level|
.checkbox
= level
%span.help-block#restricted-visibility-help
Selected levels cannot be used by non-admin users for projects or snippets.
If the public level is restricted, user profiles are only visible to logged in users.
.form-group
= f.label :import_sources, class: 'control-label col-sm-2'
.col-sm-10
- import_sources_checkboxes('import-sources-help').each do |source|
.checkbox= source
%span.help-block#import-sources-help
Enabled sources for code import during project creation. OmniAuth must be configured for GitHub
= link_to "(?)", help_page_path("integration/github")
, Bitbucket
= link_to "(?)", help_page_path("integration/bitbucket")
and GitLab.com
= link_to "(?)", help_page_path("integration/gitlab")
.form-group
= f.label :default_branch_protection, class: 'control-label col-sm-2'
.col-sm-10
= f.select :default_branch_protection, options_for_select(Gitlab::Access.protection_options, @application_setting.default_branch_protection), {}, class: 'form-control'
-# EE-only
- if ldap_enabled?
.form-group
= f.label :allow_group_owners_to_manage_ldap, 'LDAP settings', class: 'control-label col-sm-2'
.col-sm-10
.checkbox
= f.label :allow_group_owners_to_manage_ldap do
= f.check_box :allow_group_owners_to_manage_ldap
Allow group owners to manage LDAP-related settings
%span.help-block
If checked, group owners can manage LDAP group links and LDAP member overrides
= link_to icon('question-circle'), help_page_path('administration/auth/ldap-ee')
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :project_export_enabled do
= f.check_box :project_export_enabled
Project export enabled
.form-group
%label.control-label.col-sm-2 Enabled Git access protocols
.col-sm-10
= select(:application_setting, :enabled_git_access_protocol, [['Both SSH and HTTP(S)', nil], ['Only SSH', 'ssh'], ['Only HTTP(S)', 'http']], {}, class: 'form-control')
%span.help-block#clone-protocol-help
Allow only the selected protocols to be used for Git access.
- ApplicationSetting::SUPPORTED_KEY_TYPES.each do |type|
- field_name = :"#{type}_key_restriction"
.form-group
= f.label field_name, "#{type.upcase} SSH keys", class: 'control-label col-sm-2'
.col-sm-10
= f.select field_name, key_restriction_options_for_select(type), {}, class: 'form-control'
= f.submit 'Save changes', class: "btn btn-success"
- breadcrumb_title "Settings"
- page_title "Settings" - page_title "Settings"
- @content_class = "limit-container-width" unless fluid_layout
- expanded = Rails.env.test?
%h3.page-title Settings %section.settings.as-visibility-access.no-animate#js-visibility-settings{ class: ('expanded' if expanded) }
%hr .settings-header
= render 'form' %h4
= _('Visibility and access controls')
%button.btn.js-settings-toggle
= expanded ? 'Collapse' : 'Expand'
%p
= _('Set default and restrict visibility levels. Configure import sources and git access protocol.')
.settings-content
= render 'visibility_and_access'
%section.settings.as-account-limit.no-animate#js-account-settings{ class: ('expanded' if expanded) }
.settings-header
%h4
= _('Account and limit settings')
%button.btn.js-settings-toggle
= expanded ? 'Collapse' : 'Expand'
%p
= _('Session expiration, projects limit and attachment size.')
.settings-content
= render 'account_and_limit'
%section.settings.as-signup.no-animate#js-signup-settings{ class: ('expanded' if expanded) }
.settings-header
%h4
= _('Sign-up restrictions')
%button.btn.js-settings-toggle
= expanded ? 'Collapse' : 'Expand'
%p
= _('Configure the way a user creates a new account.')
.settings-content
= render 'signup'
%section.settings.as-signin.no-animate#js-signin-settings{ class: ('expanded' if expanded) }
.settings-header
%h4
= _('Sign-in restrictions')
%button.btn.js-settings-toggle
= expanded ? 'Collapse' : 'Expand'
%p
= _('Set requirements for a user to sign-in. Enable mandatory two-factor authentication.')
.settings-content
= render 'signin'
%section.settings.as-help-page.no-animate#js-help-settings{ class: ('expanded' if expanded) }
.settings-header
%h4
= _('Help page')
%button.btn.js-settings-toggle
= expanded ? 'Collapse' : 'Expand'
%p
= _('Help page text and support page url.')
.settings-content
= render 'help_page'
%section.settings.as-pages.no-animate#js-pages-settings{ class: ('expanded' if expanded) }
.settings-header
%h4
= _('Pages')
%button.btn.js-settings-toggle
= expanded ? 'Collapse' : 'Expand'
%p
= _('Size and domain settings for static websites')
.settings-content
= render 'pages'
.prepend-top-20
= render 'form'
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
- id_input_name = "#{form_field}[variables_attributes][][id]" - id_input_name = "#{form_field}[variables_attributes][][id]"
- destroy_input_name = "#{form_field}[variables_attributes][][_destroy]" - destroy_input_name = "#{form_field}[variables_attributes][][_destroy]"
- key_input_name = "#{form_field}[variables_attributes][][key]" - key_input_name = "#{form_field}[variables_attributes][][key]"
- value_input_name = "#{form_field}[variables_attributes][][value]" - value_input_name = "#{form_field}[variables_attributes][][secret_value]"
- protected_input_name = "#{form_field}[variables_attributes][][protected]" - protected_input_name = "#{form_field}[variables_attributes][][protected]"
%li.js-row.ci-variable-row{ data: { is_persisted: "#{!id.nil?}" } } %li.js-row.ci-variable-row{ data: { is_persisted: "#{!id.nil?}" } }
......
---
title: Use specific names for filtered CI variable controller parameters
merge_request: 17796
author:
type: other
---
title: Add documentation for runner IP address (#44232)
merge_request: 17837
author:
type: other
---
title: Fix 500 error when trying to resolve non-ASCII conflicts in the editor
merge_request: 17962
author:
type: fixed
---
title: Don't capture trailing punctuation when autolinking
merge_request: 17965
author:
type: fixed
---
title: Remove N+1 query for Noteable association.
merge_request: 17956
author:
type: performance
---
title: Add indexes for user activity queries.
merge_request: 17890
author:
type: performance
---
title: Bump `state_machines-activerecord` to 0.5.1
merge_request: 17924
author: blackst0ne
type: other
---
title: Prevent auto-retry AccessDenied error from stopping transition to failed
merge_request: 17862
author:
type: fixed
---
title: Bump rails-html-sanitizer to 1.0.4
merge_request:
author:
type: security
# Geo configuration (GitLab Omnibus) # Geo configuration (GitLab Omnibus)
>**Note:** NOTE: **Note:**
This is the documentation for the Omnibus GitLab packages. For installations This is the documentation for the Omnibus GitLab packages. For installations
from source, follow the [**Geo nodes configuration for installations from source, follow the [**Geo nodes configuration for installations
from source**][configuration-source] guide. from source**][configuration-source] guide.
## Configuring a new secondary node ## Configuring a new secondary node
>**Note:** NOTE: **Note:**
This is the final step in setting up a secondary Geo node. Stages of the This is the final step in setting up a secondary Geo node. Stages of the
setup process must be completed in the documented order. setup process must be completed in the documented order.
Before attempting the steps in this stage, [complete all prior stages][setup-geo-omnibus]. Before attempting the steps in this stage, [complete all prior stages][setup-geo-omnibus].
...@@ -20,9 +20,9 @@ You are encouraged to first read through all the steps before executing them ...@@ -20,9 +20,9 @@ You are encouraged to first read through all the steps before executing them
in your testing/production environment. in your testing/production environment.
> **Notes:** > **Notes:**
- **Do not** setup any custom authentication in the secondary nodes, this will be > - **Do not** setup any custom authentication in the secondary nodes, this will be
handled by the primary node. handled by the primary node.
- Any change that requires access to the **Admin Area** needs to be done in the > - Any change that requires access to the **Admin Area** needs to be done in the
primary node, as the secondary node is a read-only replica. primary node, as the secondary node is a read-only replica.
### Step 1. Manually replicate secret GitLab values ### Step 1. Manually replicate secret GitLab values
......
# Geo configuration (source) # Geo configuration (source)
>**Note:** NOTE: **Note:**
This is the documentation for installations from source. For installations This is the documentation for installations from source. For installations
using the Omnibus GitLab packages, follow the using the Omnibus GitLab packages, follow the
[**Omnibus Geo nodes configuration**][configuration] guide. [**Omnibus Geo nodes configuration**][configuration] guide.
## Configuring a new secondary node ## Configuring a new secondary node
>**Note:** NOTE: **Note:**
This is the final step in setting up a secondary Geo node. Stages of the setup This is the final step in setting up a secondary Geo node. Stages of the setup
process must be completed in the documented order. Before attempting the steps process must be completed in the documented order. Before attempting the steps
in this stage, [complete all prior stages][setup-geo-source]. in this stage, [complete all prior stages][setup-geo-source].
...@@ -20,7 +20,7 @@ You are encouraged to first read through all the steps before executing them ...@@ -20,7 +20,7 @@ You are encouraged to first read through all the steps before executing them
in your testing/production environment. in your testing/production environment.
>**Notes:** NOTE: **Notes:**
- **Do not** setup any custom authentication in the secondary nodes, this will be - **Do not** setup any custom authentication in the secondary nodes, this will be
handled by the primary node. handled by the primary node.
- **Do not** add anything in the secondaries Geo nodes admin area - **Do not** add anything in the secondaries Geo nodes admin area
......
# Geo database replication (GitLab Omnibus) # Geo database replication (GitLab Omnibus)
>**Note:** NOTE: **Note:**
This is the documentation for the Omnibus GitLab packages. For installations This is the documentation for the Omnibus GitLab packages. For installations
from source, follow the from source, follow the
[**database replication for installations from source**][database-source] guide. [**database replication for installations from source**][database-source] guide.
>**Note:** NOTE: **Note:**
If your GitLab installation uses external PostgreSQL, the Omnibus roles If your GitLab installation uses external PostgreSQL, the Omnibus roles
will not be able to perform all necessary configuration steps. Refer to the will not be able to perform all necessary configuration steps. Refer to the
section on [External PostreSQL][external postgresql] for additional instructions. section on [External PostreSQL][external postgresql] for additional instructions.
>**Note:** NOTE: **Note:**
The stages of the setup process must be completed in the documented order. The stages of the setup process must be completed in the documented order.
Before attempting the steps in this stage, [complete all prior stages][toc]. Before attempting the steps in this stage, [complete all prior stages][toc].
...@@ -28,7 +28,7 @@ The GitLab primary node where the write operations happen will connect to ...@@ -28,7 +28,7 @@ The GitLab primary node where the write operations happen will connect to
the primary database server, and the secondary nodes which are read-only will the primary database server, and the secondary nodes which are read-only will
connect to the secondary database servers (which are also read-only). connect to the secondary database servers (which are also read-only).
>**Note:** NOTE: **Note:**
In database documentation you may see "primary" being referenced as "master" In database documentation you may see "primary" being referenced as "master"
and "secondary" as either "slave" or "standby" server (read-only). and "secondary" as either "slave" or "standby" server (read-only).
...@@ -261,7 +261,8 @@ The following guide assumes that: ...@@ -261,7 +261,8 @@ The following guide assumes that:
gitlab-ctl stop sidekiq gitlab-ctl stop sidekiq
``` ```
> **Note**: This step is important so we don't try to execute anything before the node is fully configured. NOTE: **Note**:
This step is important so we don't try to execute anything before the node is fully configured.
1. [Check TCP connectivity][rake-maintenance] to the primary's PostgreSQL server: 1. [Check TCP connectivity][rake-maintenance] to the primary's PostgreSQL server:
...@@ -269,7 +270,8 @@ The following guide assumes that: ...@@ -269,7 +270,8 @@ The following guide assumes that:
gitlab-rake gitlab:tcp_check[1.2.3.4,5432] gitlab-rake gitlab:tcp_check[1.2.3.4,5432]
``` ```
> **Note**: If this step fails, you may be using the wrong IP address, or a firewall may NOTE: **Note**:
If this step fails, you may be using the wrong IP address, or a firewall may
be preventing access to the server. Check the IP address, paying close be preventing access to the server. Check the IP address, paying close
attention to the difference between public and private addresses and ensure attention to the difference between public and private addresses and ensure
that, if a firewall is present, the secondary is permitted to connect to the that, if a firewall is present, the secondary is permitted to connect to the
...@@ -368,7 +370,7 @@ The directories used are the defaults that are set up in Omnibus. If you have ...@@ -368,7 +370,7 @@ The directories used are the defaults that are set up in Omnibus. If you have
changed any defaults or are using a source installation, configure it as you changed any defaults or are using a source installation, configure it as you
see fit replacing the directories and paths. see fit replacing the directories and paths.
>**Warning:** CAUTION: **Warning:**
Make sure to run this on the **secondary** server as it removes all PostgreSQL's Make sure to run this on the **secondary** server as it removes all PostgreSQL's
data before running `pg_basebackup`. data before running `pg_basebackup`.
...@@ -384,7 +386,7 @@ data before running `pg_basebackup`. ...@@ -384,7 +386,7 @@ data before running `pg_basebackup`.
name as shown in the commands below. name as shown in the commands below.
1. Execute the command below to start a backup/restore and begin the replication 1. Execute the command below to start a backup/restore and begin the replication
>**Warning:** Each Geo secondary must have its own unique replication slot name. CAUTION: **Warning:** Each Geo secondary must have its own unique replication slot name.
Using the same slot name between two secondaries will break PostgreSQL replication. Using the same slot name between two secondaries will break PostgreSQL replication.
```bash ```bash
......
# Geo database replication (source) # Geo database replication (source)
>**Note:** NOTE: **Note:**
This is the documentation for installations from source. For installations This is the documentation for installations from source. For installations
using the Omnibus GitLab packages, follow the using the Omnibus GitLab packages, follow the
[**database replication for Omnibus GitLab**][database] guide. [**database replication for Omnibus GitLab**][database] guide.
>**Note:** NOTE: **Note:**
The stages of the setup process must be completed in the documented order. The stages of the setup process must be completed in the documented order.
Before attempting the steps in this stage, [complete all prior stages][toc]. Before attempting the steps in this stage, [complete all prior stages][toc].
...@@ -22,7 +22,7 @@ The GitLab primary node where the write operations happen will connect to ...@@ -22,7 +22,7 @@ The GitLab primary node where the write operations happen will connect to
primary database server, and the secondary ones which are read-only will primary database server, and the secondary ones which are read-only will
connect to secondary database servers (which are read-only too). connect to secondary database servers (which are read-only too).
>**Note:** NOTE: **Note:**
In many databases documentation you will see "primary" being referenced as "master" In many databases documentation you will see "primary" being referenced as "master"
and "secondary" as either "slave" or "standby" server (read-only). and "secondary" as either "slave" or "standby" server (read-only).
...@@ -91,10 +91,11 @@ The following guide assumes that: ...@@ -91,10 +91,11 @@ The following guide assumes that:
1. Set up TLS support for the PostgreSQL primary server 1. Set up TLS support for the PostgreSQL primary server
> **Warning**: Only skip this step if you **know** that PostgreSQL traffic CAUTION: **Warning**:
> between the primary and secondary will be secured through some other Only skip this step if you **know** that PostgreSQL traffic
> means, e.g., a known-safe physical network path or a site-to-site VPN that between the primary and secondary will be secured through some other
> you have configured. means, e.g., a known-safe physical network path or a site-to-site VPN that
you have configured.
If you are replicating your database across the open Internet, it is If you are replicating your database across the open Internet, it is
**essential** that the connection is TLS-secured. Correctly configured, this **essential** that the connection is TLS-secured. Correctly configured, this
...@@ -141,6 +142,7 @@ The following guide assumes that: ...@@ -141,6 +142,7 @@ The following guide assumes that:
hot_standby = on hot_standby = on
``` ```
NOTE: **Note**:
Be sure to set `max_replication_slots` to the number of Geo secondary Be sure to set `max_replication_slots` to the number of Geo secondary
nodes that you may potentially have (at least 1). nodes that you may potentially have (at least 1).
...@@ -302,7 +304,7 @@ needed files for streaming replication. ...@@ -302,7 +304,7 @@ needed files for streaming replication.
The directories used are the defaults for Debian/Ubuntu. If you have changed The directories used are the defaults for Debian/Ubuntu. If you have changed
any defaults, configure it as you see fit replacing the directories and paths. any defaults, configure it as you see fit replacing the directories and paths.
>**Warning:** CAUTION: **Warning:**
Make sure to run this on the **secondary** server as it removes all PostgreSQL's Make sure to run this on the **secondary** server as it removes all PostgreSQL's
data before running `pg_basebackup`. data before running `pg_basebackup`.
......
...@@ -102,9 +102,10 @@ in your SAML IdP: ...@@ -102,9 +102,10 @@ in your SAML IdP:
installation to generate the correct value). installation to generate the correct value).
1. Change the values of `idp_cert_fingerprint`, `idp_sso_target_url`, 1. Change the values of `idp_cert_fingerprint`, `idp_sso_target_url`,
`name_identifier_format` to match your IdP. Check `name_identifier_format` to match your IdP. If a fingerprint is used it must
be a SHA1 fingerprint; check
[the omniauth-saml documentation](https://github.com/omniauth/omniauth-saml) [the omniauth-saml documentation](https://github.com/omniauth/omniauth-saml)
for details on these options. for more details on these options.
1. Change the value of `issuer` to a unique name, which will identify the application 1. Change the value of `issuer` to a unique name, which will identify the application
to the IdP. to the IdP.
...@@ -362,6 +363,7 @@ need to be validated using a fingerprint, a certificate or a validator. ...@@ -362,6 +363,7 @@ need to be validated using a fingerprint, a certificate or a validator.
For this you need take the following into account: For this you need take the following into account:
- If a fingerprint is used, it must be the SHA1 fingerprint
- If no certificate is provided in the settings, a fingerprint or fingerprint - If no certificate is provided in the settings, a fingerprint or fingerprint
validator needs to be provided and the response from the server must contain validator needs to be provided and the response from the server must contain
a certificate (`<ds:KeyInfo><ds:X509Data><ds:X509Certificate>`) a certificate (`<ds:KeyInfo><ds:X509Data><ds:X509Certificate>`)
......
...@@ -2,15 +2,12 @@ module EE ...@@ -2,15 +2,12 @@ module EE
module DeploymentPlatform module DeploymentPlatform
extend ::Gitlab::Utils::Override extend ::Gitlab::Utils::Override
override :deployment_platform override :find_cluster_platform_kubernetes
def deployment_platform(environment: nil) def find_cluster_platform_kubernetes(environment: nil)
return super unless environment && feature_available?(:multiple_clusters) return super unless environment && feature_available?(:multiple_clusters)
@deployment_platform ||= # rubocop:disable Gitlab/ModuleWithInstanceVariables
clusters.enabled.on_environment(environment.name) clusters.enabled.on_environment(environment.name)
.last&.platform_kubernetes .last&.platform_kubernetes
super # Wildcard or KubernetesService
end end
end end
end end
...@@ -33,14 +33,15 @@ module Geo ...@@ -33,14 +33,15 @@ module Geo
return if registry.project.wiki_enabled? return if registry.project.wiki_enabled?
registry.last_wiki_sync_failure = nil registry.last_wiki_sync_failure = nil
registry.last_wiki_synced_at = DateTime.now
registry.last_wiki_successful_sync_at = DateTime.now
registry.resync_wiki = false registry.resync_wiki = false
registry.wiki_retry_count = nil registry.wiki_retry_count = nil
registry.wiki_retry_at = nil registry.wiki_retry_at = nil
registry.force_to_redownload_wiki = false registry.force_to_redownload_wiki = false
if registry.changed? if registry.changed? || registry.last_wiki_synced_at.nil? || registry.last_wiki_successful_sync_at.nil?
registry.last_wiki_synced_at = DateTime.now
registry.last_wiki_successful_sync_at = DateTime.now
success = registry.save success = registry.save
log_info("#{success ? 'Successfully marked' : 'Failed to mark'} disabled wiki as synced", registry_id: registry.id, project_id: registry.project_id) log_info("#{success ? 'Successfully marked' : 'Failed to mark'} disabled wiki as synced", registry_id: registry.id, project_id: registry.project_id)
end end
......
---
title: Resolve "undefined method 'log_transfer_error'"
merge_request:
author:
type: fixed
---
title: Fixes incorrect assignation of cluster details
merge_request: 5047
author:
type: fixed
---
title: Hard failing a mirror no longer fails for a blocked user's personal project
merge_request: 5063
author:
type: fixed
---
title: 'Geo: Recovery from temporary directory doesn''t work if the namespace directory
doesn''t exist'
merge_request:
author:
type: fixed
---
title: Define a chat responder for the Slack app
merge_request:
author:
type: fixed
---
title: Geo - Avoid rescheduling the same project again in a backfill condition
merge_request: 5069
author:
type: fixed
---
title: Update Epic documentation to include labels
merge_request:
author:
type: other
---
title: Fix LDAP group sync permission override UI
merge_request: 5003
author:
type: fixed
---
title: Mark disabled wikis as fully synced
merge_request: 5104
author:
type: fixed
---
title: Also log Geo Prometheus metrics from primary
merge_request: 5058
author:
type: added
...@@ -55,24 +55,22 @@ module Gitlab ...@@ -55,24 +55,22 @@ module Gitlab
) )
service.execute(:chat) do |pipeline| service.execute(:chat) do |pipeline|
create_environment_variables(pipeline) build_environment_variables(pipeline)
create_chat_data(pipeline) build_chat_data(pipeline)
end end
end end
# pipeline - The `Ci::Pipeline` to create the environment variables for. # pipeline - The `Ci::Pipeline` to create the environment variables for.
def create_environment_variables(pipeline) def build_environment_variables(pipeline)
pipeline.variables.create!( pipeline.variables.build(
[ [{ key: 'CHAT_INPUT', value: arguments },
{ key: 'CHAT_INPUT', value: arguments }, { key: 'CHAT_CHANNEL', value: channel }]
{ key: 'CHAT_CHANNEL', value: channel }
]
) )
end end
# pipeline - The `Ci::Pipeline` to create the chat data for. # pipeline - The `Ci::Pipeline` to create the chat data for.
def create_chat_data(pipeline) def build_chat_data(pipeline)
pipeline.create_chat_data!( pipeline.build_chat_data(
chat_name_id: chat_name.id, chat_name_id: chat_name.id,
response_url: response_url response_url: response_url
) )
......
...@@ -19,13 +19,13 @@ describe Projects::VariablesController do ...@@ -19,13 +19,13 @@ describe Projects::VariablesController do
let(:variable_attributes) do let(:variable_attributes) do
{ id: variable.id, { id: variable.id,
key: variable.key, key: variable.key,
value: variable.value, secret_value: variable.value,
protected: variable.protected?.to_s, protected: variable.protected?.to_s,
environment_scope: variable.environment_scope } environment_scope: variable.environment_scope }
end end
let(:new_variable_attributes) do let(:new_variable_attributes) do
{ key: 'new_key', { key: 'new_key',
value: 'dummy_value', secret_value: 'dummy_value',
protected: 'false', protected: 'false',
environment_scope: 'new_scope' } environment_scope: 'new_scope' }
end end
......
...@@ -17,7 +17,7 @@ describe 'Project show page', :feature do ...@@ -17,7 +17,7 @@ describe 'Project show page', :feature do
it '"Kubernetes cluster" button linked to clusters page' do it '"Kubernetes cluster" button linked to clusters page' do
create(:cluster, :provided_by_gcp, projects: [project]) create(:cluster, :provided_by_gcp, projects: [project])
create(:cluster, :provided_by_gcp, projects: [project]) create(:cluster, :provided_by_gcp, :production_environment, projects: [project])
visit project_path(project) visit project_path(project)
......
...@@ -4,15 +4,8 @@ describe EE::DeploymentPlatform do ...@@ -4,15 +4,8 @@ describe EE::DeploymentPlatform do
describe '#deployment_platform' do describe '#deployment_platform' do
let(:project) { create(:project) } let(:project) { create(:project) }
context 'when environment is specified' do
let(:environment) { create(:environment, project: project, name: 'review/name') }
let!(:default_cluster) { create(:cluster, :provided_by_user, projects: [project], environment_scope: '*') }
let!(:cluster) { create(:cluster, :provided_by_user, environment_scope: 'review/*', projects: [project]) }
subject { project.deployment_platform(environment: environment) }
shared_examples 'matching environment scope' do shared_examples 'matching environment scope' do
context 'when multiple clusters is available' do context 'when multiple clusters license is available' do
before do before do
stub_licensed_features(multiple_clusters: true) stub_licensed_features(multiple_clusters: true)
end end
...@@ -22,7 +15,7 @@ describe EE::DeploymentPlatform do ...@@ -22,7 +15,7 @@ describe EE::DeploymentPlatform do
end end
end end
context 'when multiple clusters is unavailable' do context 'when multiple clusters licence is unavailable' do
before do before do
stub_licensed_features(multiple_clusters: false) stub_licensed_features(multiple_clusters: false)
end end
...@@ -34,7 +27,7 @@ describe EE::DeploymentPlatform do ...@@ -34,7 +27,7 @@ describe EE::DeploymentPlatform do
end end
shared_examples 'not matching environment scope' do shared_examples 'not matching environment scope' do
context 'when multiple clusters is available' do context 'when multiple clusters license is available' do
before do before do
stub_licensed_features(multiple_clusters: true) stub_licensed_features(multiple_clusters: true)
end end
...@@ -44,7 +37,7 @@ describe EE::DeploymentPlatform do ...@@ -44,7 +37,7 @@ describe EE::DeploymentPlatform do
end end
end end
context 'when multiple clusters is unavailable' do context 'when multiple clusters license is unavailable' do
before do before do
stub_licensed_features(multiple_clusters: false) stub_licensed_features(multiple_clusters: false)
end end
...@@ -55,6 +48,13 @@ describe EE::DeploymentPlatform do ...@@ -55,6 +48,13 @@ describe EE::DeploymentPlatform do
end end
end end
context 'when environment is specified' do
let!(:default_cluster) { create(:cluster, :provided_by_user, projects: [project], environment_scope: '*') }
let!(:cluster) { create(:cluster, :provided_by_user, environment_scope: 'review/*', projects: [project]) }
let(:environment) { create(:environment, project: project, name: 'review/name') }
subject { project.deployment_platform(environment: environment) }
context 'when environment scope is exactly matched' do context 'when environment scope is exactly matched' do
before do before do
cluster.update!(environment_scope: 'review/name') cluster.update!(environment_scope: 'review/name')
...@@ -133,5 +133,21 @@ describe EE::DeploymentPlatform do ...@@ -133,5 +133,21 @@ describe EE::DeploymentPlatform do
end end
end end
end end
context 'with multiple clusters and multiple environments' do
let!(:cluster_1) { create(:cluster, :provided_by_user, projects: [project], environment_scope: 'staging/*') }
let!(:cluster_2) { create(:cluster, :provided_by_user, projects: [project], environment_scope: 'test/*') }
let(:environment_1) { create(:environment, project: project, name: 'staging/name') }
let(:environment_2) { create(:environment, project: project, name: 'test/name') }
before do
stub_licensed_features(multiple_clusters: true)
end
it 'should return the appropriate cluster' do
expect(project.deployment_platform(environment: environment_1)).to eq(cluster_1.platform_kubernetes)
expect(project.deployment_platform(environment: environment_2)).to eq(cluster_2.platform_kubernetes)
end
end
end end
end end
...@@ -9,11 +9,16 @@ module Gitlab ...@@ -9,11 +9,16 @@ module Gitlab
::Ci::Pipeline.transaction do ::Ci::Pipeline.transaction do
pipeline.save! pipeline.save!
@command.seeds_block&.call(pipeline) ##
# Create environments before the pipeline starts.
::Ci::CreatePipelineStagesService #
.new(project, current_user) pipeline.builds.each do |build|
.execute(pipeline) if build.has_environment?
project.environments.find_or_create_by(
name: build.expanded_environment_name
)
end
end
end end
rescue ActiveRecord::RecordInvalid => e rescue ActiveRecord::RecordInvalid => e
error("Failed to persist the pipeline: #{e}") error("Failed to persist the pipeline: #{e}")
......
module Gitlab
module Ci
module Pipeline
module Chain
class Populate < Chain::Base
include Chain::Helpers
PopulateError = Class.new(StandardError)
def perform!
##
# Populate pipeline with block argument of CreatePipelineService#execute.
#
@command.seeds_block&.call(pipeline)
##
# Populate pipeline with all stages and builds from pipeline seeds.
#
pipeline.stage_seeds.each do |stage|
stage.user = current_user
pipeline.stages << stage.to_resource
stage.seeds.each do |build|
pipeline.builds << build.to_resource
end
end
if pipeline.stages.none?
return error('No stages / jobs for this pipeline.')
end
if pipeline.invalid?
return error('Failed to build the pipeline!')
end
raise Populate::PopulateError if pipeline.persisted?
end
def break?
pipeline.errors.any?
end
end
end
end
end
end
...@@ -16,11 +16,7 @@ module Gitlab ...@@ -16,11 +16,7 @@ module Gitlab
@pipeline.drop!(:config_error) @pipeline.drop!(:config_error)
end end
return error(@pipeline.yaml_errors) error(@pipeline.yaml_errors)
end
unless @pipeline.has_stage_seeds?
return error('No stages / jobs for this pipeline.')
end end
end end
......
module Gitlab
module Ci
module Pipeline
module Seed
class Base
def attributes
raise NotImplementedError
end
def included?
raise NotImplementedError
end
def to_resource
raise NotImplementedError
end
end
end
end
end
end
module Gitlab
module Ci
module Pipeline
module Seed
class Build < Seed::Base
include Gitlab::Utils::StrongMemoize
delegate :dig, to: :@attributes
def initialize(pipeline, attributes)
@pipeline = pipeline
@attributes = attributes
@only = attributes.delete(:only)
@except = attributes.delete(:except)
end
def user=(current_user)
@attributes.merge!(user: current_user)
end
def included?
strong_memoize(:inclusion) do
only_specs = Gitlab::Ci::Build::Policy.fabricate(@only)
except_specs = Gitlab::Ci::Build::Policy.fabricate(@except)
only_specs.all? { |spec| spec.satisfied_by?(@pipeline) } &&
except_specs.none? { |spec| spec.satisfied_by?(@pipeline) }
end
end
def attributes
@attributes.merge(
pipeline: @pipeline,
project: @pipeline.project,
ref: @pipeline.ref,
tag: @pipeline.tag,
trigger_request: @pipeline.legacy_trigger,
protected: @pipeline.protected_ref?
)
end
def to_resource
strong_memoize(:resource) do
::Ci::Build.new(attributes)
end
end
end
end
end
end
end
module Gitlab
module Ci
module Pipeline
module Seed
class Stage < Seed::Base
include Gitlab::Utils::StrongMemoize
delegate :size, to: :seeds
delegate :dig, to: :seeds
def initialize(pipeline, attributes)
@pipeline = pipeline
@attributes = attributes
@builds = attributes.fetch(:builds).map do |attributes|
Seed::Build.new(@pipeline, attributes)
end
end
def user=(current_user)
@builds.each { |seed| seed.user = current_user }
end
def attributes
{ name: @attributes.fetch(:name),
pipeline: @pipeline,
project: @pipeline.project }
end
def seeds
strong_memoize(:seeds) do
@builds.select(&:included?)
end
end
def included?
seeds.any?
end
def to_resource
strong_memoize(:stage) do
::Ci::Stage.new(attributes).tap do |stage|
seeds.each { |seed| stage.builds << seed.to_resource }
end
end
end
end
end
end
end
end
module Gitlab
module Ci
module Stage
class Seed
include ::Gitlab::Utils::StrongMemoize
attr_reader :pipeline
delegate :project, to: :pipeline
delegate :size, to: :@jobs
def initialize(pipeline, stage, jobs)
@pipeline = pipeline
@stage = { name: stage }
@jobs = jobs.to_a.dup
end
def user=(current_user)
@jobs.map! do |attributes|
attributes.merge(user: current_user)
end
end
def stage
@stage.merge(project: project)
end
def builds
trigger = pipeline.trigger_requests.first
@jobs.map do |attributes|
attributes.merge(project: project,
ref: pipeline.ref,
tag: pipeline.tag,
trigger_request: trigger,
protected: protected_ref?)
end
end
def create!
pipeline.stages.create!(stage).tap do |stage|
builds_attributes = builds.map do |attributes|
attributes.merge(stage_id: stage.id)
end
pipeline.builds.create!(builds_attributes).each do |build|
yield build if block_given?
end
end
end
private
def protected_ref?
strong_memoize(:protected_ref) do
project.protected_for?(pipeline.ref)
end
end
end
end
end
end
...@@ -27,7 +27,7 @@ module Gitlab ...@@ -27,7 +27,7 @@ module Gitlab
end end
def build_attributes(name) def build_attributes(name)
job = @jobs[name.to_sym] || {} job = @jobs.fetch(name.to_sym, {})
{ stage_idx: @stages.index(job[:stage]), { stage_idx: @stages.index(job[:stage]),
stage: job[:stage], stage: job[:stage],
...@@ -53,30 +53,24 @@ module Gitlab ...@@ -53,30 +53,24 @@ module Gitlab
}.compact } }.compact }
end end
def pipeline_stage_builds(stage, pipeline) def stage_builds_attributes(stage)
selected_jobs = @jobs.select do |_, job| @jobs.values
next unless job[:stage] == stage .select { |job| job[:stage] == stage }
.map { |job| build_attributes(job[:name]) }
only_specs = Gitlab::Ci::Build::Policy
.fabricate(job.fetch(:only, {}))
except_specs = Gitlab::Ci::Build::Policy
.fabricate(job.fetch(:except, {}))
only_specs.all? { |spec| spec.satisfied_by?(pipeline) } &&
except_specs.none? { |spec| spec.satisfied_by?(pipeline) }
end end
selected_jobs.map { |_, job| build_attributes(job[:name]) } def stages_attributes
end @stages.uniq.map do |stage|
seeds = stage_builds_attributes(stage).map do |attributes|
job = @jobs.fetch(attributes[:name].to_sym)
def stage_seeds(pipeline) attributes
seeds = @stages.uniq.map do |stage| .merge(only: job.fetch(:only, {}))
builds = pipeline_stage_builds(stage, pipeline) .merge(except: job.fetch(:except, {}))
Gitlab::Ci::Stage::Seed.new(pipeline, stage, builds) if builds.any?
end end
seeds.compact { name: stage, index: @stages.index(stage), builds: seeds }
end
end end
def self.validation_message(content, opts = {}) def self.validation_message(content, opts = {})
......
...@@ -18,7 +18,7 @@ describe Projects::ClustersController do ...@@ -18,7 +18,7 @@ describe Projects::ClustersController do
context 'when project has one or more clusters' do context 'when project has one or more clusters' do
let(:project) { create(:project) } let(:project) { create(:project) }
let!(:enabled_cluster) { create(:cluster, :provided_by_gcp, projects: [project]) } let!(:enabled_cluster) { create(:cluster, :provided_by_gcp, projects: [project]) }
let!(:disabled_cluster) { create(:cluster, :disabled, :provided_by_gcp, projects: [project]) } let!(:disabled_cluster) { create(:cluster, :disabled, :provided_by_gcp, :production_environment, projects: [project]) }
it 'lists available clusters' do it 'lists available clusters' do
go go
...@@ -32,7 +32,7 @@ describe Projects::ClustersController do ...@@ -32,7 +32,7 @@ describe Projects::ClustersController do
before do before do
allow(Clusters::Cluster).to receive(:paginates_per).and_return(1) allow(Clusters::Cluster).to receive(:paginates_per).and_return(1)
create_list(:cluster, 2, :provided_by_gcp, projects: [project]) create_list(:cluster, 2, :provided_by_gcp, :production_environment, projects: [project])
get :index, namespace_id: project.namespace, project_id: project, page: last_page get :index, namespace_id: project.namespace, project_id: project, page: last_page
end end
...@@ -420,7 +420,7 @@ describe Projects::ClustersController do ...@@ -420,7 +420,7 @@ describe Projects::ClustersController do
context 'when cluster is provided by GCP' do context 'when cluster is provided by GCP' do
context 'when cluster is created' do context 'when cluster is created' do
let!(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) } let!(:cluster) { create(:cluster, :provided_by_gcp, :production_environment, projects: [project]) }
it "destroys and redirects back to clusters list" do it "destroys and redirects back to clusters list" do
expect { go } expect { go }
...@@ -434,7 +434,7 @@ describe Projects::ClustersController do ...@@ -434,7 +434,7 @@ describe Projects::ClustersController do
end end
context 'when cluster is being created' do context 'when cluster is being created' do
let!(:cluster) { create(:cluster, :providing_by_gcp, projects: [project]) } let!(:cluster) { create(:cluster, :providing_by_gcp, :production_environment, projects: [project]) }
it "destroys and redirects back to clusters list" do it "destroys and redirects back to clusters list" do
expect { go } expect { go }
...@@ -448,7 +448,7 @@ describe Projects::ClustersController do ...@@ -448,7 +448,7 @@ describe Projects::ClustersController do
end end
context 'when cluster is provided by user' do context 'when cluster is provided by user' do
let!(:cluster) { create(:cluster, :provided_by_user, projects: [project]) } let!(:cluster) { create(:cluster, :provided_by_user, :production_environment, projects: [project]) }
it "destroys and redirects back to clusters list" do it "destroys and redirects back to clusters list" do
expect { go } expect { go }
...@@ -463,7 +463,7 @@ describe Projects::ClustersController do ...@@ -463,7 +463,7 @@ describe Projects::ClustersController do
end end
describe 'security' do describe 'security' do
set(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) } set(:cluster) { create(:cluster, :provided_by_gcp, :production_environment, projects: [project]) }
it { expect { go }.to be_allowed_for(:admin) } it { expect { go }.to be_allowed_for(:admin) }
it { expect { go }.to be_allowed_for(:owner).of(project) } it { expect { go }.to be_allowed_for(:owner).of(project) }
......
...@@ -80,7 +80,7 @@ describe Projects::PipelineSchedulesController do ...@@ -80,7 +80,7 @@ describe Projects::PipelineSchedulesController do
context 'when variables_attributes has one variable' do context 'when variables_attributes has one variable' do
let(:schedule) do let(:schedule) do
basic_param.merge({ basic_param.merge({
variables_attributes: [{ key: 'AAA', value: 'AAA123' }] variables_attributes: [{ key: 'AAA', secret_value: 'AAA123' }]
}) })
end end
...@@ -101,7 +101,8 @@ describe Projects::PipelineSchedulesController do ...@@ -101,7 +101,8 @@ describe Projects::PipelineSchedulesController do
context 'when variables_attributes has two variables and duplicated' do context 'when variables_attributes has two variables and duplicated' do
let(:schedule) do let(:schedule) do
basic_param.merge({ basic_param.merge({
variables_attributes: [{ key: 'AAA', value: 'AAA123' }, { key: 'AAA', value: 'BBB123' }] variables_attributes: [{ key: 'AAA', secret_value: 'AAA123' },
{ key: 'AAA', secret_value: 'BBB123' }]
}) })
end end
...@@ -152,7 +153,7 @@ describe Projects::PipelineSchedulesController do ...@@ -152,7 +153,7 @@ describe Projects::PipelineSchedulesController do
context 'when params include one variable' do context 'when params include one variable' do
let(:schedule) do let(:schedule) do
basic_param.merge({ basic_param.merge({
variables_attributes: [{ key: 'AAA', value: 'AAA123' }] variables_attributes: [{ key: 'AAA', secret_value: 'AAA123' }]
}) })
end end
...@@ -169,7 +170,8 @@ describe Projects::PipelineSchedulesController do ...@@ -169,7 +170,8 @@ describe Projects::PipelineSchedulesController do
context 'when params include two duplicated variables' do context 'when params include two duplicated variables' do
let(:schedule) do let(:schedule) do
basic_param.merge({ basic_param.merge({
variables_attributes: [{ key: 'AAA', value: 'AAA123' }, { key: 'AAA', value: 'BBB123' }] variables_attributes: [{ key: 'AAA', secret_value: 'AAA123' },
{ key: 'AAA', secret_value: 'BBB123' }]
}) })
end end
...@@ -194,7 +196,7 @@ describe Projects::PipelineSchedulesController do ...@@ -194,7 +196,7 @@ describe Projects::PipelineSchedulesController do
context 'when adds a new variable' do context 'when adds a new variable' do
let(:schedule) do let(:schedule) do
basic_param.merge({ basic_param.merge({
variables_attributes: [{ key: 'AAA', value: 'AAA123' }] variables_attributes: [{ key: 'AAA', secret_value: 'AAA123' }]
}) })
end end
...@@ -209,7 +211,7 @@ describe Projects::PipelineSchedulesController do ...@@ -209,7 +211,7 @@ describe Projects::PipelineSchedulesController do
context 'when adds a new duplicated variable' do context 'when adds a new duplicated variable' do
let(:schedule) do let(:schedule) do
basic_param.merge({ basic_param.merge({
variables_attributes: [{ key: 'CCC', value: 'AAA123' }] variables_attributes: [{ key: 'CCC', secret_value: 'AAA123' }]
}) })
end end
...@@ -224,7 +226,7 @@ describe Projects::PipelineSchedulesController do ...@@ -224,7 +226,7 @@ describe Projects::PipelineSchedulesController do
context 'when updates a variable' do context 'when updates a variable' do
let(:schedule) do let(:schedule) do
basic_param.merge({ basic_param.merge({
variables_attributes: [{ id: pipeline_schedule_variable.id, value: 'new_value' }] variables_attributes: [{ id: pipeline_schedule_variable.id, secret_value: 'new_value' }]
}) })
end end
...@@ -252,7 +254,7 @@ describe Projects::PipelineSchedulesController do ...@@ -252,7 +254,7 @@ describe Projects::PipelineSchedulesController do
let(:schedule) do let(:schedule) do
basic_param.merge({ basic_param.merge({
variables_attributes: [{ id: pipeline_schedule_variable.id, _destroy: true }, variables_attributes: [{ id: pipeline_schedule_variable.id, _destroy: true },
{ key: 'CCC', value: 'CCC123' }] { key: 'CCC', secret_value: 'CCC123' }]
}) })
end end
......
...@@ -2,11 +2,10 @@ FactoryBot.define do ...@@ -2,11 +2,10 @@ FactoryBot.define do
factory :cluster, class: Clusters::Cluster do factory :cluster, class: Clusters::Cluster do
user user
name 'test-cluster' name 'test-cluster'
sequence(:environment_scope) { |n| "production#{n}/*" }
trait :project do trait :project do
before(:create) do |cluster, evaluator| before(:create) do |cluster, evaluator|
cluster.projects << create(:project) cluster.projects << create(:project, :repository)
end end
end end
...@@ -33,5 +32,9 @@ FactoryBot.define do ...@@ -33,5 +32,9 @@ FactoryBot.define do
trait :disabled do trait :disabled do
enabled false enabled false
end end
trait :production_environment do
sequence(:environment_scope) { |n| "production#{n}/*" }
end
end end
end end
...@@ -55,14 +55,19 @@ feature 'Admin disables Git access protocol' do ...@@ -55,14 +55,19 @@ feature 'Admin disables Git access protocol' do
end end
def disable_http_protocol def disable_http_protocol
visit admin_application_settings_path switch_git_protocol(2)
find('#application_setting_enabled_git_access_protocol').find(:xpath, 'option[2]').select_option
click_on 'Save'
end end
def disable_ssh_protocol def disable_ssh_protocol
switch_git_protocol(3)
end
def switch_git_protocol(value)
visit admin_application_settings_path visit admin_application_settings_path
find('#application_setting_enabled_git_access_protocol').find(:xpath, 'option[3]').select_option
page.within('.as-visibility-access') do
find('#application_setting_enabled_git_access_protocol').find(:xpath, "option[#{value}]").select_option
click_on 'Save' click_on 'Save'
end end
end
end end
...@@ -10,18 +10,21 @@ feature 'Admin updates settings' do ...@@ -10,18 +10,21 @@ feature 'Admin updates settings' do
end end
scenario 'Change visibility settings' do scenario 'Change visibility settings' do
page.within('.as-visibility-access') do
choose "application_setting_default_project_visibility_20" choose "application_setting_default_project_visibility_20"
click_button 'Save' click_button 'Save changes'
end
expect(page).to have_content "Application settings saved successfully" expect(page).to have_content "Application settings saved successfully"
end end
scenario 'Uncheck all restricted visibility levels' do scenario 'Uncheck all restricted visibility levels' do
page.within('.as-visibility-access') do
find('#application_setting_visibility_level_0').set(false) find('#application_setting_visibility_level_0').set(false)
find('#application_setting_visibility_level_10').set(false) find('#application_setting_visibility_level_10').set(false)
find('#application_setting_visibility_level_20').set(false) find('#application_setting_visibility_level_20').set(false)
click_button 'Save changes'
click_button 'Save' end
expect(page).to have_content "Application settings saved successfully" expect(page).to have_content "Application settings saved successfully"
expect(find('#application_setting_visibility_level_0')).not_to be_checked expect(find('#application_setting_visibility_level_0')).not_to be_checked
...@@ -35,8 +38,10 @@ feature 'Admin updates settings' do ...@@ -35,8 +38,10 @@ feature 'Admin updates settings' do
allow(Gitlab::Auth::LDAP::Config).to receive(:enabled?).and_return(true) allow(Gitlab::Auth::LDAP::Config).to receive(:enabled?).and_return(true)
visit admin_application_settings_path visit admin_application_settings_path
page.within('.as-visibility-access') do
find('#application_setting_allow_group_owners_to_manage_ldap').set(false) find('#application_setting_allow_group_owners_to_manage_ldap').set(false)
click_button 'Save' click_button 'Save'
end
expect(page).to have_content('Application settings saved successfully') expect(page).to have_content('Application settings saved successfully')
expect(find('#application_setting_allow_group_owners_to_manage_ldap')).not_to be_checked expect(find('#application_setting_allow_group_owners_to_manage_ldap')).not_to be_checked
...@@ -52,21 +57,59 @@ feature 'Admin updates settings' do ...@@ -52,21 +57,59 @@ feature 'Admin updates settings' do
end end
end end
scenario 'Change application settings' do scenario 'Change Visibility and Access Controls' do
page.within('.as-visibility-access') do
uncheck 'Project export enabled'
click_button 'Save changes'
end
expect(Gitlab::CurrentSettings.project_export_enabled).to be_falsey
expect(page).to have_content "Application settings saved successfully"
end
scenario 'Change Account and Limit Settings' do
page.within('.as-account-limit') do
uncheck 'Gravatar enabled' uncheck 'Gravatar enabled'
click_button 'Save changes'
end
expect(Gitlab::CurrentSettings.gravatar_enabled).to be_falsey
expect(page).to have_content "Application settings saved successfully"
end
scenario 'Change Sign-in restrictions' do
page.within('.as-signin') do
fill_in 'Home page URL', with: 'https://about.gitlab.com/' fill_in 'Home page URL', with: 'https://about.gitlab.com/'
click_button 'Save changes'
end
expect(Gitlab::CurrentSettings.home_page_url).to eq "https://about.gitlab.com/"
expect(page).to have_content "Application settings saved successfully"
end
scenario 'Change Help page' do
page.within('.as-help-page') do
fill_in 'Help page text', with: 'Example text' fill_in 'Help page text', with: 'Example text'
check 'Hide marketing-related entries from help' check 'Hide marketing-related entries from help'
fill_in 'Support page URL', with: 'http://example.com/help' fill_in 'Support page URL', with: 'http://example.com/help'
uncheck 'Project export enabled' click_button 'Save changes'
click_button 'Save' end
expect(Gitlab::CurrentSettings.gravatar_enabled).to be_falsey
expect(Gitlab::CurrentSettings.home_page_url).to eq "https://about.gitlab.com/"
expect(Gitlab::CurrentSettings.help_page_text).to eq "Example text" expect(Gitlab::CurrentSettings.help_page_text).to eq "Example text"
expect(Gitlab::CurrentSettings.help_page_hide_commercial_content).to be_truthy expect(Gitlab::CurrentSettings.help_page_hide_commercial_content).to be_truthy
expect(Gitlab::CurrentSettings.help_page_support_url).to eq "http://example.com/help" expect(Gitlab::CurrentSettings.help_page_support_url).to eq "http://example.com/help"
expect(Gitlab::CurrentSettings.project_export_enabled).to be_falsey expect(page).to have_content "Application settings saved successfully"
end
scenario 'Change Pages settings' do
page.within('.as-pages') do
fill_in 'Maximum size of pages (MB)', with: 15
check 'Require users to prove ownership of custom domains'
click_button 'Save changes'
end
expect(Gitlab::CurrentSettings.max_pages_size).to eq 15
expect(Gitlab::CurrentSettings.pages_domain_verification_enabled?).to be_truthy
expect(page).to have_content "Application settings saved successfully" expect(page).to have_content "Application settings saved successfully"
end end
...@@ -106,18 +149,22 @@ feature 'Admin updates settings' do ...@@ -106,18 +149,22 @@ feature 'Admin updates settings' do
context 'sign-in restrictions', :js do context 'sign-in restrictions', :js do
it 'de-activates oauth sign-in source' do it 'de-activates oauth sign-in source' do
page.within('.as-signin') do
find('input#application_setting_enabled_oauth_sign_in_sources_[value=gitlab]').send_keys(:return) find('input#application_setting_enabled_oauth_sign_in_sources_[value=gitlab]').send_keys(:return)
expect(find('.btn', text: 'GitLab.com')).not_to have_css('.active') expect(find('.btn', text: 'GitLab.com')).not_to have_css('.active')
end end
end end
end
scenario 'Change Keys settings' do scenario 'Change Keys settings' do
page.within('.as-visibility-access') do
select 'Are forbidden', from: 'RSA SSH keys' select 'Are forbidden', from: 'RSA SSH keys'
select 'Are allowed', from: 'DSA SSH keys' select 'Are allowed', from: 'DSA SSH keys'
select 'Must be at least 384 bits', from: 'ECDSA SSH keys' select 'Must be at least 384 bits', from: 'ECDSA SSH keys'
select 'Are forbidden', from: 'ED25519 SSH keys' select 'Are forbidden', from: 'ED25519 SSH keys'
click_on 'Save' click_on 'Save changes'
end
forbidden = ApplicationSetting::FORBIDDEN_KEY_VALUE.to_s forbidden = ApplicationSetting::FORBIDDEN_KEY_VALUE.to_s
......
...@@ -160,9 +160,9 @@ feature 'Pipeline Schedules', :js do ...@@ -160,9 +160,9 @@ feature 'Pipeline Schedules', :js do
click_link 'New schedule' click_link 'New schedule'
fill_in_schedule_form fill_in_schedule_form
all('[name="schedule[variables_attributes][][key]"]')[0].set('AAA') all('[name="schedule[variables_attributes][][key]"]')[0].set('AAA')
all('[name="schedule[variables_attributes][][value]"]')[0].set('AAA123') all('[name="schedule[variables_attributes][][secret_value]"]')[0].set('AAA123')
all('[name="schedule[variables_attributes][][key]"]')[1].set('BBB') all('[name="schedule[variables_attributes][][key]"]')[1].set('BBB')
all('[name="schedule[variables_attributes][][value]"]')[1].set('BBB123') all('[name="schedule[variables_attributes][][secret_value]"]')[1].set('BBB123')
save_pipeline_schedule save_pipeline_schedule
end end
......
...@@ -6,7 +6,7 @@ describe ClustersFinder do ...@@ -6,7 +6,7 @@ describe ClustersFinder do
describe '#execute' do describe '#execute' do
let(:enabled_cluster) { create(:cluster, :provided_by_gcp, projects: [project]) } let(:enabled_cluster) { create(:cluster, :provided_by_gcp, projects: [project]) }
let(:disabled_cluster) { create(:cluster, :disabled, :provided_by_gcp, projects: [project]) } let(:disabled_cluster) { create(:cluster, :disabled, :provided_by_gcp, :production_environment, projects: [project]) }
subject { described_class.new(project, user, scope).execute } subject { described_class.new(project, user, scope).execute }
......
...@@ -20,7 +20,7 @@ describe('NativeFormVariableList', () => { ...@@ -20,7 +20,7 @@ describe('NativeFormVariableList', () => {
it('should clear out the `name` attribute on the inputs for the last empty row on form submission (avoid BE validation)', () => { it('should clear out the `name` attribute on the inputs for the last empty row on form submission (avoid BE validation)', () => {
const $row = $wrapper.find('.js-row'); const $row = $wrapper.find('.js-row');
expect($row.find('.js-ci-variable-input-key').attr('name')).toBe('schedule[variables_attributes][][key]'); expect($row.find('.js-ci-variable-input-key').attr('name')).toBe('schedule[variables_attributes][][key]');
expect($row.find('.js-ci-variable-input-value').attr('name')).toBe('schedule[variables_attributes][][value]'); expect($row.find('.js-ci-variable-input-value').attr('name')).toBe('schedule[variables_attributes][][secret_value]');
$wrapper.closest('form').trigger('trigger-submit'); $wrapper.closest('form').trigger('trigger-submit');
......
...@@ -74,6 +74,10 @@ describe('Multi-file editor library', () => { ...@@ -74,6 +74,10 @@ describe('Multi-file editor library', () => {
}, },
readOnly: true, readOnly: true,
scrollBeyondLastLine: false, scrollBeyondLastLine: false,
quickSuggestions: false,
occurrencesHighlight: false,
renderLineHighlight: 'none',
hideCursorInOverviewRuler: true,
}, },
); );
}); });
......
...@@ -5,23 +5,23 @@ describe Gitlab::Ci::Pipeline::Chain::Create do ...@@ -5,23 +5,23 @@ describe Gitlab::Ci::Pipeline::Chain::Create do
set(:user) { create(:user) } set(:user) { create(:user) }
let(:pipeline) do let(:pipeline) do
build(:ci_pipeline_with_one_job, project: project, build(:ci_empty_pipeline, project: project, ref: 'master')
ref: 'master')
end end
let(:command) do let(:command) do
Gitlab::Ci::Pipeline::Chain::Command.new( Gitlab::Ci::Pipeline::Chain::Command.new(
project: project, project: project, current_user: user)
current_user: user, seeds_block: nil)
end end
let(:step) { described_class.new(pipeline, command) } let(:step) { described_class.new(pipeline, command) }
context 'when pipeline is ready to be saved' do
before do before do
pipeline.stages.build(name: 'test', project: project)
step.perform! step.perform!
end end
context 'when pipeline is ready to be saved' do
it 'saves a pipeline' do it 'saves a pipeline' do
expect(pipeline).to be_persisted expect(pipeline).to be_persisted
end end
...@@ -32,6 +32,7 @@ describe Gitlab::Ci::Pipeline::Chain::Create do ...@@ -32,6 +32,7 @@ describe Gitlab::Ci::Pipeline::Chain::Create do
it 'creates stages' do it 'creates stages' do
expect(pipeline.reload.stages).to be_one expect(pipeline.reload.stages).to be_one
expect(pipeline.stages.first).to be_persisted
end end
end end
...@@ -40,6 +41,10 @@ describe Gitlab::Ci::Pipeline::Chain::Create do ...@@ -40,6 +41,10 @@ describe Gitlab::Ci::Pipeline::Chain::Create do
build(:ci_pipeline, project: project, ref: nil) build(:ci_pipeline, project: project, ref: nil)
end end
before do
step.perform!
end
it 'breaks the chain' do it 'breaks the chain' do
expect(step.break?).to be true expect(step.break?).to be true
end end
...@@ -49,18 +54,4 @@ describe Gitlab::Ci::Pipeline::Chain::Create do ...@@ -49,18 +54,4 @@ describe Gitlab::Ci::Pipeline::Chain::Create do
.to include /Failed to persist the pipeline/ .to include /Failed to persist the pipeline/
end end
end end
context 'when there is a seed block present' do
let(:seeds) { spy('pipeline seeds') }
let(:command) do
double('command', project: project,
current_user: user,
seeds_block: seeds)
end
it 'executes the block' do
expect(seeds).to have_received(:call).with(pipeline)
end
end
end end
require 'spec_helper'
describe Gitlab::Ci::Pipeline::Chain::Populate do
set(:project) { create(:project, :repository) }
set(:user) { create(:user) }
let(:pipeline) do
build(:ci_pipeline_with_one_job, project: project,
ref: 'master')
end
let(:command) do
Gitlab::Ci::Pipeline::Chain::Command.new(
project: project,
current_user: user,
seeds_block: nil)
end
let(:step) { described_class.new(pipeline, command) }
context 'when pipeline doesn not have seeds block' do
before do
step.perform!
end
it 'does not persist the pipeline' do
expect(pipeline).not_to be_persisted
end
it 'does not break the chain' do
expect(step.break?).to be false
end
it 'populates pipeline with stages' do
expect(pipeline.stages).to be_one
expect(pipeline.stages.first).not_to be_persisted
end
it 'populates pipeline with builds' do
expect(pipeline.builds).to be_one
expect(pipeline.builds.first).not_to be_persisted
expect(pipeline.stages.first.builds).to be_one
expect(pipeline.stages.first.builds.first).not_to be_persisted
end
end
context 'when pipeline is empty' do
let(:config) do
{ rspec: {
script: 'ls',
only: ['something']
} }
end
let(:pipeline) do
build(:ci_pipeline, project: project, config: config)
end
before do
step.perform!
end
it 'breaks the chain' do
expect(step.break?).to be true
end
it 'appends an error about missing stages' do
expect(pipeline.errors.to_a)
.to include 'No stages / jobs for this pipeline.'
end
end
context 'when pipeline has validation errors' do
let(:pipeline) do
build(:ci_pipeline, project: project, ref: nil)
end
before do
step.perform!
end
it 'breaks the chain' do
expect(step.break?).to be true
end
it 'appends validation error' do
expect(pipeline.errors.to_a)
.to include 'Failed to build the pipeline!'
end
end
context 'when there is a seed blocks present' do
let(:command) do
Gitlab::Ci::Pipeline::Chain::Command.new(
project: project,
current_user: user,
seeds_block: seeds_block)
end
context 'when seeds block builds some resources' do
let(:seeds_block) do
->(pipeline) { pipeline.variables.build(key: 'VAR', value: '123') }
end
it 'populates pipeline with resources described in the seeds block' do
step.perform!
expect(pipeline).not_to be_persisted
expect(pipeline.variables).not_to be_empty
expect(pipeline.variables.first).not_to be_persisted
expect(pipeline.variables.first.key).to eq 'VAR'
expect(pipeline.variables.first.value).to eq '123'
end
end
context 'when seeds block tries to persist some resources' do
let(:seeds_block) do
->(pipeline) { pipeline.variables.create!(key: 'VAR', value: '123') }
end
it 'raises exception' do
expect { step.perform! }.to raise_error(ActiveRecord::RecordNotSaved)
end
end
end
context 'when pipeline gets persisted during the process' do
let(:pipeline) { create(:ci_pipeline, project: project) }
it 'raises error' do
expect { step.perform! }.to raise_error(described_class::PopulateError)
end
end
context 'when using only/except build policies' do
let(:config) do
{ rspec: { script: 'rspec', stage: 'test', only: ['master'] },
prod: { script: 'cap prod', stage: 'deploy', only: ['tags'] } }
end
let(:pipeline) do
build(:ci_pipeline, ref: 'master', project: project, config: config)
end
it 'populates pipeline according to used policies' do
step.perform!
expect(pipeline.stages.size).to eq 1
expect(pipeline.builds.size).to eq 1
expect(pipeline.builds.first.name).to eq 'rspec'
end
end
end
...@@ -76,28 +76,6 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Config do ...@@ -76,28 +76,6 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Config do
end end
end end
context 'when pipeline has no stages / jobs' do
let(:config) do
{ rspec: {
script: 'ls',
only: ['something']
} }
end
let(:pipeline) do
build(:ci_pipeline, project: project, config: config)
end
it 'appends an error about missing stages' do
expect(pipeline.errors.to_a)
.to include 'No stages / jobs for this pipeline.'
end
it 'breaks the chain' do
expect(step.break?).to be true
end
end
context 'when pipeline contains configuration validation errors' do context 'when pipeline contains configuration validation errors' do
let(:config) { { rspec: {} } } let(:config) { { rspec: {} } }
......
require 'spec_helper'
describe Gitlab::Ci::Pipeline::Seed::Build do
let(:pipeline) { create(:ci_empty_pipeline) }
let(:attributes) do
{ name: 'rspec',
ref: 'master',
commands: 'rspec' }
end
subject do
described_class.new(pipeline, attributes)
end
describe '#attributes' do
it 'returns hash attributes of a build' do
expect(subject.attributes).to be_a Hash
expect(subject.attributes)
.to include(:name, :project, :ref, :commands)
end
end
describe '#user=' do
let(:user) { build(:user) }
it 'assignes user to a build' do
subject.user = user
expect(subject.attributes).to include(user: user)
end
end
describe '#to_resource' do
it 'returns a valid build resource' do
expect(subject.to_resource).to be_a(::Ci::Build)
expect(subject.to_resource).to be_valid
end
it 'memoizes a resource object' do
build = subject.to_resource
expect(build.object_id).to eq subject.to_resource.object_id
end
it 'can not be persisted without explicit assignment' do
build = subject.to_resource
pipeline.save!
expect(build).not_to be_persisted
end
end
describe 'applying only/except policies' do
context 'when no branch policy is specified' do
let(:attributes) { { name: 'rspec' } }
it { is_expected.to be_included }
end
context 'when branch policy does not match' do
context 'when using only' do
let(:attributes) { { name: 'rspec', only: { refs: ['deploy'] } } }
it { is_expected.not_to be_included }
end
context 'when using except' do
let(:attributes) { { name: 'rspec', except: { refs: ['deploy'] } } }
it { is_expected.to be_included }
end
end
context 'when branch regexp policy does not match' do
context 'when using only' do
let(:attributes) { { name: 'rspec', only: { refs: ['/^deploy$/'] } } }
it { is_expected.not_to be_included }
end
context 'when using except' do
let(:attributes) { { name: 'rspec', except: { refs: ['/^deploy$/'] } } }
it { is_expected.to be_included }
end
end
context 'when branch policy matches' do
context 'when using only' do
let(:attributes) { { name: 'rspec', only: { refs: %w[deploy master] } } }
it { is_expected.to be_included }
end
context 'when using except' do
let(:attributes) { { name: 'rspec', except: { refs: %w[deploy master] } } }
it { is_expected.not_to be_included }
end
end
context 'when keyword policy matches' do
context 'when using only' do
let(:attributes) { { name: 'rspec', only: { refs: ['branches'] } } }
it { is_expected.to be_included }
end
context 'when using except' do
let(:attributes) { { name: 'rspec', except: { refs: ['branches'] } } }
it { is_expected.not_to be_included }
end
end
context 'when keyword policy does not match' do
context 'when using only' do
let(:attributes) { { name: 'rspec', only: { refs: ['tags'] } } }
it { is_expected.not_to be_included }
end
context 'when using except' do
let(:attributes) { { name: 'rspec', except: { refs: ['tags'] } } }
it { is_expected.to be_included }
end
end
context 'when keywords and pipeline source policy matches' do
possibilities = [%w[pushes push],
%w[web web],
%w[triggers trigger],
%w[schedules schedule],
%w[api api],
%w[external external]]
context 'when using only' do
possibilities.each do |keyword, source|
context "when using keyword `#{keyword}` and source `#{source}`" do
let(:pipeline) do
build(:ci_empty_pipeline, ref: 'deploy', tag: false, source: source)
end
let(:attributes) { { name: 'rspec', only: { refs: [keyword] } } }
it { is_expected.to be_included }
end
end
end
context 'when using except' do
possibilities.each do |keyword, source|
context "when using keyword `#{keyword}` and source `#{source}`" do
let(:pipeline) do
build(:ci_empty_pipeline, ref: 'deploy', tag: false, source: source)
end
let(:attributes) { { name: 'rspec', except: { refs: [keyword] } } }
it { is_expected.not_to be_included }
end
end
end
end
context 'when keywords and pipeline source does not match' do
possibilities = [%w[pushes web],
%w[web push],
%w[triggers schedule],
%w[schedules external],
%w[api trigger],
%w[external api]]
context 'when using only' do
possibilities.each do |keyword, source|
context "when using keyword `#{keyword}` and source `#{source}`" do
let(:pipeline) do
build(:ci_empty_pipeline, ref: 'deploy', tag: false, source: source)
end
let(:attributes) { { name: 'rspec', only: { refs: [keyword] } } }
it { is_expected.not_to be_included }
end
end
end
context 'when using except' do
possibilities.each do |keyword, source|
context "when using keyword `#{keyword}` and source `#{source}`" do
let(:pipeline) do
build(:ci_empty_pipeline, ref: 'deploy', tag: false, source: source)
end
let(:attributes) { { name: 'rspec', except: { refs: [keyword] } } }
it { is_expected.to be_included }
end
end
end
end
context 'when repository path matches' do
context 'when using only' do
let(:attributes) do
{ name: 'rspec', only: { refs: ["branches@#{pipeline.project_full_path}"] } }
end
it { is_expected.to be_included }
end
context 'when using except' do
let(:attributes) do
{ name: 'rspec', except: { refs: ["branches@#{pipeline.project_full_path}"] } }
end
it { is_expected.not_to be_included }
end
end
context 'when repository path does not matches' do
context 'when using only' do
let(:attributes) do
{ name: 'rspec', only: { refs: ['branches@fork'] } }
end
it { is_expected.not_to be_included }
end
context 'when using except' do
let(:attributes) do
{ name: 'rspec', except: { refs: ['branches@fork'] } }
end
it { is_expected.to be_included }
end
end
end
end
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Stage::Seed do describe Gitlab::Ci::Pipeline::Seed::Stage do
let(:pipeline) { create(:ci_empty_pipeline) } let(:pipeline) { create(:ci_empty_pipeline) }
let(:builds) do let(:attributes) do
[{ name: 'rspec' }, { name: 'spinach' }] { name: 'test',
index: 0,
builds: [{ name: 'rspec' },
{ name: 'spinach' },
{ name: 'deploy', only: { refs: ['feature'] } }] }
end end
subject do subject do
described_class.new(pipeline, 'test', builds) described_class.new(pipeline, attributes)
end end
describe '#size' do describe '#size' do
...@@ -17,20 +21,46 @@ describe Gitlab::Ci::Stage::Seed do ...@@ -17,20 +21,46 @@ describe Gitlab::Ci::Stage::Seed do
end end
end end
describe '#stage' do describe '#attributes' do
it 'returns hash attributes of a stage' do it 'returns hash attributes of a stage' do
expect(subject.stage).to be_a Hash expect(subject.attributes).to be_a Hash
expect(subject.stage).to include(:name, :project) expect(subject.attributes).to include(:name, :project)
end end
end end
describe '#builds' do describe '#included?' do
it 'returns hash attributes of all builds' do context 'when it contains builds seeds' do
expect(subject.builds.size).to eq 2 let(:attributes) do
expect(subject.builds).to all(include(ref: 'master')) { name: 'test',
expect(subject.builds).to all(include(tag: false)) index: 0,
expect(subject.builds).to all(include(project: pipeline.project)) builds: [{ name: 'deploy', only: { refs: ['master'] } }] }
expect(subject.builds) end
it { is_expected.to be_included }
end
context 'when it does not contain build seeds' do
let(:attributes) do
{ name: 'test',
index: 0,
builds: [{ name: 'deploy', only: { refs: ['feature'] } }] }
end
it { is_expected.not_to be_included }
end
end
describe '#seeds' do
it 'returns build seeds' do
expect(subject.seeds).to all(be_a Gitlab::Ci::Pipeline::Seed::Build)
end
it 'returns build seeds including valid attributes' do
expect(subject.seeds.size).to eq 2
expect(subject.seeds.map(&:attributes)).to all(include(ref: 'master'))
expect(subject.seeds.map(&:attributes)).to all(include(tag: false))
expect(subject.seeds.map(&:attributes)).to all(include(project: pipeline.project))
expect(subject.seeds.map(&:attributes))
.to all(include(trigger_request: pipeline.trigger_requests.first)) .to all(include(trigger_request: pipeline.trigger_requests.first))
end end
...@@ -40,17 +70,27 @@ describe Gitlab::Ci::Stage::Seed do ...@@ -40,17 +70,27 @@ describe Gitlab::Ci::Stage::Seed do
end end
it 'returns protected builds' do it 'returns protected builds' do
expect(subject.builds).to all(include(protected: true)) expect(subject.seeds.map(&:attributes)).to all(include(protected: true))
end end
end end
context 'when a ref is unprotected' do context 'when a ref is not protected' do
before do before do
allow_any_instance_of(Project).to receive(:protected_for?).and_return(false) allow_any_instance_of(Project).to receive(:protected_for?).and_return(false)
end end
it 'returns unprotected builds' do it 'returns unprotected builds' do
expect(subject.builds).to all(include(protected: false)) expect(subject.seeds.map(&:attributes)).to all(include(protected: false))
end
end
it 'filters seeds using only/except policies' do
expect(subject.seeds.map(&:attributes)).to satisfy do |seeds|
seeds.any? { |hash| hash.fetch(:name) == 'rspec' }
end
expect(subject.seeds.map(&:attributes)).not_to satisfy do |seeds|
seeds.any? { |hash| hash.fetch(:name) == 'deploy' }
end end
end end
end end
...@@ -61,13 +101,13 @@ describe Gitlab::Ci::Stage::Seed do ...@@ -61,13 +101,13 @@ describe Gitlab::Ci::Stage::Seed do
it 'assignes relevant pipeline attributes' do it 'assignes relevant pipeline attributes' do
subject.user = user subject.user = user
expect(subject.builds).to all(include(user: user)) expect(subject.seeds.map(&:attributes)).to all(include(user: user))
end end
end end
describe '#create!' do describe '#to_resource' do
it 'creates all stages and builds' do it 'builds a valid stage object with all builds' do
subject.create! subject.to_resource.save!
expect(pipeline.reload.stages.count).to eq 1 expect(pipeline.reload.stages.count).to eq 1
expect(pipeline.reload.builds.count).to eq 2 expect(pipeline.reload.builds.count).to eq 2
...@@ -79,5 +119,15 @@ describe Gitlab::Ci::Stage::Seed do ...@@ -79,5 +119,15 @@ describe Gitlab::Ci::Stage::Seed do
expect(pipeline.stages) expect(pipeline.stages)
.to all(satisfy { |stage| stage.project.present? }) .to all(satisfy { |stage| stage.project.present? })
end end
it 'can not be persisted without explicit pipeline assignment' do
stage = subject.to_resource
pipeline.save!
expect(stage).not_to be_persisted
expect(pipeline.reload.stages.count).to eq 0
expect(pipeline.reload.builds.count).to eq 0
end
end end
end end
...@@ -18,6 +18,34 @@ module Gitlab ...@@ -18,6 +18,34 @@ module Gitlab
describe '#build_attributes' do describe '#build_attributes' do
subject { described_class.new(config).build_attributes(:rspec) } subject { described_class.new(config).build_attributes(:rspec) }
describe 'attributes list' do
let(:config) do
YAML.dump(
before_script: ['pwd'],
rspec: { script: 'rspec' }
)
end
it 'returns valid build attributes' do
expect(subject).to eq({
stage: "test",
stage_idx: 1,
name: "rspec",
commands: "pwd\nrspec",
coverage_regex: nil,
tag_list: [],
options: {
before_script: ["pwd"],
script: ["rspec"]
},
allow_failure: false,
when: "on_success",
environment: nil,
yaml_variables: []
})
end
end
describe 'coverage entry' do describe 'coverage entry' do
describe 'code coverage regexp' do describe 'code coverage regexp' do
let(:config) do let(:config) do
...@@ -105,297 +133,59 @@ module Gitlab ...@@ -105,297 +133,59 @@ module Gitlab
end end
end end
describe '#stage_seeds' do describe '#stages_attributes' do
context 'when no refs policy is specified' do
let(:config) do
YAML.dump(production: { stage: 'deploy', script: 'cap prod' },
rspec: { stage: 'test', script: 'rspec' },
spinach: { stage: 'test', script: 'spinach' })
end
let(:pipeline) { create(:ci_empty_pipeline) }
it 'correctly fabricates a stage seeds object' do
seeds = subject.stage_seeds(pipeline)
expect(seeds.size).to eq 2
expect(seeds.first.stage[:name]).to eq 'test'
expect(seeds.second.stage[:name]).to eq 'deploy'
expect(seeds.first.builds.dig(0, :name)).to eq 'rspec'
expect(seeds.first.builds.dig(1, :name)).to eq 'spinach'
expect(seeds.second.builds.dig(0, :name)).to eq 'production'
end
end
context 'when refs policy is specified' do
let(:config) do
YAML.dump(production: { stage: 'deploy', script: 'cap prod', only: ['master'] },
spinach: { stage: 'test', script: 'spinach', only: ['tags'] })
end
let(:pipeline) do
create(:ci_empty_pipeline, ref: 'feature', tag: true)
end
it 'returns stage seeds only assigned to master to master' do
seeds = subject.stage_seeds(pipeline)
expect(seeds.size).to eq 1
expect(seeds.first.stage[:name]).to eq 'test'
expect(seeds.first.builds.dig(0, :name)).to eq 'spinach'
end
end
context 'when source policy is specified' do
let(:config) do
YAML.dump(production: { stage: 'deploy', script: 'cap prod', only: ['triggers'] },
spinach: { stage: 'test', script: 'spinach', only: ['schedules'] })
end
let(:pipeline) do
create(:ci_empty_pipeline, source: :schedule)
end
it 'returns stage seeds only assigned to schedules' do
seeds = subject.stage_seeds(pipeline)
expect(seeds.size).to eq 1
expect(seeds.first.stage[:name]).to eq 'test'
expect(seeds.first.builds.dig(0, :name)).to eq 'spinach'
end
end
context 'when kubernetes policy is specified' do
let(:config) do let(:config) do
YAML.dump( YAML.dump(
spinach: { stage: 'test', script: 'spinach' }, rspec: { script: 'rspec', stage: 'test', only: ['branches'] },
production: { prod: { script: 'cap prod', stage: 'deploy', only: ['tags'] }
stage: 'deploy',
script: 'cap',
only: { kubernetes: 'active' }
}
) )
end end
context 'when kubernetes is active' do let(:attributes) do
shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do [{ name: "build",
it 'returns seeds for kubernetes dependent job' do index: 0,
seeds = subject.stage_seeds(pipeline) builds: [] },
{ name: "test",
expect(seeds.size).to eq 2 index: 1,
expect(seeds.first.builds.dig(0, :name)).to eq 'spinach' builds:
expect(seeds.second.builds.dig(0, :name)).to eq 'production' [{ stage_idx: 1,
end
end
context 'when user configured kubernetes from Integration > Kubernetes' do
let(:project) { create(:kubernetes_project) }
let(:pipeline) { create(:ci_empty_pipeline, project: project) }
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
end
context 'when user configured kubernetes from CI/CD > Clusters' do
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:project) { cluster.project }
let(:pipeline) { create(:ci_empty_pipeline, project: project) }
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
end
end
context 'when kubernetes is not active' do
it 'does not return seeds for kubernetes dependent job' do
seeds = subject.stage_seeds(pipeline)
expect(seeds.size).to eq 1
expect(seeds.first.builds.dig(0, :name)).to eq 'spinach'
end
end
end
end
describe "#pipeline_stage_builds" do
let(:type) { 'test' }
it "returns builds if no branch specified" do
config = YAML.dump({
before_script: ["pwd"],
rspec: { script: "rspec" }
})
config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(1)
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).first).to eq({
stage: "test", stage: "test",
stage_idx: 1, commands: "rspec",
tag_list: [],
name: "rspec", name: "rspec",
commands: "pwd\nrspec", allow_failure: false,
when: "on_success",
environment: nil,
coverage_regex: nil, coverage_regex: nil,
yaml_variables: [],
options: { script: ["rspec"] },
only: { refs: ["branches"] },
except: {} }] },
{ name: "deploy",
index: 2,
builds:
[{ stage_idx: 2,
stage: "deploy",
commands: "cap prod",
tag_list: [], tag_list: [],
options: { name: "prod",
before_script: ["pwd"],
script: ["rspec"]
},
allow_failure: false, allow_failure: false,
when: "on_success", when: "on_success",
environment: nil, environment: nil,
yaml_variables: [] coverage_regex: nil,
}) yaml_variables: [],
end options: { script: ["cap prod"] },
only: { refs: ["tags"] },
describe 'only' do except: {} }] }]
it "does not return builds if only has another branch" do
config = YAML.dump({
before_script: ["pwd"],
rspec: { script: "rspec", only: ["deploy"] }
})
config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(0)
end
it "does not return builds if only has regexp with another branch" do
config = YAML.dump({
before_script: ["pwd"],
rspec: { script: "rspec", only: ["/^deploy$/"] }
})
config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(0)
end
it "returns builds if only has specified this branch" do
config = YAML.dump({
before_script: ["pwd"],
rspec: { script: "rspec", only: ["master"] }
})
config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(1)
end
it "returns builds if only has a list of branches including specified" do
config = YAML.dump({
before_script: ["pwd"],
rspec: { script: "rspec", type: type, only: %w(master deploy) }
})
config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(1)
end
it "returns builds if only has a branches keyword specified" do
config = YAML.dump({
before_script: ["pwd"],
rspec: { script: "rspec", type: type, only: ["branches"] }
})
config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(1)
end
it "does not return builds if only has a tags keyword" do
config = YAML.dump({
before_script: ["pwd"],
rspec: { script: "rspec", type: type, only: ["tags"] }
})
config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(0)
end
it "returns builds if only has special keywords specified and source matches" do
possibilities = [{ keyword: 'pushes', source: 'push' },
{ keyword: 'web', source: 'web' },
{ keyword: 'triggers', source: 'trigger' },
{ keyword: 'schedules', source: 'schedule' },
{ keyword: 'api', source: 'api' },
{ keyword: 'external', source: 'external' }]
possibilities.each do |possibility|
config = YAML.dump({
before_script: ["pwd"],
rspec: { script: "rspec", type: type, only: [possibility[:keyword]] }
})
config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: 'deploy', tag: false, source: possibility[:source])).size).to eq(1)
end
end
it "does not return builds if only has special keywords specified and source doesn't match" do
possibilities = [{ keyword: 'pushes', source: 'web' },
{ keyword: 'web', source: 'push' },
{ keyword: 'triggers', source: 'schedule' },
{ keyword: 'schedules', source: 'external' },
{ keyword: 'api', source: 'trigger' },
{ keyword: 'external', source: 'api' }]
possibilities.each do |possibility|
config = YAML.dump({
before_script: ["pwd"],
rspec: { script: "rspec", type: type, only: [possibility[:keyword]] }
})
config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: 'deploy', tag: false, source: possibility[:source])).size).to eq(0)
end
end end
it "returns builds if only has current repository path" do it 'returns stages seed attributes' do
seed_pipeline = pipeline(ref: 'deploy') expect(subject.stages_attributes).to eq attributes
config = YAML.dump({
before_script: ["pwd"],
rspec: {
script: "rspec",
type: type,
only: ["branches@#{seed_pipeline.project_full_path}"]
}
})
config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds(type, seed_pipeline).size).to eq(1)
end end
it "does not return builds if only has different repository path" do
config = YAML.dump({
before_script: ["pwd"],
rspec: { script: "rspec", type: type, only: ["branches@fork"] }
})
config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(0)
end end
it "returns build only for specified type" do describe 'only / except policies validations' do
config = YAML.dump({ context 'when `only` has an invalid value' do
before_script: ["pwd"],
rspec: { script: "rspec", type: "test", only: %w(master deploy) },
staging: { script: "deploy", type: "deploy", only: %w(master deploy) },
production: { script: "deploy", type: "deploy", only: ["master@path", "deploy"] }
})
config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds("deploy", pipeline(ref: "deploy")).size).to eq(2)
expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "deploy")).size).to eq(1)
expect(config_processor.pipeline_stage_builds("deploy", pipeline(ref: "master")).size).to eq(1)
end
context 'for invalid value' do
let(:config) { { rspec: { script: "rspec", type: "test", only: only } } } let(:config) { { rspec: { script: "rspec", type: "test", only: only } } }
let(:processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) } let(:processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) }
...@@ -426,163 +216,8 @@ module Gitlab ...@@ -426,163 +216,8 @@ module Gitlab
end end
end end
end end
end
describe 'except' do
it "returns builds if except has another branch" do
config = YAML.dump({
before_script: ["pwd"],
rspec: { script: "rspec", except: ["deploy"] }
})
config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(1)
end
it "returns builds if except has regexp with another branch" do
config = YAML.dump({
before_script: ["pwd"],
rspec: { script: "rspec", except: ["/^deploy$/"] }
})
config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(1)
end
it "does not return builds if except has specified this branch" do
config = YAML.dump({
before_script: ["pwd"],
rspec: { script: "rspec", except: ["master"] }
})
config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "master")).size).to eq(0)
end
it "does not return builds if except has a list of branches including specified" do
config = YAML.dump({
before_script: ["pwd"],
rspec: { script: "rspec", type: type, except: %w(master deploy) }
})
config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(0) context 'when `except` has an invalid value' do
end
it "does not return builds if except has a branches keyword specified" do
config = YAML.dump({
before_script: ["pwd"],
rspec: { script: "rspec", type: type, except: ["branches"] }
})
config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(0)
end
it "returns builds if except has a tags keyword" do
config = YAML.dump({
before_script: ["pwd"],
rspec: { script: "rspec", type: type, except: ["tags"] }
})
config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(1)
end
it "does not return builds if except has special keywords specified and source matches" do
possibilities = [{ keyword: 'pushes', source: 'push' },
{ keyword: 'web', source: 'web' },
{ keyword: 'triggers', source: 'trigger' },
{ keyword: 'schedules', source: 'schedule' },
{ keyword: 'api', source: 'api' },
{ keyword: 'external', source: 'external' }]
possibilities.each do |possibility|
config = YAML.dump({
before_script: ["pwd"],
rspec: { script: "rspec", type: type, except: [possibility[:keyword]] }
})
config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: 'deploy', tag: false, source: possibility[:source])).size).to eq(0)
end
end
it "returns builds if except has special keywords specified and source doesn't match" do
possibilities = [{ keyword: 'pushes', source: 'web' },
{ keyword: 'web', source: 'push' },
{ keyword: 'triggers', source: 'schedule' },
{ keyword: 'schedules', source: 'external' },
{ keyword: 'api', source: 'trigger' },
{ keyword: 'external', source: 'api' }]
possibilities.each do |possibility|
config = YAML.dump({
before_script: ["pwd"],
rspec: { script: "rspec", type: type, except: [possibility[:keyword]] }
})
config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: 'deploy', tag: false, source: possibility[:source])).size).to eq(1)
end
end
it "does not return builds if except has current repository path" do
seed_pipeline = pipeline(ref: 'deploy')
config = YAML.dump({
before_script: ["pwd"],
rspec: {
script: "rspec",
type: type,
except: ["branches@#{seed_pipeline.project_full_path}"]
}
})
config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds(type, seed_pipeline).size).to eq(0)
end
it "returns builds if except has different repository path" do
config = YAML.dump({
before_script: ["pwd"],
rspec: { script: "rspec", type: type, except: ["branches@fork"] }
})
config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds(type, pipeline(ref: "deploy")).size).to eq(1)
end
it "returns build except specified type" do
master_pipeline = pipeline(ref: 'master')
test_pipeline = pipeline(ref: 'test')
deploy_pipeline = pipeline(ref: 'deploy')
config = YAML.dump({
before_script: ["pwd"],
rspec: { script: "rspec", type: "test", except: ["master", "deploy", "test@#{test_pipeline.project_full_path}"] },
staging: { script: "deploy", type: "deploy", except: ["master"] },
production: { script: "deploy", type: "deploy", except: ["master@#{master_pipeline.project_full_path}"] }
})
config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds("deploy", deploy_pipeline).size).to eq(2)
expect(config_processor.pipeline_stage_builds("test", test_pipeline).size).to eq(0)
expect(config_processor.pipeline_stage_builds("deploy", master_pipeline).size).to eq(0)
end
context 'for invalid value' do
let(:config) { { rspec: { script: "rspec", except: except } } } let(:config) { { rspec: { script: "rspec", except: except } } }
let(:processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) } let(:processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) }
...@@ -614,13 +249,12 @@ module Gitlab ...@@ -614,13 +249,12 @@ module Gitlab
end end
end end
end end
end
describe "Scripts handling" do describe "Scripts handling" do
let(:config_data) { YAML.dump(config) } let(:config_data) { YAML.dump(config) }
let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config_data) } let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config_data) }
subject { config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first } subject { config_processor.stage_builds_attributes('test').first }
describe "before_script" do describe "before_script" do
context "in global context" do context "in global context" do
...@@ -703,8 +337,8 @@ module Gitlab ...@@ -703,8 +337,8 @@ module Gitlab
config_processor = Gitlab::Ci::YamlProcessor.new(config) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).size).to eq(1) expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first).to eq({ expect(config_processor.stage_builds_attributes("test").first).to eq({
stage: "test", stage: "test",
stage_idx: 1, stage_idx: 1,
name: "rspec", name: "rspec",
...@@ -738,8 +372,8 @@ module Gitlab ...@@ -738,8 +372,8 @@ module Gitlab
config_processor = Gitlab::Ci::YamlProcessor.new(config) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).size).to eq(1) expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first).to eq({ expect(config_processor.stage_builds_attributes("test").first).to eq({
stage: "test", stage: "test",
stage_idx: 1, stage_idx: 1,
name: "rspec", name: "rspec",
...@@ -771,8 +405,8 @@ module Gitlab ...@@ -771,8 +405,8 @@ module Gitlab
config_processor = Gitlab::Ci::YamlProcessor.new(config) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).size).to eq(1) expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first).to eq({ expect(config_processor.stage_builds_attributes("test").first).to eq({
stage: "test", stage: "test",
stage_idx: 1, stage_idx: 1,
name: "rspec", name: "rspec",
...@@ -800,8 +434,8 @@ module Gitlab ...@@ -800,8 +434,8 @@ module Gitlab
config_processor = Gitlab::Ci::YamlProcessor.new(config) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).size).to eq(1) expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first).to eq({ expect(config_processor.stage_builds_attributes("test").first).to eq({
stage: "test", stage: "test",
stage_idx: 1, stage_idx: 1,
name: "rspec", name: "rspec",
...@@ -946,8 +580,8 @@ module Gitlab ...@@ -946,8 +580,8 @@ module Gitlab
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config) config_processor = Gitlab::Ci::YamlProcessor.new(config)
builds = config_processor.stage_builds_attributes("test")
builds = config_processor.pipeline_stage_builds("test", pipeline(ref: "master"))
expect(builds.size).to eq(1) expect(builds.size).to eq(1)
expect(builds.first[:when]).to eq(when_state) expect(builds.first[:when]).to eq(when_state)
end end
...@@ -978,8 +612,8 @@ module Gitlab ...@@ -978,8 +612,8 @@ module Gitlab
config_processor = Gitlab::Ci::YamlProcessor.new(config) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).size).to eq(1) expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first[:options][:cache]).to eq( expect(config_processor.stage_builds_attributes("test").first[:options][:cache]).to eq(
paths: ["logs/", "binaries/"], paths: ["logs/", "binaries/"],
untracked: true, untracked: true,
key: 'key', key: 'key',
...@@ -997,8 +631,8 @@ module Gitlab ...@@ -997,8 +631,8 @@ module Gitlab
config_processor = Gitlab::Ci::YamlProcessor.new(config) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).size).to eq(1) expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first[:options][:cache]).to eq( expect(config_processor.stage_builds_attributes("test").first[:options][:cache]).to eq(
paths: ["logs/", "binaries/"], paths: ["logs/", "binaries/"],
untracked: true, untracked: true,
key: 'key', key: 'key',
...@@ -1017,8 +651,8 @@ module Gitlab ...@@ -1017,8 +651,8 @@ module Gitlab
config_processor = Gitlab::Ci::YamlProcessor.new(config) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).size).to eq(1) expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first[:options][:cache]).to eq( expect(config_processor.stage_builds_attributes("test").first[:options][:cache]).to eq(
paths: ["test/"], paths: ["test/"],
untracked: false, untracked: false,
key: 'local', key: 'local',
...@@ -1046,8 +680,8 @@ module Gitlab ...@@ -1046,8 +680,8 @@ module Gitlab
config_processor = Gitlab::Ci::YamlProcessor.new(config) config_processor = Gitlab::Ci::YamlProcessor.new(config)
expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).size).to eq(1) expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.pipeline_stage_builds("test", pipeline(ref: "master")).first).to eq({ expect(config_processor.stage_builds_attributes("test").first).to eq({
stage: "test", stage: "test",
stage_idx: 1, stage_idx: 1,
name: "rspec", name: "rspec",
...@@ -1083,8 +717,8 @@ module Gitlab ...@@ -1083,8 +717,8 @@ module Gitlab
}) })
config_processor = Gitlab::Ci::YamlProcessor.new(config) config_processor = Gitlab::Ci::YamlProcessor.new(config)
builds = config_processor.stage_builds_attributes("test")
builds = config_processor.pipeline_stage_builds("test", pipeline(ref: "master"))
expect(builds.size).to eq(1) expect(builds.size).to eq(1)
expect(builds.first[:options][:artifacts][:when]).to eq(when_state) expect(builds.first[:options][:artifacts][:when]).to eq(when_state)
end end
...@@ -1099,7 +733,7 @@ module Gitlab ...@@ -1099,7 +733,7 @@ module Gitlab
end end
let(:processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) } let(:processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) }
let(:builds) { processor.pipeline_stage_builds('deploy', pipeline(ref: 'master')) } let(:builds) { processor.stage_builds_attributes('deploy') }
context 'when a production environment is specified' do context 'when a production environment is specified' do
let(:environment) { 'production' } let(:environment) { 'production' }
...@@ -1256,7 +890,7 @@ module Gitlab ...@@ -1256,7 +890,7 @@ module Gitlab
describe "Hidden jobs" do describe "Hidden jobs" do
let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config) } let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config) }
subject { config_processor.pipeline_stage_builds("test", pipeline(ref: "master")) } subject { config_processor.stage_builds_attributes("test") }
shared_examples 'hidden_job_handling' do shared_examples 'hidden_job_handling' do
it "doesn't create jobs that start with dot" do it "doesn't create jobs that start with dot" do
...@@ -1304,7 +938,7 @@ module Gitlab ...@@ -1304,7 +938,7 @@ module Gitlab
describe "YAML Alias/Anchor" do describe "YAML Alias/Anchor" do
let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config) } let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config) }
subject { config_processor.pipeline_stage_builds("build", pipeline(ref: "master")) } subject { config_processor.stage_builds_attributes("build") }
shared_examples 'job_templates_handling' do shared_examples 'job_templates_handling' do
it "is correctly supported for jobs" do it "is correctly supported for jobs" do
...@@ -1344,13 +978,13 @@ module Gitlab ...@@ -1344,13 +978,13 @@ module Gitlab
context 'when template is a job' do context 'when template is a job' do
let(:config) do let(:config) do
<<EOT <<~EOT
job1: &JOBTMPL job1: &JOBTMPL
stage: build stage: build
script: execute-script-for-job script: execute-script-for-job
job2: *JOBTMPL job2: *JOBTMPL
EOT EOT
end end
it_behaves_like 'job_templates_handling' it_behaves_like 'job_templates_handling'
...@@ -1358,15 +992,15 @@ EOT ...@@ -1358,15 +992,15 @@ EOT
context 'when template is a hidden job' do context 'when template is a hidden job' do
let(:config) do let(:config) do
<<EOT <<~EOT
.template: &JOBTMPL .template: &JOBTMPL
stage: build stage: build
script: execute-script-for-job script: execute-script-for-job
job1: *JOBTMPL job1: *JOBTMPL
job2: *JOBTMPL job2: *JOBTMPL
EOT EOT
end end
it_behaves_like 'job_templates_handling' it_behaves_like 'job_templates_handling'
...@@ -1374,18 +1008,18 @@ EOT ...@@ -1374,18 +1008,18 @@ EOT
context 'when job adds its own keys to a template definition' do context 'when job adds its own keys to a template definition' do
let(:config) do let(:config) do
<<EOT <<~EOT
.template: &JOBTMPL .template: &JOBTMPL
stage: build stage: build
job1: job1:
<<: *JOBTMPL <<: *JOBTMPL
script: execute-script-for-job script: execute-script-for-job
job2: job2:
<<: *JOBTMPL <<: *JOBTMPL
script: execute-script-for-job script: execute-script-for-job
EOT EOT
end end
it_behaves_like 'job_templates_handling' it_behaves_like 'job_templates_handling'
...@@ -1724,10 +1358,6 @@ EOT ...@@ -1724,10 +1358,6 @@ EOT
it { is_expected.to be_nil } it { is_expected.to be_nil }
end end
end end
def pipeline(**attributes)
build_stubbed(:ci_empty_pipeline, **attributes)
end
end end
end end
end end
...@@ -181,6 +181,24 @@ describe Ci::Pipeline, :mailer do ...@@ -181,6 +181,24 @@ describe Ci::Pipeline, :mailer do
end end
end end
describe '#protected_ref?' do
it 'delegates method to project' do
expect(pipeline).not_to be_protected_ref
end
end
describe '#legacy_trigger' do
let(:trigger_request) { create(:ci_trigger_request) }
before do
pipeline.trigger_requests << trigger_request
end
it 'returns first trigger request' do
expect(pipeline.legacy_trigger).to eq trigger_request
end
end
describe '#auto_canceled?' do describe '#auto_canceled?' do
subject { pipeline.auto_canceled? } subject { pipeline.auto_canceled? }
...@@ -219,6 +237,144 @@ describe Ci::Pipeline, :mailer do ...@@ -219,6 +237,144 @@ describe Ci::Pipeline, :mailer do
end end
describe 'pipeline stages' do describe 'pipeline stages' do
describe '#stage_seeds' do
let(:project) { create(:project, :repository) }
let(:pipeline) { build(:ci_pipeline, project: project, config: config) }
let(:config) { { rspec: { script: 'rake' } } }
it 'returns preseeded stage seeds object' do
expect(pipeline.stage_seeds)
.to all(be_a Gitlab::Ci::Pipeline::Seed::Base)
expect(pipeline.stage_seeds.count).to eq 1
end
context 'when no refs policy is specified' do
let(:config) do
{ production: { stage: 'deploy', script: 'cap prod' },
rspec: { stage: 'test', script: 'rspec' },
spinach: { stage: 'test', script: 'spinach' } }
end
it 'correctly fabricates a stage seeds object' do
seeds = pipeline.stage_seeds
expect(seeds.size).to eq 2
expect(seeds.first.attributes[:name]).to eq 'test'
expect(seeds.second.attributes[:name]).to eq 'deploy'
expect(seeds.dig(0, 0, :name)).to eq 'rspec'
expect(seeds.dig(0, 1, :name)).to eq 'spinach'
expect(seeds.dig(1, 0, :name)).to eq 'production'
end
end
context 'when refs policy is specified' do
let(:pipeline) do
build(:ci_pipeline, ref: 'feature', tag: true, project: project, config: config)
end
let(:config) do
{ production: { stage: 'deploy', script: 'cap prod', only: ['master'] },
spinach: { stage: 'test', script: 'spinach', only: ['tags'] } }
end
it 'returns stage seeds only assigned to master to master' do
seeds = pipeline.stage_seeds
expect(seeds.size).to eq 1
expect(seeds.first.attributes[:name]).to eq 'test'
expect(seeds.dig(0, 0, :name)).to eq 'spinach'
end
end
context 'when source policy is specified' do
let(:pipeline) do
build(:ci_pipeline, source: :schedule, project: project, config: config)
end
let(:config) do
{ production: { stage: 'deploy', script: 'cap prod', only: ['triggers'] },
spinach: { stage: 'test', script: 'spinach', only: ['schedules'] } }
end
it 'returns stage seeds only assigned to schedules' do
seeds = pipeline.stage_seeds
expect(seeds.size).to eq 1
expect(seeds.first.attributes[:name]).to eq 'test'
expect(seeds.dig(0, 0, :name)).to eq 'spinach'
end
end
context 'when kubernetes policy is specified' do
let(:config) do
{
spinach: { stage: 'test', script: 'spinach' },
production: {
stage: 'deploy',
script: 'cap',
only: { kubernetes: 'active' }
}
}
end
context 'when kubernetes is active' do
shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
it 'returns seeds for kubernetes dependent job' do
seeds = pipeline.stage_seeds
expect(seeds.size).to eq 2
expect(seeds.dig(0, 0, :name)).to eq 'spinach'
expect(seeds.dig(1, 0, :name)).to eq 'production'
end
end
context 'when user configured kubernetes from Integration > Kubernetes' do
let(:project) { create(:kubernetes_project, :repository) }
let(:pipeline) { build(:ci_pipeline, project: project, config: config) }
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
end
context 'when user configured kubernetes from CI/CD > Clusters' do
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:project) { cluster.project }
let(:pipeline) { build(:ci_pipeline, project: project, config: config) }
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
end
end
context 'when kubernetes is not active' do
it 'does not return seeds for kubernetes dependent job' do
seeds = pipeline.stage_seeds
expect(seeds.size).to eq 1
expect(seeds.dig(0, 0, :name)).to eq 'spinach'
end
end
end
end
describe '#seeds_size' do
context 'when refs policy is specified' do
let(:project) { create(:project, :repository) }
let(:config) do
{ production: { stage: 'deploy', script: 'cap prod', only: ['master'] },
spinach: { stage: 'test', script: 'spinach', only: ['tags'] } }
end
let(:pipeline) do
build(:ci_pipeline, ref: 'feature', tag: true, project: project, config: config)
end
it 'returns real seeds size' do
expect(pipeline.seeds_size).to eq 1
end
end
end
describe 'legacy stages' do
before do before do
create(:commit_status, pipeline: pipeline, create(:commit_status, pipeline: pipeline,
stage: 'build', stage: 'build',
...@@ -245,27 +401,6 @@ describe Ci::Pipeline, :mailer do ...@@ -245,27 +401,6 @@ describe Ci::Pipeline, :mailer do
status: 'success') status: 'success')
end end
describe '#stage_seeds' do
let(:project) { create(:project, :repository) }
let(:pipeline) do
build(:ci_pipeline, project: project, config: { rspec: { script: 'rake' } })
end
it 'returns preseeded stage seeds object' do
expect(pipeline.stage_seeds).to all(be_a Gitlab::Ci::Stage::Seed)
expect(pipeline.stage_seeds.count).to eq 1
end
end
describe '#seeds_size' do
let(:project) { create(:project, :repository) }
let(:pipeline) { build(:ci_pipeline_with_one_job, project: project) }
it 'returns number of jobs in stage seeds' do
expect(pipeline.seeds_size).to eq 1
end
end
describe '#legacy_stages' do describe '#legacy_stages' do
subject { pipeline.legacy_stages } subject { pipeline.legacy_stages }
...@@ -360,6 +495,7 @@ describe Ci::Pipeline, :mailer do ...@@ -360,6 +495,7 @@ describe Ci::Pipeline, :mailer do
end end
end end
end end
end
describe 'state machine' do describe 'state machine' do
let(:current) { Time.now.change(usec: 0) } let(:current) { Time.now.change(usec: 0) }
...@@ -595,21 +731,6 @@ describe Ci::Pipeline, :mailer do ...@@ -595,21 +731,6 @@ describe Ci::Pipeline, :mailer do
end end
end end
describe '#has_stage_seeds?' do
context 'when pipeline has stage seeds' do
let(:project) { create(:project, :repository) }
subject { build(:ci_pipeline_with_one_job, project: project) }
it { is_expected.to have_stage_seeds }
end
context 'when pipeline does not have stage seeds' do
subject { create(:ci_pipeline_without_jobs) }
it { is_expected.not_to have_stage_seeds }
end
end
describe '#has_warnings?' do describe '#has_warnings?' do
subject { pipeline.has_warnings? } subject { pipeline.has_warnings? }
......
...@@ -378,7 +378,7 @@ describe Environment do ...@@ -378,7 +378,7 @@ describe Environment do
shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
it 'returns the terminals from the deployment service' do it 'returns the terminals from the deployment service' do
expect(project.deployment_platform) expect(project.deployment_platform(environment: environment))
.to receive(:terminals).with(environment) .to receive(:terminals).with(environment)
.and_return(:fake_terminals) .and_return(:fake_terminals)
...@@ -419,7 +419,7 @@ describe Environment do ...@@ -419,7 +419,7 @@ describe Environment do
end end
it 'returns the rollout status from the deployment service' do it 'returns the rollout status from the deployment service' do
expect(project.deployment_platform) expect(project.deployment_platform(environment: environment))
.to receive(:rollout_status).with(environment) .to receive(:rollout_status).with(environment)
.and_return(:fake_rollout_status) .and_return(:fake_rollout_status)
......
...@@ -2404,6 +2404,26 @@ describe MergeRequest do ...@@ -2404,6 +2404,26 @@ describe MergeRequest do
end end
end end
describe '#base_pipeline' do
let(:pipeline_arguments) do
{
project: project,
ref: merge_request.target_branch,
sha: merge_request.diff_base_sha
}
end
let(:project) { create(:project, :public, :repository) }
let(:merge_request) { create(:merge_request, source_project: project) }
let!(:first_pipeline) { create(:ci_pipeline_without_jobs, pipeline_arguments) }
let!(:last_pipeline) { create(:ci_pipeline_without_jobs, pipeline_arguments) }
it 'returns latest pipeline' do
expect(merge_request.base_pipeline).to eq(last_pipeline)
end
end
describe '#has_commits?' do describe '#has_commits?' do
before do before do
allow(subject.merge_request_diff).to receive(:commits_count) allow(subject.merge_request_diff).to receive(:commits_count)
......
...@@ -339,7 +339,7 @@ describe ProjectPresenter do ...@@ -339,7 +339,7 @@ describe ProjectPresenter do
it 'returns link to clusters page if more than one exists' do it 'returns link to clusters page if more than one exists' do
project.add_master(user) project.add_master(user)
create(:cluster, projects: [project]) create(:cluster, :production_environment, projects: [project])
create(:cluster, projects: [project]) create(:cluster, projects: [project])
expect(presenter.kubernetes_cluster_anchor_data).to eq(OpenStruct.new(enabled: true, expect(presenter.kubernetes_cluster_anchor_data).to eq(OpenStruct.new(enabled: true,
......
...@@ -185,6 +185,12 @@ describe API::Triggers do ...@@ -185,6 +185,12 @@ describe API::Triggers do
expect(response).to have_http_status(201) expect(response).to have_http_status(201)
expect(Ci::Pipeline.last.source).to eq('pipeline') expect(Ci::Pipeline.last.source).to eq('pipeline')
expect(Ci::Pipeline.last.triggered_by_pipeline).not_to be_nil expect(Ci::Pipeline.last.triggered_by_pipeline).not_to be_nil
expect(Ci::Sources::Pipeline.last).to have_attributes(
pipeline_id: (a_value > 0),
source_pipeline_id: (a_value > 0),
source_job_id: (a_value > 0),
source_project_id: (a_value > 0)
)
end end
context 'when build is complete' do context 'when build is complete' do
......
...@@ -81,7 +81,7 @@ describe Clusters::CreateService do ...@@ -81,7 +81,7 @@ describe Clusters::CreateService do
end end
context 'when project has a cluster' do context 'when project has a cluster' do
let!(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) } let!(:cluster) { create(:cluster, :provided_by_gcp, :production_environment, projects: [project]) }
before do before do
allow(project).to receive(:feature_available?).and_call_original allow(project).to receive(:feature_available?).and_call_original
......
...@@ -16,19 +16,19 @@ shared_examples 'PATCH #update updates variables' do ...@@ -16,19 +16,19 @@ shared_examples 'PATCH #update updates variables' do
let(:variable_attributes) do let(:variable_attributes) do
{ id: variable.id, { id: variable.id,
key: variable.key, key: variable.key,
value: variable.value, secret_value: variable.value,
protected: variable.protected?.to_s } protected: variable.protected?.to_s }
end end
let(:new_variable_attributes) do let(:new_variable_attributes) do
{ key: 'new_key', { key: 'new_key',
value: 'dummy_value', secret_value: 'dummy_value',
protected: 'false' } protected: 'false' }
end end
context 'with invalid new variable parameters' do context 'with invalid new variable parameters' do
let(:variables_attributes) do let(:variables_attributes) do
[ [
variable_attributes.merge(value: 'other_value'), variable_attributes.merge(secret_value: 'other_value'),
new_variable_attributes.merge(key: '...?') new_variable_attributes.merge(key: '...?')
] ]
end end
...@@ -52,7 +52,7 @@ shared_examples 'PATCH #update updates variables' do ...@@ -52,7 +52,7 @@ shared_examples 'PATCH #update updates variables' do
let(:variables_attributes) do let(:variables_attributes) do
[ [
new_variable_attributes, new_variable_attributes,
new_variable_attributes.merge(value: 'other_value') new_variable_attributes.merge(secret_value: 'other_value')
] ]
end end
...@@ -74,7 +74,7 @@ shared_examples 'PATCH #update updates variables' do ...@@ -74,7 +74,7 @@ shared_examples 'PATCH #update updates variables' do
context 'with valid new variable parameters' do context 'with valid new variable parameters' do
let(:variables_attributes) do let(:variables_attributes) do
[ [
variable_attributes.merge(value: 'other_value'), variable_attributes.merge(secret_value: 'other_value'),
new_variable_attributes new_variable_attributes
] ]
end end
......
...@@ -5,6 +5,7 @@ describe 'ci/lints/show' do ...@@ -5,6 +5,7 @@ describe 'ci/lints/show' do
describe 'XSS protection' do describe 'XSS protection' do
let(:config_processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(content)) } let(:config_processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(content)) }
before do before do
assign(:status, true) assign(:status, true)
assign(:builds, config_processor.builds) assign(:builds, config_processor.builds)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment