Commit edab9360 authored by Douwe Maan's avatar Douwe Maan

Merge branch 'master' into 'rd-44364-deprecate-support-for-dsa-keys'

# Conflicts:
#   db/schema.rb
parents c503429e 6ced2f12
image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3.7-golang-1.9-git-2.17-chrome-65.0-node-8.x-yarn-1.2-postgresql-9.6" image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.4.4-golang-1.9-git-2.17-chrome-65.0-node-8.x-yarn-1.2-postgresql-9.6"
.dedicated-runner: &dedicated-runner .dedicated-runner: &dedicated-runner
retry: 1 retry: 1
...@@ -6,7 +6,7 @@ image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3.7-golang-1.9-git ...@@ -6,7 +6,7 @@ image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3.7-golang-1.9-git
- gitlab-org - gitlab-org
.default-cache: &default-cache .default-cache: &default-cache
key: "ruby-2.3.7-debian-stretch-with-yarn" key: "ruby-2.4.4-debian-stretch-with-yarn"
paths: paths:
- vendor/ruby - vendor/ruby
- .yarn-cache/ - .yarn-cache/
...@@ -550,7 +550,7 @@ static-analysis: ...@@ -550,7 +550,7 @@ static-analysis:
script: script:
- scripts/static-analysis - scripts/static-analysis
cache: cache:
key: "ruby-2.3.7-debian-stretch-with-yarn-and-rubocop" key: "ruby-2.4.4-debian-stretch-with-yarn-and-rubocop"
paths: paths:
- vendor/ruby - vendor/ruby
- .yarn-cache/ - .yarn-cache/
......
...@@ -182,7 +182,7 @@ Assigning a team label makes sure issues get the attention of the appropriate ...@@ -182,7 +182,7 @@ Assigning a team label makes sure issues get the attention of the appropriate
people. people.
The current team labels are ~Distribution, ~"CI/CD", ~Discussion, ~Documentation, ~Quality, The current team labels are ~Distribution, ~"CI/CD", ~Discussion, ~Documentation, ~Quality,
~Geo, ~Gitaly, ~Monitoring, ~Platform, ~Release, ~"Security Products" and ~"UX". ~Geo, ~Gitaly, ~Monitoring, ~Platform, ~Release, ~"Security Products", ~"Configuration", and ~"UX".
The descriptions on the [labels page][labels-page] explain what falls under the The descriptions on the [labels page][labels-page] explain what falls under the
responsibility of each team. responsibility of each team.
......
...@@ -342,7 +342,7 @@ group :development, :test do ...@@ -342,7 +342,7 @@ group :development, :test do
gem 'capybara', '~> 2.15' gem 'capybara', '~> 2.15'
gem 'capybara-screenshot', '~> 1.0.0' gem 'capybara-screenshot', '~> 1.0.0'
gem 'selenium-webdriver', '~> 3.5' gem 'selenium-webdriver', '~> 3.12'
gem 'spring', '~> 2.0.0' gem 'spring', '~> 2.0.0'
gem 'spring-commands-rspec', '~> 1.0.4' gem 'spring-commands-rspec', '~> 1.0.4'
...@@ -374,7 +374,7 @@ end ...@@ -374,7 +374,7 @@ end
group :test do group :test do
gem 'shoulda-matchers', '~> 3.1.2', require: false gem 'shoulda-matchers', '~> 3.1.2', require: false
gem 'email_spec', '~> 1.6.0' gem 'email_spec', '~> 2.2.0'
gem 'json-schema', '~> 2.8.0' gem 'json-schema', '~> 2.8.0'
gem 'webmock', '~> 2.3.2' gem 'webmock', '~> 2.3.2'
gem 'rails-controller-testing' if rails5? # Rails5 only gem. gem 'rails-controller-testing' if rails5? # Rails5 only gem.
...@@ -384,7 +384,7 @@ group :test do ...@@ -384,7 +384,7 @@ group :test do
gem 'test-prof', '~> 0.2.5' gem 'test-prof', '~> 0.2.5'
end end
gem 'octokit', '~> 4.8' gem 'octokit', '~> 4.9'
gem 'mail_room', '~> 0.9.1' gem 'mail_room', '~> 0.9.1'
......
...@@ -115,7 +115,7 @@ GEM ...@@ -115,7 +115,7 @@ GEM
mime-types (>= 1.16) mime-types (>= 1.16)
cause (0.1) cause (0.1)
charlock_holmes (0.7.6) charlock_holmes (0.7.6)
childprocess (0.7.0) childprocess (0.9.0)
ffi (~> 1.0, >= 1.0.11) ffi (~> 1.0, >= 1.0.11)
chronic (0.10.2) chronic (0.10.2)
chronic_duration (0.10.6) chronic_duration (0.10.6)
...@@ -172,15 +172,16 @@ GEM ...@@ -172,15 +172,16 @@ GEM
unf (>= 0.0.5, < 1.0.0) unf (>= 0.0.5, < 1.0.0)
doorkeeper (4.3.2) doorkeeper (4.3.2)
railties (>= 4.2) railties (>= 4.2)
doorkeeper-openid_connect (1.3.0) doorkeeper-openid_connect (1.4.0)
doorkeeper (~> 4.3) doorkeeper (~> 4.3)
json-jwt (~> 1.6) json-jwt (~> 1.6)
dropzonejs-rails (0.7.2) dropzonejs-rails (0.7.2)
rails (> 3.1) rails (> 3.1)
email_reply_trimmer (0.1.6) email_reply_trimmer (0.1.6)
email_spec (1.6.0) email_spec (2.2.0)
htmlentities (~> 4.3.3)
launchy (~> 2.1) launchy (~> 2.1)
mail (~> 2.2) mail (~> 2.7)
encryptor (3.0.0) encryptor (3.0.0)
equalizer (0.0.11) equalizer (0.0.11)
erubis (2.7.0) erubis (2.7.0)
...@@ -517,7 +518,7 @@ GEM ...@@ -517,7 +518,7 @@ 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.8.0) octokit (4.9.0)
sawyer (~> 0.8.0, >= 0.5.3) sawyer (~> 0.8.0, >= 0.5.3)
omniauth (1.8.1) omniauth (1.8.1)
hashie (>= 3.4.6, < 3.6.0) hashie (>= 3.4.6, < 3.6.0)
...@@ -828,9 +829,9 @@ GEM ...@@ -828,9 +829,9 @@ GEM
activesupport (>= 3.1) activesupport (>= 3.1)
select2-rails (3.5.9.3) select2-rails (3.5.9.3)
thor (~> 0.14) thor (~> 0.14)
selenium-webdriver (3.5.0) selenium-webdriver (3.12.0)
childprocess (~> 0.5) childprocess (~> 0.5)
rubyzip (~> 1.0) rubyzip (~> 1.2)
sentry-raven (2.7.2) 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)
...@@ -1012,7 +1013,7 @@ DEPENDENCIES ...@@ -1012,7 +1013,7 @@ DEPENDENCIES
doorkeeper-openid_connect (~> 1.3) 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 (~> 2.2.0)
factory_bot_rails (~> 4.8.2) factory_bot_rails (~> 4.8.2)
faraday (~> 0.12) faraday (~> 0.12)
fast_blank fast_blank
...@@ -1084,7 +1085,7 @@ DEPENDENCIES ...@@ -1084,7 +1085,7 @@ DEPENDENCIES
net-ssh (~> 4.2.0) net-ssh (~> 4.2.0)
nokogiri (~> 1.8.2) nokogiri (~> 1.8.2)
oauth2 (~> 1.4) oauth2 (~> 1.4)
octokit (~> 4.8) octokit (~> 4.9)
omniauth (~> 1.8) omniauth (~> 1.8)
omniauth-auth0 (~> 2.0.0) omniauth-auth0 (~> 2.0.0)
omniauth-authentiq (~> 0.3.3) omniauth-authentiq (~> 0.3.3)
...@@ -1154,7 +1155,7 @@ DEPENDENCIES ...@@ -1154,7 +1155,7 @@ DEPENDENCIES
scss_lint (~> 0.56.0) scss_lint (~> 0.56.0)
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.12)
sentry-raven (~> 2.7) sentry-raven (~> 2.7)
settingslogic (~> 2.0.9) settingslogic (~> 2.0.9)
sham_rack (~> 1.3.6) sham_rack (~> 1.3.6)
......
...@@ -72,8 +72,6 @@ GEM ...@@ -72,8 +72,6 @@ GEM
attr_encrypted (3.1.0) attr_encrypted (3.1.0)
encryptor (~> 3.0.0) encryptor (~> 3.0.0)
attr_required (1.0.1) attr_required (1.0.1)
autoprefixer-rails (8.1.0.1)
execjs
awesome_print (1.2.0) awesome_print (1.2.0)
axiom-types (0.1.1) axiom-types (0.1.1)
descendants_tracker (~> 0.0.4) descendants_tracker (~> 0.0.4)
...@@ -93,9 +91,6 @@ GEM ...@@ -93,9 +91,6 @@ GEM
binding_of_caller (0.7.3) binding_of_caller (0.7.3)
debug_inspector (>= 0.0.1) debug_inspector (>= 0.0.1)
blankslate (2.1.2.4) blankslate (2.1.2.4)
bootstrap-sass (3.3.7)
autoprefixer-rails (>= 5.2.1)
sass (>= 3.3.4)
bootstrap_form (2.7.0) bootstrap_form (2.7.0)
brakeman (4.2.1) brakeman (4.2.1)
browser (2.5.3) browser (2.5.3)
...@@ -175,7 +170,7 @@ GEM ...@@ -175,7 +170,7 @@ GEM
diff-lcs (1.3) diff-lcs (1.3)
diffy (3.1.0) diffy (3.1.0)
docile (1.1.5) docile (1.1.5)
domain_name (0.5.20170404) domain_name (0.5.20180417)
unf (>= 0.0.5, < 1.0.0) unf (>= 0.0.5, < 1.0.0)
doorkeeper (4.3.1) doorkeeper (4.3.1)
railties (>= 4.2) railties (>= 4.2)
...@@ -185,9 +180,10 @@ GEM ...@@ -185,9 +180,10 @@ GEM
dropzonejs-rails (0.7.4) dropzonejs-rails (0.7.4)
rails (> 3.1) rails (> 3.1)
email_reply_trimmer (0.1.10) email_reply_trimmer (0.1.10)
email_spec (1.6.0) email_spec (2.2.0)
htmlentities (~> 4.3.3)
launchy (~> 2.1) launchy (~> 2.1)
mail (~> 2.2) mail (~> 2.7)
encryptor (3.0.0) encryptor (3.0.0)
equalizer (0.0.11) equalizer (0.0.11)
erubis (2.7.0) erubis (2.7.0)
...@@ -288,7 +284,7 @@ GEM ...@@ -288,7 +284,7 @@ GEM
gettext_i18n_rails (>= 0.7.1) gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0) po_to_json (>= 1.0.0)
rails (>= 3.2.0) rails (>= 3.2.0)
gitaly-proto (0.99.0) gitaly-proto (0.100.0)
google-protobuf (~> 3.1) google-protobuf (~> 3.1)
grpc (~> 1.10) grpc (~> 1.10)
github-linguist (5.3.3) github-linguist (5.3.3)
...@@ -365,9 +361,9 @@ GEM ...@@ -365,9 +361,9 @@ GEM
grape-entity (0.7.1) grape-entity (0.7.1)
activesupport (>= 4.0) activesupport (>= 4.0)
multi_json (>= 1.3.2) multi_json (>= 1.3.2)
grape-route-helpers (2.1.0) grape-path-helpers (1.0.0)
activesupport activesupport
grape (>= 0.16.0) grape (~> 1.0)
rake rake
grape_logging (1.7.0) grape_logging (1.7.0)
grape grape
...@@ -417,6 +413,7 @@ GEM ...@@ -417,6 +413,7 @@ GEM
httpclient (2.8.3) httpclient (2.8.3)
i18n (1.0.1) i18n (1.0.1)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
icalendar (2.4.1)
ice_nine (0.11.2) ice_nine (0.11.2)
influxdb (0.5.3) influxdb (0.5.3)
ipaddress (0.8.3) ipaddress (0.8.3)
...@@ -450,9 +447,9 @@ GEM ...@@ -450,9 +447,9 @@ GEM
kgio (2.11.2) kgio (2.11.2)
knapsack (1.16.0) knapsack (1.16.0)
rake rake
kubeclient (3.0.0) kubeclient (3.1.1)
http (~> 2.2.2) http (~> 2.2.2)
recursive-open-struct (~> 1.0.4) recursive-open-struct (~> 1.0, >= 1.0.4)
rest-client (~> 2.0) rest-client (~> 2.0)
launchy (2.4.3) launchy (2.4.3)
addressable (~> 2.3) addressable (~> 2.3)
...@@ -521,15 +518,16 @@ GEM ...@@ -521,15 +518,16 @@ 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.8.0) octokit (4.9.0)
sawyer (~> 0.8.0, >= 0.5.3) sawyer (~> 0.8.0, >= 0.5.3)
omniauth (1.8.1) omniauth (1.8.1)
hashie (>= 3.4.6, < 3.6.0) hashie (>= 3.4.6, < 3.6.0)
rack (>= 1.6.2, < 3) rack (>= 1.6.2, < 3)
omniauth-auth0 (2.0.0) omniauth-auth0 (2.0.0)
omniauth-oauth2 (~> 1.4) omniauth-oauth2 (~> 1.4)
omniauth-authentiq (0.3.1) omniauth-authentiq (0.3.3)
omniauth-oauth2 (~> 1.3, >= 1.3.1) jwt (>= 1.5)
omniauth-oauth2 (>= 1.5)
omniauth-azure-oauth2 (0.0.9) omniauth-azure-oauth2 (0.0.9)
jwt (~> 1.0) jwt (~> 1.0)
omniauth (~> 1.0) omniauth (~> 1.0)
...@@ -628,7 +626,7 @@ GEM ...@@ -628,7 +626,7 @@ GEM
parser parser
unparser unparser
procto (0.0.3) procto (0.0.3)
prometheus-client-mmap (0.9.2) prometheus-client-mmap (0.9.3)
pry (0.11.3) pry (0.11.3)
coderay (~> 1.1.0) coderay (~> 1.1.0)
method_source (~> 0.9.0) method_source (~> 0.9.0)
...@@ -702,11 +700,11 @@ GEM ...@@ -702,11 +700,11 @@ GEM
ffi ffi
rbnacl-libsodium (1.0.16) rbnacl-libsodium (1.0.16)
rbnacl (>= 3.0.1) rbnacl (>= 3.0.1)
rdoc (4.3.0) rdoc (6.0.4)
re2 (1.1.1) re2 (1.1.1)
recaptcha (3.4.0) recaptcha (3.4.0)
json json
recursive-open-struct (1.0.5) recursive-open-struct (1.1.0)
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)
...@@ -716,8 +714,8 @@ GEM ...@@ -716,8 +714,8 @@ GEM
redis-activesupport (5.0.4) redis-activesupport (5.0.4)
activesupport (>= 3, < 6) activesupport (>= 3, < 6)
redis-store (>= 1.3, < 2) redis-store (>= 1.3, < 2)
redis-namespace (1.5.3) redis-namespace (1.6.0)
redis (~> 3.0, >= 3.0.4) redis (>= 3.0.4)
redis-rack (2.0.4) redis-rack (2.0.4)
rack (>= 1.5, < 3) rack (>= 1.5, < 3)
redis-store (>= 1.2, < 2) redis-store (>= 1.2, < 2)
...@@ -836,7 +834,7 @@ GEM ...@@ -836,7 +834,7 @@ GEM
activesupport (>= 3.1) activesupport (>= 3.1)
select2-rails (3.5.10) select2-rails (3.5.10)
thor (~> 0.14) thor (~> 0.14)
selenium-webdriver (3.11.0) selenium-webdriver (3.12.0)
childprocess (~> 0.5) childprocess (~> 0.5)
rubyzip (~> 1.2) rubyzip (~> 1.2)
sentry-raven (2.7.2) sentry-raven (2.7.2)
...@@ -986,7 +984,7 @@ DEPENDENCIES ...@@ -986,7 +984,7 @@ DEPENDENCIES
asciidoctor-plantuml (= 0.0.8) asciidoctor-plantuml (= 0.0.8)
asset_sync (~> 2.4) asset_sync (~> 2.4)
attr_encrypted (~> 3.1.0) attr_encrypted (~> 3.1.0)
awesome_print (~> 1.2.0) awesome_print
babosa (~> 1.0.2) babosa (~> 1.0.2)
base32 (~> 0.3.0) base32 (~> 0.3.0)
batch-loader (~> 1.2.1) batch-loader (~> 1.2.1)
...@@ -994,7 +992,6 @@ DEPENDENCIES ...@@ -994,7 +992,6 @@ DEPENDENCIES
benchmark-ips (~> 2.3.0) benchmark-ips (~> 2.3.0)
better_errors (~> 2.1.0) better_errors (~> 2.1.0)
binding_of_caller (~> 0.7.2) binding_of_caller (~> 0.7.2)
bootstrap-sass (~> 3.3.0)
bootstrap_form (~> 2.7.0) bootstrap_form (~> 2.7.0)
brakeman (~> 4.2) brakeman (~> 4.2)
browser (~> 2.2) browser (~> 2.2)
...@@ -1021,7 +1018,7 @@ DEPENDENCIES ...@@ -1021,7 +1018,7 @@ DEPENDENCIES
doorkeeper-openid_connect (~> 1.3) 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 (~> 2.2.0)
factory_bot_rails (~> 4.8.2) factory_bot_rails (~> 4.8.2)
faraday (~> 0.12) faraday (~> 0.12)
fast_blank fast_blank
...@@ -1045,7 +1042,7 @@ DEPENDENCIES ...@@ -1045,7 +1042,7 @@ DEPENDENCIES
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.3) gettext_i18n_rails_js (~> 1.3)
gitaly-proto (~> 0.99.0) gitaly-proto (~> 0.100.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)
gitlab-gollum-lib (~> 4.2) gitlab-gollum-lib (~> 4.2)
...@@ -1059,7 +1056,7 @@ DEPENDENCIES ...@@ -1059,7 +1056,7 @@ DEPENDENCIES
gpgme gpgme
grape (~> 1.0) grape (~> 1.0)
grape-entity (~> 0.7.1) grape-entity (~> 0.7.1)
grape-route-helpers (~> 2.1.0) grape-path-helpers (~> 1.0)
grape_logging (~> 1.7) grape_logging (~> 1.7)
grpc (~> 1.11.0) grpc (~> 1.11.0)
haml_lint (~> 0.26.0) haml_lint (~> 0.26.0)
...@@ -1070,6 +1067,7 @@ DEPENDENCIES ...@@ -1070,6 +1067,7 @@ DEPENDENCIES
html-pipeline (~> 2.7.1) html-pipeline (~> 2.7.1)
html2text html2text
httparty (~> 0.13.3) httparty (~> 0.13.3)
icalendar
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)
...@@ -1077,7 +1075,7 @@ DEPENDENCIES ...@@ -1077,7 +1075,7 @@ DEPENDENCIES
jwt (~> 1.5.6) jwt (~> 1.5.6)
kaminari (~> 1.0) kaminari (~> 1.0)
knapsack (~> 1.16) knapsack (~> 1.16)
kubeclient (~> 3.0) kubeclient (~> 3.1.0)
letter_opener_web (~> 1.3.0) letter_opener_web (~> 1.3.0)
license_finder (~> 3.1) license_finder (~> 3.1)
licensee (~> 8.9) licensee (~> 8.9)
...@@ -1092,10 +1090,10 @@ DEPENDENCIES ...@@ -1092,10 +1090,10 @@ DEPENDENCIES
net-ssh (~> 4.2.0) net-ssh (~> 4.2.0)
nokogiri (~> 1.8.2) nokogiri (~> 1.8.2)
oauth2 (~> 1.4) oauth2 (~> 1.4)
octokit (~> 4.8) octokit (~> 4.9)
omniauth (~> 1.8) omniauth (~> 1.8)
omniauth-auth0 (~> 2.0.0) omniauth-auth0 (~> 2.0.0)
omniauth-authentiq (~> 0.3.1) omniauth-authentiq (~> 0.3.3)
omniauth-azure-oauth2 (~> 0.0.9) omniauth-azure-oauth2 (~> 0.0.9)
omniauth-cas3 (~> 1.1.4) omniauth-cas3 (~> 1.1.4)
omniauth-facebook (~> 4.0.0) omniauth-facebook (~> 4.0.0)
...@@ -1118,7 +1116,7 @@ DEPENDENCIES ...@@ -1118,7 +1116,7 @@ DEPENDENCIES
peek-sidekiq (~> 1.0.3) peek-sidekiq (~> 1.0.3)
pg (~> 0.18.2) pg (~> 0.18.2)
premailer-rails (~> 1.9.7) premailer-rails (~> 1.9.7)
prometheus-client-mmap (~> 0.9.2) prometheus-client-mmap (~> 0.9.3)
pry-byebug (~> 3.4.1) pry-byebug (~> 3.4.1)
pry-rails (~> 0.3.4) pry-rails (~> 0.3.4)
rack-attack (~> 4.4.1) rack-attack (~> 4.4.1)
...@@ -1134,12 +1132,12 @@ DEPENDENCIES ...@@ -1134,12 +1132,12 @@ DEPENDENCIES
rblineprof (~> 0.3.6) rblineprof (~> 0.3.6)
rbnacl (~> 4.0) rbnacl (~> 4.0)
rbnacl-libsodium rbnacl-libsodium
rdoc (~> 4.2) rdoc (~> 6.0)
re2 (~> 1.1.1) re2 (~> 1.1.1)
recaptcha (~> 3.0) recaptcha (~> 3.0)
redcarpet (~> 3.4) redcarpet (~> 3.4)
redis (~> 3.2) redis (~> 3.2)
redis-namespace (~> 1.5.2) redis-namespace (~> 1.6.0)
redis-rails (~> 5.0.2) redis-rails (~> 5.0.2)
request_store (~> 1.3) request_store (~> 1.3)
responders (~> 2.0) responders (~> 2.0)
...@@ -1154,6 +1152,7 @@ DEPENDENCIES ...@@ -1154,6 +1152,7 @@ DEPENDENCIES
rubocop-rspec (~> 1.22.1) rubocop-rspec (~> 1.22.1)
ruby-fogbugz (~> 0.2.1) ruby-fogbugz (~> 0.2.1)
ruby-prof (~> 0.17.0) ruby-prof (~> 0.17.0)
ruby-progressbar
ruby_parser (~> 3.8) ruby_parser (~> 3.8)
rufus-scheduler (~> 3.4) rufus-scheduler (~> 3.4)
rugged (~> 0.27) rugged (~> 0.27)
...@@ -1162,12 +1161,12 @@ DEPENDENCIES ...@@ -1162,12 +1161,12 @@ DEPENDENCIES
scss_lint (~> 0.56.0) scss_lint (~> 0.56.0)
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.12)
sentry-raven (~> 2.7) 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)
sidekiq (~> 5.0) sidekiq (~> 5.1)
sidekiq-cron (~> 0.6.0) sidekiq-cron (~> 0.6.0)
sidekiq-limit_fetch (~> 3.4) sidekiq-limit_fetch (~> 3.4)
simple_po_parser (~> 1.1.2) simple_po_parser (~> 1.1.2)
...@@ -1199,4 +1198,4 @@ DEPENDENCIES ...@@ -1199,4 +1198,4 @@ DEPENDENCIES
wikicloth (= 0.8.1) wikicloth (= 0.8.1)
BUNDLED WITH BUNDLED WITH
1.16.1 1.16.2
...@@ -126,5 +126,5 @@ Please see [Getting help for GitLab](https://about.gitlab.com/getting-help/) on ...@@ -126,5 +126,5 @@ Please see [Getting help for GitLab](https://about.gitlab.com/getting-help/) on
## Is it awesome? ## Is it awesome?
Thanks for [asking this question](https://twitter.com/supersloth/status/489462789384056832) Joshua.
[These people](https://twitter.com/gitlab/likes) seem to like it. [These people](https://twitter.com/gitlab/likes) seem to like it.
...@@ -187,7 +187,7 @@ ...@@ -187,7 +187,7 @@
role="row" role="row"
> >
<div <div
class="alert alert-danger alert-block append-bottom-0" class="alert alert-danger alert-block append-bottom-0 clusters-error-alert"
role="gridcell" role="gridcell"
> >
<div> <div>
......
<script> <script>
import $ from 'jquery';
import { mapActions, mapGetters, mapState } from 'vuex'; import { mapActions, mapGetters, mapState } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
...@@ -20,6 +21,13 @@ export default { ...@@ -20,6 +21,13 @@ export default {
}, },
methods: { methods: {
...mapActions(['updateActivityBarView']), ...mapActions(['updateActivityBarView']),
changedActivityView(e, view) {
e.currentTarget.blur();
this.updateActivityBarView(view);
$(e.currentTarget).tooltip('hide');
},
}, },
activityBarViews, activityBarViews,
}; };
...@@ -54,7 +62,7 @@ export default { ...@@ -54,7 +62,7 @@ export default {
:class="{ :class="{
active: currentActivityView === $options.activityBarViews.edit active: currentActivityView === $options.activityBarViews.edit
}" }"
@click.prevent="updateActivityBarView($options.activityBarViews.edit)" @click.prevent="changedActivityView($event, $options.activityBarViews.edit)"
:title="s__('IDE|Edit')" :title="s__('IDE|Edit')"
:aria-label="s__('IDE|Edit')" :aria-label="s__('IDE|Edit')"
> >
...@@ -73,7 +81,7 @@ export default { ...@@ -73,7 +81,7 @@ export default {
:class="{ :class="{
active: currentActivityView === $options.activityBarViews.review active: currentActivityView === $options.activityBarViews.review
}" }"
@click.prevent="updateActivityBarView($options.activityBarViews.review)" @click.prevent="changedActivityView($event, $options.activityBarViews.review)"
:title="s__('IDE|Review')" :title="s__('IDE|Review')"
:aria-label="s__('IDE|Review')" :aria-label="s__('IDE|Review')"
> >
...@@ -92,7 +100,7 @@ export default { ...@@ -92,7 +100,7 @@ export default {
:class="{ :class="{
active: currentActivityView === $options.activityBarViews.commit active: currentActivityView === $options.activityBarViews.commit
}" }"
@click.prevent="updateActivityBarView($options.activityBarViews.commit)" @click.prevent="changedActivityView($event, $options.activityBarViews.commit)"
:title="s__('IDE|Commit')" :title="s__('IDE|Commit')"
:aria-label="s__('IDE|Commit')" :aria-label="s__('IDE|Commit')"
> >
......
...@@ -54,7 +54,7 @@ export default { ...@@ -54,7 +54,7 @@ export default {
placement: 'top', placement: 'top',
content: sprintf( content: sprintf(
__(` __(`
The character highligher helps you keep the subject line to %{titleLength} characters The character highlighter helps you keep the subject line to %{titleLength} characters
and wrap the body at %{bodyLength} so they are readable in git. and wrap the body at %{bodyLength} so they are readable in git.
`), `),
{ titleLength: MAX_TITLE_LENGTH, bodyLength: MAX_BODY_LENGTH }, { titleLength: MAX_TITLE_LENGTH, bodyLength: MAX_BODY_LENGTH },
......
...@@ -426,7 +426,7 @@ export default class LabelsSelect { ...@@ -426,7 +426,7 @@ export default class LabelsSelect {
const tpl = _.template([ const tpl = _.template([
'<% _.each(labels, function(label){ %>', '<% _.each(labels, function(label){ %>',
'<a href="<%- issueUpdateURL.slice(0, issueUpdateURL.lastIndexOf("/")) %>?label_name[]=<%- encodeURIComponent(label.title) %>">', '<a href="<%- issueUpdateURL.slice(0, issueUpdateURL.lastIndexOf("/")) %>?label_name[]=<%- encodeURIComponent(label.title) %>">',
'<span class="label has-tooltip color-label" title="<%- label.description %>" style="background-color: <%- label.color %>; color: <%- label.text_color %>;">', '<span class="badge label has-tooltip color-label" title="<%- label.description %>" style="background-color: <%- label.color %>; color: <%- label.text_color %>;">',
'<%- label.title %>', '<%- label.title %>',
'</span>', '</span>',
'</a>', '</a>',
......
...@@ -14,6 +14,7 @@ export const EPIC_NOTEABLE_TYPE = 'epic'; ...@@ -14,6 +14,7 @@ export const EPIC_NOTEABLE_TYPE = 'epic';
export const MERGE_REQUEST_NOTEABLE_TYPE = 'merge_request'; export const MERGE_REQUEST_NOTEABLE_TYPE = 'merge_request';
export const UNRESOLVE_NOTE_METHOD_NAME = 'delete'; export const UNRESOLVE_NOTE_METHOD_NAME = 'delete';
export const RESOLVE_NOTE_METHOD_NAME = 'post'; export const RESOLVE_NOTE_METHOD_NAME = 'post';
export const DESCRIPTION_TYPE = 'changed the description';
export const NOTEABLE_TYPE_MAPPING = { export const NOTEABLE_TYPE_MAPPING = {
Issue: ISSUE_NOTEABLE_TYPE, Issue: ISSUE_NOTEABLE_TYPE,
......
import { n__, s__, sprintf } from '~/locale';
import { DESCRIPTION_TYPE } from '../constants';
/**
* Changes the description from a note, returns 'changed the description n number of times'
*/
export const changeDescriptionNote = (note, descriptionChangedTimes, timeDifferenceMinutes) => {
const descriptionNote = Object.assign({}, note);
descriptionNote.note_html = sprintf(
s__(`MergeRequest|
%{paragraphStart}changed the description %{descriptionChangedTimes} times %{timeDifferenceMinutes}%{paragraphEnd}`),
{
paragraphStart: '<p dir="auto">',
paragraphEnd: '</p>',
descriptionChangedTimes,
timeDifferenceMinutes: n__('within %d minute ', 'within %d minutes ', timeDifferenceMinutes),
},
false,
);
descriptionNote.times_updated = descriptionChangedTimes;
return descriptionNote;
};
/**
* Checks the time difference between two notes from their 'created_at' dates
* returns an integer
*/
export const getTimeDifferenceMinutes = (noteBeggining, noteEnd) => {
const descriptionNoteBegin = new Date(noteBeggining.created_at);
const descriptionNoteEnd = new Date(noteEnd.created_at);
const timeDifferenceMinutes = (descriptionNoteEnd - descriptionNoteBegin) / 1000 / 60;
return Math.ceil(timeDifferenceMinutes);
};
/**
* Checks if a note is a system note and if the content is description
*
* @param {Object} note
* @returns {Boolean}
*/
export const isDescriptionSystemNote = note => note.system && note.note === DESCRIPTION_TYPE;
/**
* Collapses the system notes of a description type, e.g. Changed the description, n minutes ago
* the notes will collapse as long as they happen no more than 10 minutes away from each away
* in between the notes can be anything, another type of system note
* (such as 'changed the weight') or a comment.
*
* @param {Array} notes
* @returns {Array}
*/
export const collapseSystemNotes = notes => {
let lastDescriptionSystemNote = null;
let lastDescriptionSystemNoteIndex = -1;
let descriptionChangedTimes = 1;
return notes.slice(0).reduce((acc, currentNote) => {
const note = currentNote.notes[0];
if (isDescriptionSystemNote(note)) {
// is it the first one?
if (!lastDescriptionSystemNote) {
lastDescriptionSystemNote = note;
lastDescriptionSystemNoteIndex = acc.length;
} else if (lastDescriptionSystemNote) {
const timeDifferenceMinutes = getTimeDifferenceMinutes(
lastDescriptionSystemNote,
note,
);
// are they less than 10 minutes appart?
if (timeDifferenceMinutes > 10) {
// reset counter
descriptionChangedTimes = 1;
// update the previous system note
lastDescriptionSystemNote = note;
lastDescriptionSystemNoteIndex = acc.length;
} else {
// increase counter
descriptionChangedTimes += 1;
// delete the previous one
acc.splice(lastDescriptionSystemNoteIndex, 1);
// replace the text of the current system note with the collapsed note.
currentNote.notes.splice(
0,
1,
changeDescriptionNote(note, descriptionChangedTimes, timeDifferenceMinutes),
);
// update the previous system note index
lastDescriptionSystemNoteIndex = acc.length;
}
}
}
acc.push(currentNote);
return acc;
}, []);
};
// for babel-rewire
export default {};
import _ from 'underscore'; import _ from 'underscore';
import { collapseSystemNotes } from './collapse_utils';
export const notes = state => collapseSystemNotes(state.notes);
export const notes = state => state.notes;
export const targetNoteHash = state => state.targetNoteHash; export const targetNoteHash = state => state.targetNoteHash;
export const getNotesData = state => state.notesData; export const getNotesData = state => state.notesData;
......
...@@ -265,10 +265,10 @@ export default { ...@@ -265,10 +265,10 @@ export default {
/> />
<section <section
v-if="mr.maintainerEditAllowed" v-if="mr.allowCollaboration"
class="mr-info-list mr-links" class="mr-info-list mr-links"
> >
{{ s__("mrWidget|Allows edits from maintainers") }} {{ s__("mrWidget|Allows commits from members who can merge to the target branch") }}
</section> </section>
<mr-widget-related-links <mr-widget-related-links
......
...@@ -83,7 +83,7 @@ export default class MergeRequestStore { ...@@ -83,7 +83,7 @@ export default class MergeRequestStore {
this.canBeMerged = data.can_be_merged || false; this.canBeMerged = data.can_be_merged || false;
this.isMergeAllowed = data.mergeable || false; this.isMergeAllowed = data.mergeable || false;
this.mergeOngoing = data.merge_ongoing; this.mergeOngoing = data.merge_ongoing;
this.maintainerEditAllowed = data.allow_maintainer_to_push; this.allowCollaboration = data.allow_collaboration;
// Cherry-pick and Revert actions related // Cherry-pick and Revert actions related
this.canCherryPickInCurrentMR = currentUser.can_cherry_pick_on_current_merge_request || false; this.canCherryPickInCurrentMR = currentUser.can_cherry_pick_on_current_merge_request || false;
......
...@@ -35,7 +35,12 @@ export default { ...@@ -35,7 +35,12 @@ export default {
</script> </script>
<template> <template>
<div class="hide-collapsed value issuable-show-labels js-value"> <div
class="hide-collapsed value issuable-show-labels js-value"
:class="{
'has-labels':!isEmpty,
}"
>
<span <span
v-if="isEmpty" v-if="isEmpty"
class="text-secondary" class="text-secondary"
...@@ -50,7 +55,7 @@ export default { ...@@ -50,7 +55,7 @@ export default {
> >
<span <span
v-tooltip v-tooltip
class="label color-label" class="badge color-label"
data-placement="bottom" data-placement="bottom"
data-container="body" data-container="body"
:style="labelStyle(label)" :style="labelStyle(label)"
......
...@@ -36,6 +36,12 @@ html [type="button"], ...@@ -36,6 +36,12 @@ html [type="button"],
cursor: pointer; cursor: pointer;
} }
input[type="file"] {
// Bootstrap 4 file input height is taller by default
// which makes them look ugly
line-height: 1;
}
b, b,
strong { strong {
font-weight: bold; font-weight: bold;
...@@ -55,8 +61,23 @@ a { ...@@ -55,8 +61,23 @@ a {
code { code {
padding: 2px 4px; padding: 2px 4px;
color: $red-600;
background-color: $red-100; background-color: $red-100;
border-radius: 3px; border-radius: 3px;
.code & {
background-color: inherit;
padding: unset;
}
.build-trace & {
background-color: inherit;
padding: inherit;
}
}
.code {
padding: 9.5px;
} }
table { table {
...@@ -162,7 +183,9 @@ table { ...@@ -162,7 +183,9 @@ table {
.nav-tabs { .nav-tabs {
.nav-link { .nav-link {
border: 0; border-top: 0;
border-left: 0;
border-right: 0;
} }
.nav-item { .nav-item {
......
...@@ -35,6 +35,12 @@ ...@@ -35,6 +35,12 @@
@include media-breakpoint-down(xs) { @include media-breakpoint-down(xs) {
width: 100%; width: 100%;
} }
&.projects-dropdown-menu {
padding: 0;
overflow-y: initial;
max-height: initial;
}
} }
.dropdown-toggle, .dropdown-toggle,
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
} }
&.active > a, &.active > a,
&.dropdown.open > a { &.dropdown.show > a {
color: $color-900; color: $color-900;
background-color: $color-alternate; background-color: $color-alternate;
} }
...@@ -74,7 +74,7 @@ ...@@ -74,7 +74,7 @@
} }
&.active > a, &.active > a,
&.dropdown.open > a { &.dropdown.show > a {
color: $color-900; color: $color-900;
background-color: $color-alternate; background-color: $color-alternate;
......
...@@ -297,12 +297,6 @@ ...@@ -297,12 +297,6 @@
display: flex; display: flex;
margin: 0 0 0 6px; margin: 0 0 0 6px;
.projects-dropdown-menu {
padding: 0;
overflow-y: initial;
max-height: initial;
}
.dropdown-chevron { .dropdown-chevron {
position: relative; position: relative;
top: -1px; top: -1px;
......
...@@ -115,9 +115,3 @@ body { ...@@ -115,9 +115,3 @@ body {
.with-performance-bar .layout-page { .with-performance-bar .layout-page {
margin-top: $header-height + $performance-bar-height; margin-top: $header-height + $performance-bar-height;
} }
.vertical-center {
min-height: 100vh;
display: flex;
align-items: center;
}
...@@ -11,15 +11,15 @@ ...@@ -11,15 +11,15 @@
padding-top: $gl-padding; padding-top: $gl-padding;
} }
.panel { .card {
.panel-heading { .card-header {
display: -webkit-flex; display: -webkit-flex;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
line-height: $line-height-base; line-height: $line-height-base;
.title { .card-title {
display: flex; display: flex;
align-items: center; align-items: center;
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
.navbar-collapse { .navbar-collapse {
padding-right: 0; padding-right: 0;
flex-grow: 0;
flex-basis: auto;
.navbar-nav { .navbar-nav {
margin: 0; margin: 0;
......
...@@ -114,20 +114,20 @@ ...@@ -114,20 +114,20 @@
font-size: 0.95em; font-size: 0.95em;
} }
blockquote,
.blockquote { .blockquote {
color: $gl-grayish-blue; color: $gl-grayish-blue;
font-size: inherit; font-size: inherit;
padding: 8px 24px; padding: 8px 24px;
margin: 16px 0; margin: 16px 0;
border-left: 3px solid $white-dark; border-left: 3px solid $white-dark;
}
.blockquote:dir(rtl) { &:dir(rtl) {
border-left: 0; border-left: 0;
border-right: 3px solid $white-dark; border-right: 3px solid $white-dark;
} }
.blockquote p { p {
color: $gl-grayish-blue !important; color: $gl-grayish-blue !important;
font-size: inherit; font-size: inherit;
line-height: 1.5; line-height: 1.5;
...@@ -136,6 +136,7 @@ ...@@ -136,6 +136,7 @@
margin: 0; margin: 0;
} }
} }
}
p { p {
color: $gl-text-color; color: $gl-text-color;
......
...@@ -138,6 +138,7 @@ pre { ...@@ -138,6 +138,7 @@ pre {
margin: 0; margin: 0;
} }
blockquote,
.blockquote { .blockquote {
color: $gl-grayish-blue; color: $gl-grayish-blue;
padding: 0 0 0 15px; padding: 0 0 0 15px;
......
...@@ -13,6 +13,10 @@ ...@@ -13,6 +13,10 @@
max-width: 100%; max-width: 100%;
} }
.clusters-error-alert {
width: 100%;
}
.clusters-container { .clusters-container {
.nav-bar-right { .nav-bar-right {
padding: $gl-padding-top $gl-padding; padding: $gl-padding-top $gl-padding;
......
...@@ -196,6 +196,10 @@ ...@@ -196,6 +196,10 @@
.prioritized-labels { .prioritized-labels {
margin-bottom: 30px; margin-bottom: 30px;
h5 {
font-size: $gl-font-size;
}
.add-priority { .add-priority {
display: none; display: none;
color: $gray-light; color: $gray-light;
...@@ -210,6 +214,10 @@ ...@@ -210,6 +214,10 @@
} }
.other-labels { .other-labels {
h5 {
font-size: $gl-font-size;
}
.remove-priority { .remove-priority {
display: none; display: none;
} }
......
...@@ -183,7 +183,7 @@ ...@@ -183,7 +183,7 @@
svg { svg {
position: relative; position: relative;
top: -1px; top: -2px;
} }
.ide-file-changed-icon { .ide-file-changed-icon {
...@@ -458,6 +458,10 @@ ...@@ -458,6 +458,10 @@
width: auto; width: auto;
margin-right: 0; margin-right: 0;
a {
height: 60px;
}
a:hover, a:hover,
a:focus { a:focus {
text-decoration: none; text-decoration: none;
...@@ -718,9 +722,17 @@ ...@@ -718,9 +722,17 @@
} }
.ide-new-btn { .ide-new-btn {
.btn {
padding-top: 3px;
padding-bottom: 3px;
}
.dropdown {
display: flex;
}
.dropdown-toggle svg { .dropdown-toggle svg {
margin-top: -2px; top: 0;
margin-bottom: 2px;
} }
.dropdown-menu { .dropdown-menu {
...@@ -877,6 +889,7 @@ ...@@ -877,6 +889,7 @@
border-top: 1px solid transparent; border-top: 1px solid transparent;
border-bottom: 1px solid transparent; border-bottom: 1px solid transparent;
outline: 0; outline: 0;
cursor: pointer;
svg { svg {
margin: 0 auto; margin: 0 auto;
......
...@@ -174,7 +174,7 @@ ...@@ -174,7 +174,7 @@
.option-description, .option-description,
.option-disabled-reason { .option-disabled-reason {
margin-left: 45px; margin-left: 30px;
color: $project-option-descr-color; color: $project-option-descr-color;
} }
......
...@@ -22,9 +22,9 @@ ...@@ -22,9 +22,9 @@
header, header,
nav, nav,
nav.main-nav,
nav.navbar-collapse, nav.navbar-collapse,
nav.navbar-collapse.collapse, nav.navbar-collapse.collapse,
.nav-sidebar,
.profiler-results, .profiler-results,
.tree-ref-holder, .tree-ref-holder,
.tree-holder .breadcrumb, .tree-holder .breadcrumb,
...@@ -38,7 +38,8 @@ ul.notes-form, ...@@ -38,7 +38,8 @@ ul.notes-form,
.edit-link, .edit-link,
.note-action-button, .note-action-button,
.right-sidebar, .right-sidebar,
.flash-container { .flash-container,
#js-peek {
display: none !important; display: none !important;
} }
......
...@@ -24,7 +24,9 @@ module Groups ...@@ -24,7 +24,9 @@ module Groups
# Make the `search` param consistent for the frontend, # Make the `search` param consistent for the frontend,
# which will be using `filter`. # which will be using `filter`.
params[:search] ||= params[:filter] if params[:filter] params[:search] ||= params[:filter] if params[:filter]
params.permit(:sort, :search) # Don't show archived projects
params[:non_archived] = true
params.permit(:sort, :search, :non_archived)
end end
end end
end end
......
...@@ -18,7 +18,7 @@ class Projects::LfsStorageController < Projects::GitHttpClientController ...@@ -18,7 +18,7 @@ class Projects::LfsStorageController < Projects::GitHttpClientController
def upload_authorize def upload_authorize
set_workhorse_internal_api_content_type set_workhorse_internal_api_content_type
authorized = LfsObjectUploader.workhorse_authorize authorized = LfsObjectUploader.workhorse_authorize(has_length: true)
authorized.merge!(LfsOid: oid, LfsSize: size) authorized.merge!(LfsOid: oid, LfsSize: size)
render json: authorized render json: authorized
......
...@@ -15,7 +15,7 @@ class Projects::MergeRequests::ApplicationController < Projects::ApplicationCont ...@@ -15,7 +15,7 @@ class Projects::MergeRequests::ApplicationController < Projects::ApplicationCont
def merge_request_params_attributes def merge_request_params_attributes
[ [
:allow_maintainer_to_push, :allow_collaboration,
:assignee_id, :assignee_id,
:description, :description,
:force_remove_source_branch, :force_remove_source_branch,
......
class Projects::MilestonesController < Projects::ApplicationController class Projects::MilestonesController < Projects::ApplicationController
include Gitlab::Utils::StrongMemoize
include MilestoneActions include MilestoneActions
before_action :check_issuables_available! before_action :check_issuables_available!
...@@ -103,7 +104,7 @@ class Projects::MilestonesController < Projects::ApplicationController ...@@ -103,7 +104,7 @@ class Projects::MilestonesController < Projects::ApplicationController
protected protected
def milestones def milestones
@milestones ||= begin strong_memoize(:milestones) do
MilestonesFinder.new(search_params).execute MilestonesFinder.new(search_params).execute
end end
end end
...@@ -121,10 +122,10 @@ class Projects::MilestonesController < Projects::ApplicationController ...@@ -121,10 +122,10 @@ class Projects::MilestonesController < Projects::ApplicationController
end end
def search_params def search_params
if @project.group && can?(current_user, :read_group, @project.group) if request.format.json? && @project.group && can?(current_user, :read_group, @project.group)
group = @project.group groups = @project.group.self_and_ancestors
end end
params.permit(:state).merge(project_ids: @project.id, group_ids: group&.id) params.permit(:state).merge(project_ids: @project.id, group_ids: groups&.select(:id))
end end
end end
...@@ -36,7 +36,7 @@ module ApplicationSettingsHelper ...@@ -36,7 +36,7 @@ module ApplicationSettingsHelper
# Return a group of checkboxes that use Bootstrap's button plugin for a # Return a group of checkboxes that use Bootstrap's button plugin for a
# toggle button effect. # toggle button effect.
def restricted_level_checkboxes(help_block_id, checkbox_name) def restricted_level_checkboxes(help_block_id, checkbox_name, options = {})
Gitlab::VisibilityLevel.values.map do |level| Gitlab::VisibilityLevel.values.map do |level|
checked = restricted_visibility_levels(true).include?(level) checked = restricted_visibility_levels(true).include?(level)
css_class = checked ? 'active' : '' css_class = checked ? 'active' : ''
...@@ -46,6 +46,7 @@ module ApplicationSettingsHelper ...@@ -46,6 +46,7 @@ module ApplicationSettingsHelper
check_box_tag(checkbox_name, level, checked, check_box_tag(checkbox_name, level, checked,
autocomplete: 'off', autocomplete: 'off',
'aria-describedby' => help_block_id, 'aria-describedby' => help_block_id,
'class' => options[:class],
id: tag_name) + visibility_level_icon(level) + visibility_level_label(level) id: tag_name) + visibility_level_icon(level) + visibility_level_label(level)
end end
end end
...@@ -53,7 +54,7 @@ module ApplicationSettingsHelper ...@@ -53,7 +54,7 @@ module ApplicationSettingsHelper
# Return a group of checkboxes that use Bootstrap's button plugin for a # Return a group of checkboxes that use Bootstrap's button plugin for a
# toggle button effect. # toggle button effect.
def import_sources_checkboxes(help_block_id) def import_sources_checkboxes(help_block_id, options = {})
Gitlab::ImportSources.options.map do |name, source| Gitlab::ImportSources.options.map do |name, source|
checked = Gitlab::CurrentSettings.import_sources.include?(source) checked = Gitlab::CurrentSettings.import_sources.include?(source)
css_class = checked ? 'active' : '' css_class = checked ? 'active' : ''
...@@ -63,6 +64,7 @@ module ApplicationSettingsHelper ...@@ -63,6 +64,7 @@ module ApplicationSettingsHelper
check_box_tag(checkbox_name, source, checked, check_box_tag(checkbox_name, source, checked,
autocomplete: 'off', autocomplete: 'off',
'aria-describedby' => help_block_id, 'aria-describedby' => help_block_id,
'class' => options[:class],
id: name.tr(' ', '_')) + name id: name.tr(' ', '_')) + name
end end
end end
......
...@@ -126,8 +126,8 @@ module MergeRequestsHelper ...@@ -126,8 +126,8 @@ module MergeRequestsHelper
link_to(url[merge_request.project, merge_request], data: data_attrs, &block) link_to(url[merge_request.project, merge_request], data: data_attrs, &block)
end end
def allow_maintainer_push_unavailable_reason(merge_request) def allow_collaboration_unavailable_reason(merge_request)
return if merge_request.can_allow_maintainer_to_push?(current_user) return if merge_request.can_allow_collaboration?(current_user)
minimum_visibility = [merge_request.target_project.visibility_level, minimum_visibility = [merge_request.target_project.visibility_level,
merge_request.source_project.visibility_level].min merge_request.source_project.visibility_level].min
......
...@@ -238,6 +238,14 @@ module ProjectsHelper ...@@ -238,6 +238,14 @@ module ProjectsHelper
"git push --set-upstream #{repository_url}/$(git rev-parse --show-toplevel | xargs basename).git $(git rev-parse --abbrev-ref HEAD)" "git push --set-upstream #{repository_url}/$(git rev-parse --show-toplevel | xargs basename).git $(git rev-parse --abbrev-ref HEAD)"
end end
def show_xcode_link?(project = @project)
browser.platform.mac? && project.repository.xcode_project?
end
def xcode_uri_to_repo(project = @project)
"xcode://clone?repo=#{CGI.escape(default_url_to_repo(project))}"
end
private private
def get_project_nav_tabs(project, current_user) def get_project_nav_tabs(project, current_user)
......
...@@ -25,14 +25,22 @@ module SearchHelper ...@@ -25,14 +25,22 @@ module SearchHelper
return unless collection.count > 0 return unless collection.count > 0
from = collection.offset_value + 1 from = collection.offset_value + 1
to = collection.offset_value + collection.length to = collection.offset_value + collection.count
count = collection.total_count count = collection.total_count
"Showing #{from} - #{to} of #{count} #{scope.humanize(capitalize: false)} for \"#{term}\"" "Showing #{from} - #{to} of #{count} #{scope.humanize(capitalize: false)} for \"#{term}\""
end end
def find_project_for_result_blob(result)
@project
end
def parse_search_result(result) def parse_search_result(result)
Gitlab::ProjectSearchResults.parse_search_result(result) result
end
def search_blob_title(project, filename)
filename
end end
private private
......
...@@ -55,6 +55,11 @@ module Ci ...@@ -55,6 +55,11 @@ module Ci
where('(artifacts_file IS NOT NULL AND artifacts_file <> ?) OR EXISTS (?)', where('(artifacts_file IS NOT NULL AND artifacts_file <> ?) OR EXISTS (?)',
'', Ci::JobArtifact.select(1).where('ci_builds.id = ci_job_artifacts.job_id').archive) '', Ci::JobArtifact.select(1).where('ci_builds.id = ci_job_artifacts.job_id').archive)
end end
scope :without_archived_trace, ->() do
where('NOT EXISTS (?)', Ci::JobArtifact.select(1).where('ci_builds.id = ci_job_artifacts.job_id').trace)
end
scope :with_artifacts_stored_locally, -> { with_artifacts_archive.where(artifacts_file_store: [nil, LegacyArtifactUploader::Store::LOCAL]) } scope :with_artifacts_stored_locally, -> { with_artifacts_archive.where(artifacts_file_store: [nil, LegacyArtifactUploader::Store::LOCAL]) }
scope :with_artifacts_not_expired, ->() { with_artifacts_archive.where('artifacts_expire_at IS NULL OR artifacts_expire_at > ?', Time.now) } scope :with_artifacts_not_expired, ->() { with_artifacts_archive.where('artifacts_expire_at IS NULL OR artifacts_expire_at > ?', Time.now) }
scope :with_expired_artifacts, ->() { with_artifacts_archive.where('artifacts_expire_at < ?', Time.now) } scope :with_expired_artifacts, ->() { with_artifacts_archive.where('artifacts_expire_at < ?', Time.now) }
...@@ -144,6 +149,7 @@ module Ci ...@@ -144,6 +149,7 @@ module Ci
after_transition any => [:success] do |build| after_transition any => [:success] do |build|
build.run_after_commit do build.run_after_commit do
BuildSuccessWorker.perform_async(id) BuildSuccessWorker.perform_async(id)
PagesWorker.perform_async(:deploy, id) if build.pages_generator?
end end
end end
...@@ -183,6 +189,11 @@ module Ci ...@@ -183,6 +189,11 @@ module Ci
pipeline.manual_actions.where.not(name: name) pipeline.manual_actions.where.not(name: name)
end end
def pages_generator?
Gitlab.config.pages.enabled &&
self.name == 'pages'
end
def playable? def playable?
action? && (manual? || retryable?) action? && (manual? || retryable?)
end end
...@@ -402,8 +413,6 @@ module Ci ...@@ -402,8 +413,6 @@ module Ci
build_data = Gitlab::DataBuilder::Build.build(self) build_data = Gitlab::DataBuilder::Build.build(self)
project.execute_hooks(build_data.dup, :job_hooks) project.execute_hooks(build_data.dup, :job_hooks)
project.execute_services(build_data.dup, :job_hooks) project.execute_services(build_data.dup, :job_hooks)
PagesService.new(build_data).execute
project.running_or_pending_build_count(force: true)
end end
def browsable_artifacts? def browsable_artifacts?
......
...@@ -7,12 +7,17 @@ module Ci ...@@ -7,12 +7,17 @@ module Ci
include Presentable include Presentable
include Gitlab::OptimisticLocking include Gitlab::OptimisticLocking
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
include AtomicInternalId
belongs_to :project, inverse_of: :pipelines belongs_to :project, inverse_of: :pipelines
belongs_to :user belongs_to :user
belongs_to :auto_canceled_by, class_name: 'Ci::Pipeline' belongs_to :auto_canceled_by, class_name: 'Ci::Pipeline'
belongs_to :pipeline_schedule, class_name: 'Ci::PipelineSchedule' belongs_to :pipeline_schedule, class_name: 'Ci::PipelineSchedule'
has_internal_id :iid, scope: :project, presence: false, init: ->(s) do
s&.project&.pipelines&.maximum(:iid) || s&.project&.pipelines&.count
end
has_many :stages has_many :stages
has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline
has_many :builds, foreign_key: :commit_id, inverse_of: :pipeline has_many :builds, foreign_key: :commit_id, inverse_of: :pipeline
...@@ -531,6 +536,7 @@ module Ci ...@@ -531,6 +536,7 @@ module Ci
def predefined_variables def predefined_variables
Gitlab::Ci::Variables::Collection.new Gitlab::Ci::Variables::Collection.new
.append(key: 'CI_PIPELINE_IID', value: iid.to_s)
.append(key: 'CI_CONFIG_PATH', value: ci_yaml_file_path) .append(key: 'CI_CONFIG_PATH', value: ci_yaml_file_path)
.append(key: 'CI_PIPELINE_SOURCE', value: source.to_s) .append(key: 'CI_PIPELINE_SOURCE', value: source.to_s)
.append(key: 'CI_COMMIT_MESSAGE', value: git_commit_message) .append(key: 'CI_COMMIT_MESSAGE', value: git_commit_message)
......
...@@ -219,10 +219,8 @@ module Ci ...@@ -219,10 +219,8 @@ module Ci
cache_attributes(values) cache_attributes(values)
if persist_cached_data? # We save data without validation, it will always change due to `contacted_at`
self.assign_attributes(values) self.update_columns(values) if persist_cached_data?
self.save if self.changed?
end
end end
def pick_build!(build) def pick_build!(build)
......
...@@ -11,12 +11,12 @@ module Clusters ...@@ -11,12 +11,12 @@ module Clusters
attr_encrypted :password, attr_encrypted :password,
mode: :per_attribute_iv, mode: :per_attribute_iv,
key: Gitlab::Application.secrets.db_key_base, key: Settings.attr_encrypted_db_key_base_truncated,
algorithm: 'aes-256-cbc' algorithm: 'aes-256-cbc'
attr_encrypted :token, attr_encrypted :token,
mode: :per_attribute_iv, mode: :per_attribute_iv,
key: Gitlab::Application.secrets.db_key_base, key: Settings.attr_encrypted_db_key_base_truncated,
algorithm: 'aes-256-cbc' algorithm: 'aes-256-cbc'
before_validation :enforce_namespace_to_lower_case before_validation :enforce_namespace_to_lower_case
......
...@@ -11,7 +11,7 @@ module Clusters ...@@ -11,7 +11,7 @@ module Clusters
attr_encrypted :access_token, attr_encrypted :access_token,
mode: :per_attribute_iv, mode: :per_attribute_iv,
key: Gitlab::Application.secrets.db_key_base, key: Settings.attr_encrypted_db_key_base_truncated,
algorithm: 'aes-256-cbc' algorithm: 'aes-256-cbc'
validates :gcp_project_id, validates :gcp_project_id,
......
...@@ -25,9 +25,13 @@ module AtomicInternalId ...@@ -25,9 +25,13 @@ module AtomicInternalId
extend ActiveSupport::Concern extend ActiveSupport::Concern
module ClassMethods module ClassMethods
def has_internal_id(column, scope:, init:) # rubocop:disable Naming/PredicateName def has_internal_id(column, scope:, init:, presence: true) # rubocop:disable Naming/PredicateName
before_validation(on: :create) do before_validation :"ensure_#{scope}_#{column}!", on: :create
validates column, presence: presence
define_method("ensure_#{scope}_#{column}!") do
scope_value = association(scope).reader scope_value = association(scope).reader
if read_attribute(column).blank? && scope_value if read_attribute(column).blank? && scope_value
scope_attrs = { scope_value.class.table_name.singularize.to_sym => scope_value } scope_attrs = { scope_value.class.table_name.singularize.to_sym => scope_value }
usage = self.class.table_name.to_sym usage = self.class.table_name.to_sym
...@@ -35,13 +39,9 @@ module AtomicInternalId ...@@ -35,13 +39,9 @@ module AtomicInternalId
new_iid = InternalId.generate_next(self, scope_attrs, usage, init) new_iid = InternalId.generate_next(self, scope_attrs, usage, init)
write_attribute(column, new_iid) write_attribute(column, new_iid)
end end
end
validates column, presence: true, numericality: true read_attribute(column)
end end
end end
def to_param
iid.to_s
end end
end end
...@@ -4,11 +4,14 @@ module Avatarable ...@@ -4,11 +4,14 @@ module Avatarable
included do included do
prepend ShadowMethods prepend ShadowMethods
include ObjectStorage::BackgroundMove include ObjectStorage::BackgroundMove
include Gitlab::Utils::StrongMemoize
validate :avatar_type, if: ->(user) { user.avatar.present? && user.avatar_changed? } validate :avatar_type, if: ->(user) { user.avatar.present? && user.avatar_changed? }
validates :avatar, file_size: { maximum: 200.kilobytes.to_i } validates :avatar, file_size: { maximum: 200.kilobytes.to_i }
mount_uploader :avatar, AvatarUploader mount_uploader :avatar, AvatarUploader
after_initialize :add_avatar_to_batch
end end
module ShadowMethods module ShadowMethods
...@@ -18,6 +21,17 @@ module Avatarable ...@@ -18,6 +21,17 @@ module Avatarable
avatar_path(only_path: args.fetch(:only_path, true)) || super avatar_path(only_path: args.fetch(:only_path, true)) || super
end end
def retrieve_upload(identifier, paths)
upload = retrieve_upload_from_batch(identifier)
# This fallback is needed when deleting an upload, because we may have
# already been removed from the DB. We have to check an explicit `#nil?`
# because it's a BatchLoader instance.
upload = super if upload.nil?
upload
end
end end
def avatar_type def avatar_type
...@@ -52,4 +66,37 @@ module Avatarable ...@@ -52,4 +66,37 @@ module Avatarable
url_base + avatar.local_url url_base + avatar.local_url
end end
# Path that is persisted in the tracking Upload model. Used to fetch the
# upload from the model.
def upload_paths(identifier)
avatar_mounter.blank_uploader.store_dirs.map { |store, path| File.join(path, identifier) }
end
private
def retrieve_upload_from_batch(identifier)
BatchLoader.for(identifier: identifier, model: self).batch(key: self.class) do |upload_params, loader, args|
model_class = args[:key]
paths = upload_params.flat_map do |params|
params[:model].upload_paths(params[:identifier])
end
Upload.where(uploader: AvatarUploader, path: paths).find_each do |upload|
model = model_class.instantiate('id' => upload.model_id)
loader.call({ model: model, identifier: File.basename(upload.path) }, upload)
end
end
end
def add_avatar_to_batch
return unless avatar_mounter
avatar_mounter.read_identifiers.each { |identifier| retrieve_upload_from_batch(identifier) }
end
def avatar_mounter
strong_memoize(:avatar_mounter) { _mounter(:avatar) }
end
end end
...@@ -13,7 +13,7 @@ module HasVariable ...@@ -13,7 +13,7 @@ module HasVariable
attr_encrypted :value, attr_encrypted :value,
mode: :per_attribute_iv_and_salt, mode: :per_attribute_iv_and_salt,
insecure_mode: true, insecure_mode: true,
key: Gitlab::Application.secrets.db_key_base, key: Settings.attr_encrypted_db_key_base,
algorithm: 'aes-256-cbc' algorithm: 'aes-256-cbc'
def key=(new_key) def key=(new_key)
......
module IidRoutes
##
# This automagically enforces all related routes to use `iid` instead of `id`
# If you want to use `iid` for some routes and `id` for other routes, this module should not to be included,
# instead you should define `iid` or `id` explictly at each route generators. e.g. pipeline_path(project.id, pipeline.iid)
def to_param
iid.to_s
end
end
...@@ -36,4 +36,8 @@ module WithUploads ...@@ -36,4 +36,8 @@ module WithUploads
upload.destroy upload.destroy
end end
end end
def retrieve_upload(_identifier, paths)
uploads.find_by(path: paths)
end
end end
class Deployment < ActiveRecord::Base class Deployment < ActiveRecord::Base
include AtomicInternalId include AtomicInternalId
include IidRoutes
belongs_to :project, required: true belongs_to :project, required: true
belongs_to :environment, required: true belongs_to :environment, required: true
......
...@@ -14,7 +14,7 @@ class InternalId < ActiveRecord::Base ...@@ -14,7 +14,7 @@ class InternalId < ActiveRecord::Base
belongs_to :project belongs_to :project
belongs_to :namespace belongs_to :namespace
enum usage: { issues: 0, merge_requests: 1, deployments: 2, milestones: 3, epics: 4 } enum usage: { issues: 0, merge_requests: 1, deployments: 2, milestones: 3, epics: 4, ci_pipelines: 5 }
validates :usage, presence: true validates :usage, presence: true
......
...@@ -2,6 +2,7 @@ require 'carrierwave/orm/activerecord' ...@@ -2,6 +2,7 @@ require 'carrierwave/orm/activerecord'
class Issue < ActiveRecord::Base class Issue < ActiveRecord::Base
include AtomicInternalId include AtomicInternalId
include IidRoutes
include Issuable include Issuable
include Noteable include Noteable
include Referable include Referable
......
class MergeRequest < ActiveRecord::Base class MergeRequest < ActiveRecord::Base
include AtomicInternalId include AtomicInternalId
include IidRoutes
include Issuable include Issuable
include Noteable include Noteable
include Referable include Referable
...@@ -1124,21 +1125,21 @@ class MergeRequest < ActiveRecord::Base ...@@ -1124,21 +1125,21 @@ class MergeRequest < ActiveRecord::Base
project.merge_requests.merged.where(author_id: author_id).empty? project.merge_requests.merged.where(author_id: author_id).empty?
end end
def allow_maintainer_to_push def allow_collaboration
maintainer_push_possible? && super collaborative_push_possible? && super
end end
alias_method :allow_maintainer_to_push?, :allow_maintainer_to_push alias_method :allow_collaboration?, :allow_collaboration
def maintainer_push_possible? def collaborative_push_possible?
source_project.present? && for_fork? && source_project.present? && for_fork? &&
target_project.visibility_level > Gitlab::VisibilityLevel::PRIVATE && target_project.visibility_level > Gitlab::VisibilityLevel::PRIVATE &&
source_project.visibility_level > Gitlab::VisibilityLevel::PRIVATE && source_project.visibility_level > Gitlab::VisibilityLevel::PRIVATE &&
!ProtectedBranch.protected?(source_project, source_branch) !ProtectedBranch.protected?(source_project, source_branch)
end end
def can_allow_maintainer_to_push?(user) def can_allow_collaboration?(user)
maintainer_push_possible? && collaborative_push_possible? &&
Ability.allowed?(user, :push_code, source_project) Ability.allowed?(user, :push_code, source_project)
end end
......
...@@ -9,6 +9,7 @@ class Milestone < ActiveRecord::Base ...@@ -9,6 +9,7 @@ class Milestone < ActiveRecord::Base
include CacheMarkdownField include CacheMarkdownField
include AtomicInternalId include AtomicInternalId
include IidRoutes
include Sortable include Sortable
include Referable include Referable
include StripAttribute include StripAttribute
......
...@@ -435,6 +435,10 @@ class Note < ActiveRecord::Base ...@@ -435,6 +435,10 @@ class Note < ActiveRecord::Base
super.merge(noteable: noteable) super.merge(noteable: noteable)
end end
def retrieve_upload(_identifier, paths)
Upload.find_by(model: self, path: paths)
end
private private
def keep_around_commit def keep_around_commit
......
...@@ -19,7 +19,7 @@ class PagesDomain < ActiveRecord::Base ...@@ -19,7 +19,7 @@ class PagesDomain < ActiveRecord::Base
attr_encrypted :key, attr_encrypted :key,
mode: :per_attribute_iv_and_salt, mode: :per_attribute_iv_and_salt,
insecure_mode: true, insecure_mode: true,
key: Gitlab::Application.secrets.db_key_base, key: Settings.attr_encrypted_db_key_base,
algorithm: 'aes-256-cbc' algorithm: 'aes-256-cbc'
after_initialize :set_verification_code after_initialize :set_verification_code
......
class PersonalSnippet < Snippet class PersonalSnippet < Snippet
include WithUploads
end end
...@@ -1649,12 +1649,6 @@ class Project < ActiveRecord::Base ...@@ -1649,12 +1649,6 @@ class Project < ActiveRecord::Base
import_state.update_column(:jid, nil) import_state.update_column(:jid, nil)
end end
def running_or_pending_build_count(force: false)
Rails.cache.fetch(['projects', id, 'running_or_pending_build_count'], force: force) do
builds.running_or_pending.count(:all)
end
end
# Lazy loading of the `pipeline_status` attribute # Lazy loading of the `pipeline_status` attribute
def pipeline_status def pipeline_status
@pipeline_status ||= Gitlab::Cache::Ci::ProjectPipelineStatus.load_for_project(self) @pipeline_status ||= Gitlab::Cache::Ci::ProjectPipelineStatus.load_for_project(self)
...@@ -1974,18 +1968,18 @@ class Project < ActiveRecord::Base ...@@ -1974,18 +1968,18 @@ class Project < ActiveRecord::Base
.limit(1) .limit(1)
.select(1) .select(1)
source_of_merge_requests.opened source_of_merge_requests.opened
.where(allow_maintainer_to_push: true) .where(allow_collaboration: true)
.where('EXISTS (?)', developer_access_exists) .where('EXISTS (?)', developer_access_exists)
end end
def branch_allows_maintainer_push?(user, branch_name) def branch_allows_collaboration?(user, branch_name)
return false unless user return false unless user
cache_key = "user:#{user.id}:#{branch_name}:branch_allows_push" cache_key = "user:#{user.id}:#{branch_name}:branch_allows_push"
memoized_results = strong_memoize(:branch_allows_maintainer_push) do memoized_results = strong_memoize(:branch_allows_collaboration) do
Hash.new do |result, cache_key| Hash.new do |result, cache_key|
result[cache_key] = fetch_branch_allows_maintainer_push?(user, branch_name) result[cache_key] = fetch_branch_allows_collaboration?(user, branch_name)
end end
end end
...@@ -2127,18 +2121,18 @@ class Project < ActiveRecord::Base ...@@ -2127,18 +2121,18 @@ class Project < ActiveRecord::Base
raise ex raise ex
end end
def fetch_branch_allows_maintainer_push?(user, branch_name) def fetch_branch_allows_collaboration?(user, branch_name)
check_access = -> do check_access = -> do
next false if empty_repo? next false if empty_repo?
merge_request = source_of_merge_requests.opened merge_request = source_of_merge_requests.opened
.where(allow_maintainer_to_push: true) .where(allow_collaboration: true)
.find_by(source_branch: branch_name) .find_by(source_branch: branch_name)
merge_request&.can_be_merged_by?(user) merge_request&.can_be_merged_by?(user)
end end
if RequestStore.active? if RequestStore.active?
RequestStore.fetch("project-#{id}:branch-#{branch_name}:user-#{user.id}:branch_allows_maintainer_push") do RequestStore.fetch("project-#{id}:branch-#{branch_name}:user-#{user.id}:branch_allows_collaboration") do
check_access.call check_access.call
end end
else else
......
...@@ -3,7 +3,7 @@ require 'carrierwave/orm/activerecord' ...@@ -3,7 +3,7 @@ require 'carrierwave/orm/activerecord'
class ProjectImportData < ActiveRecord::Base class ProjectImportData < ActiveRecord::Base
belongs_to :project, inverse_of: :import_data belongs_to :project, inverse_of: :import_data
attr_encrypted :credentials, attr_encrypted :credentials,
key: Gitlab::Application.secrets.db_key_base, key: Settings.attr_encrypted_db_key_base,
marshal: true, marshal: true,
encode: true, encode: true,
mode: :per_attribute_iv_and_salt, mode: :per_attribute_iv_and_salt,
......
...@@ -140,10 +140,6 @@ class ProjectWiki ...@@ -140,10 +140,6 @@ class ProjectWiki
[title, title_array.join("/")] [title, title_array.join("/")]
end end
def search_files(query)
repository.search_files_by_content(query, default_branch)
end
def repository def repository
@repository ||= Repository.new(full_path, @project, disk_path: disk_path, is_wiki: true) @repository ||= Repository.new(full_path, @project, disk_path: disk_path, is_wiki: true)
end end
......
...@@ -5,7 +5,7 @@ class RemoteMirror < ActiveRecord::Base ...@@ -5,7 +5,7 @@ class RemoteMirror < ActiveRecord::Base
UNPROTECTED_BACKOFF_DELAY = 5.minutes UNPROTECTED_BACKOFF_DELAY = 5.minutes
attr_encrypted :credentials, attr_encrypted :credentials,
key: Gitlab::Application.secrets.db_key_base, key: Settings.attr_encrypted_db_key_base,
marshal: true, marshal: true,
encode: true, encode: true,
mode: :per_attribute_iv_and_salt, mode: :per_attribute_iv_and_salt,
......
...@@ -14,8 +14,8 @@ module Ci ...@@ -14,8 +14,8 @@ module Ci
@subject.triggered_by?(@user) @subject.triggered_by?(@user)
end end
condition(:branch_allows_maintainer_push) do condition(:branch_allows_collaboration) do
@subject.project.branch_allows_maintainer_push?(@user, @subject.ref) @subject.project.branch_allows_collaboration?(@user, @subject.ref)
end end
rule { protected_ref }.policy do rule { protected_ref }.policy do
...@@ -25,7 +25,7 @@ module Ci ...@@ -25,7 +25,7 @@ module Ci
rule { can?(:admin_build) | (can?(:update_build) & owner_of_job) }.enable :erase_build rule { can?(:admin_build) | (can?(:update_build) & owner_of_job) }.enable :erase_build
rule { can?(:public_access) & branch_allows_maintainer_push }.policy do rule { can?(:public_access) & branch_allows_collaboration }.policy do
enable :update_build enable :update_build
enable :update_commit_status enable :update_commit_status
end end
......
...@@ -4,13 +4,13 @@ module Ci ...@@ -4,13 +4,13 @@ module Ci
condition(:protected_ref) { ref_protected?(@user, @subject.project, @subject.tag?, @subject.ref) } condition(:protected_ref) { ref_protected?(@user, @subject.project, @subject.tag?, @subject.ref) }
condition(:branch_allows_maintainer_push) do condition(:branch_allows_collaboration) do
@subject.project.branch_allows_maintainer_push?(@user, @subject.ref) @subject.project.branch_allows_collaboration?(@user, @subject.ref)
end end
rule { protected_ref }.prevent :update_pipeline rule { protected_ref }.prevent :update_pipeline
rule { can?(:public_access) & branch_allows_maintainer_push }.policy do rule { can?(:public_access) & branch_allows_collaboration }.policy do
enable :update_pipeline enable :update_pipeline
end end
......
...@@ -13,7 +13,7 @@ class MergeRequestWidgetEntity < IssuableEntity ...@@ -13,7 +13,7 @@ class MergeRequestWidgetEntity < IssuableEntity
expose :squash expose :squash
expose :target_branch expose :target_branch
expose :target_project_id expose :target_project_id
expose :allow_maintainer_to_push expose :allow_collaboration
expose :should_be_rebased?, as: :should_be_rebased expose :should_be_rebased?, as: :should_be_rebased
expose :ff_only_enabled do |merge_request| expose :ff_only_enabled do |merge_request|
......
...@@ -90,7 +90,7 @@ module Ci ...@@ -90,7 +90,7 @@ module Ci
def builds_for_group_runner def builds_for_group_runner
# Workaround for weird Rails bug, that makes `runner.groups.to_sql` to return `runner_id = NULL` # Workaround for weird Rails bug, that makes `runner.groups.to_sql` to return `runner_id = NULL`
groups = Group.joins(:runner_namespaces).merge(runner.runner_namespaces) groups = ::Group.joins(:runner_namespaces).merge(runner.runner_namespaces)
hierarchy_groups = Gitlab::GroupHierarchy.new(groups).base_and_descendants hierarchy_groups = Gitlab::GroupHierarchy.new(groups).base_and_descendants
projects = Project.where(namespace_id: hierarchy_groups) projects = Project.where(namespace_id: hierarchy_groups)
......
...@@ -38,8 +38,8 @@ module MergeRequests ...@@ -38,8 +38,8 @@ module MergeRequests
def filter_params(merge_request) def filter_params(merge_request)
super super
unless merge_request.can_allow_maintainer_to_push?(current_user) unless merge_request.can_allow_collaboration?(current_user)
params.delete(:allow_maintainer_to_push) params.delete(:allow_collaboration)
end end
end end
......
class PagesService
attr_reader :data
def initialize(data)
@data = data
end
def execute
return unless Settings.pages.enabled
return unless data[:build_name] == 'pages'
return unless data[:build_status] == 'success'
PagesWorker.perform_async(:deploy, data[:build_id])
end
end
...@@ -11,7 +11,7 @@ module Projects ...@@ -11,7 +11,7 @@ module Projects
order: { due_date: :asc, title: :asc } order: { due_date: :asc, title: :asc }
} }
finder_params[:group_ids] = [@project.group.id] if @project.group finder_params[:group_ids] = @project.group.self_and_ancestors.select(:id) if @project.group
MilestonesFinder.new(finder_params).execute.select([:iid, :title]) MilestonesFinder.new(finder_params).execute.select([:iid, :title])
end end
......
...@@ -17,6 +17,8 @@ module Projects ...@@ -17,6 +17,8 @@ module Projects
ensure_wiki_exists if enabling_wiki? ensure_wiki_exists if enabling_wiki?
yield if block_given?
if project.update_attributes(params.except(:default_branch)) if project.update_attributes(params.except(:default_branch))
if project.previous_changes.include?('path') if project.previous_changes.include?('path')
project.rename_repo project.rename_repo
...@@ -36,7 +38,7 @@ module Projects ...@@ -36,7 +38,7 @@ module Projects
end end
def run_auto_devops_pipeline? def run_auto_devops_pipeline?
return false if project.repository.gitlab_ci_yml || !project.auto_devops.previous_changes.include?('enabled') return false if project.repository.gitlab_ci_yml || !project.auto_devops&.previous_changes&.include?('enabled')
project.auto_devops.enabled? || (project.auto_devops.enabled.nil? && Gitlab::CurrentSettings.auto_devops_enabled?) project.auto_devops.enabled? || (project.auto_devops.enabled.nil? && Gitlab::CurrentSettings.auto_devops_enabled?)
end end
...@@ -53,8 +55,8 @@ module Projects ...@@ -53,8 +55,8 @@ module Projects
def changing_default_branch? def changing_default_branch?
new_branch = params[:default_branch] new_branch = params[:default_branch]
project.repository.exists? && new_branch && project.repository.exists? &&
new_branch && new_branch != project.default_branch new_branch != project.default_branch
end end
def enabling_wiki? def enabling_wiki?
......
...@@ -10,8 +10,6 @@ module ObjectStorage ...@@ -10,8 +10,6 @@ module ObjectStorage
UnknownStoreError = Class.new(StandardError) UnknownStoreError = Class.new(StandardError)
ObjectStorageUnavailable = Class.new(StandardError) ObjectStorageUnavailable = Class.new(StandardError)
DIRECT_UPLOAD_TIMEOUT = 4.hours
DIRECT_UPLOAD_EXPIRE_OFFSET = 15.minutes
TMP_UPLOAD_PATH = 'tmp/uploads'.freeze TMP_UPLOAD_PATH = 'tmp/uploads'.freeze
module Store module Store
...@@ -35,7 +33,7 @@ module ObjectStorage ...@@ -35,7 +33,7 @@ module ObjectStorage
unless current_upload_satisfies?(paths, model) unless current_upload_satisfies?(paths, model)
# the upload we already have isn't right, find the correct one # the upload we already have isn't right, find the correct one
self.upload = uploads.find_by(model: model, path: paths) self.upload = model&.retrieve_upload(identifier, paths)
end end
super super
...@@ -48,7 +46,7 @@ module ObjectStorage ...@@ -48,7 +46,7 @@ module ObjectStorage
end end
def upload=(upload) def upload=(upload)
return unless upload return if upload.nil?
self.object_store = upload.store self.object_store = upload.store
super super
...@@ -157,9 +155,9 @@ module ObjectStorage ...@@ -157,9 +155,9 @@ module ObjectStorage
model_class.uploader_options.dig(mount_point, :mount_on) || mount_point model_class.uploader_options.dig(mount_point, :mount_on) || mount_point
end end
def workhorse_authorize def workhorse_authorize(has_length:, maximum_size: nil)
{ {
RemoteObject: workhorse_remote_upload_options, RemoteObject: workhorse_remote_upload_options(has_length: has_length, maximum_size: maximum_size),
TempPath: workhorse_local_upload_path TempPath: workhorse_local_upload_path
}.compact }.compact
end end
...@@ -168,23 +166,16 @@ module ObjectStorage ...@@ -168,23 +166,16 @@ module ObjectStorage
File.join(self.root, TMP_UPLOAD_PATH) File.join(self.root, TMP_UPLOAD_PATH)
end end
def workhorse_remote_upload_options def workhorse_remote_upload_options(has_length:, maximum_size: nil)
return unless self.object_store_enabled? return unless self.object_store_enabled?
return unless self.direct_upload_enabled? return unless self.direct_upload_enabled?
id = [CarrierWave.generate_cache_id, SecureRandom.hex].join('-') id = [CarrierWave.generate_cache_id, SecureRandom.hex].join('-')
upload_path = File.join(TMP_UPLOAD_PATH, id) upload_path = File.join(TMP_UPLOAD_PATH, id)
connection = ::Fog::Storage.new(self.object_store_credentials) direct_upload = ObjectStorage::DirectUpload.new(self.object_store_credentials, remote_store_path, upload_path,
expire_at = Time.now + DIRECT_UPLOAD_TIMEOUT + DIRECT_UPLOAD_EXPIRE_OFFSET has_length: has_length, maximum_size: maximum_size)
options = { 'Content-Type' => 'application/octet-stream' }
{ direct_upload.to_hash.merge(ID: id)
ID: id,
Timeout: DIRECT_UPLOAD_TIMEOUT,
GetURL: connection.get_object_url(remote_store_path, upload_path, expire_at),
DeleteURL: connection.delete_object_url(remote_store_path, upload_path, expire_at),
StoreURL: connection.put_object_url(remote_store_path, upload_path, expire_at, options)
}
end end
end end
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
.col-sm-10 .col-sm-10
- checkbox_name = 'application_setting[restricted_visibility_levels][]' - checkbox_name = 'application_setting[restricted_visibility_levels][]'
= hidden_field_tag(checkbox_name) = hidden_field_tag(checkbox_name)
- restricted_level_checkboxes('restricted-visibility-help', checkbox_name).each do |level| - restricted_level_checkboxes('restricted-visibility-help', checkbox_name, class: 'form-check-input').each do |level|
.form-check .form-check
= level = level
%span.form-text.text-muted#restricted-visibility-help %span.form-text.text-muted#restricted-visibility-help
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
= f.label :import_sources, class: 'col-form-label col-sm-2' = f.label :import_sources, class: 'col-form-label col-sm-2'
.col-sm-10 .col-sm-10
= hidden_field_tag 'application_setting[import_sources][]' = hidden_field_tag 'application_setting[import_sources][]'
- import_sources_checkboxes('import-sources-help').each do |source| - import_sources_checkboxes('import-sources-help', class: 'form-check-input').each do |source|
.form-check= source .form-check= source
%span.form-text.text-muted#import-sources-help %span.form-text.text-muted#import-sources-help
Enabled sources for code import during project creation. OmniAuth must be configured for GitHub Enabled sources for code import during project creation. OmniAuth must be configured for GitHub
......
%fieldset %fieldset
%legend Access %legend Access
.form-group .form-group.row
= f.label :projects_limit, class: 'col-form-label' = f.label :projects_limit, class: 'col-form-label col-sm-2'
.col-sm-10= f.number_field :projects_limit, min: 0, max: Gitlab::Database::MAX_INT_VALUE, class: 'form-control' .col-sm-10= f.number_field :projects_limit, min: 0, max: Gitlab::Database::MAX_INT_VALUE, class: 'form-control'
.form-group .form-group.row
= f.label :can_create_group, class: 'col-form-label' = f.label :can_create_group, class: 'col-form-label col-sm-2'
.col-sm-10= f.check_box :can_create_group .col-sm-10= f.check_box :can_create_group
.form-group .form-group.row
= f.label :access_level, class: 'col-form-label' = f.label :access_level, class: 'col-form-label col-sm-2'
.col-sm-10 .col-sm-10
- editing_current_user = (current_user == @user) - editing_current_user = (current_user == @user)
= f.radio_button :access_level, :regular, disabled: editing_current_user = f.radio_button :access_level, :regular, disabled: editing_current_user
= label_tag :regular do = label_tag :regular, class: 'font-weight-bold' do
Regular Regular
%p.light %p.light
Regular users have access to their groups and projects Regular users have access to their groups and projects
= f.radio_button :access_level, :admin, disabled: editing_current_user = f.radio_button :access_level, :admin, disabled: editing_current_user
= label_tag :admin do = label_tag :admin, class: 'font-weight-bold' do
Admin Admin
%p.light %p.light
Administrators have access to all groups, projects and users and can manage all features in this installation Administrators have access to all groups, projects and users and can manage all features in this installation
...@@ -28,8 +28,8 @@ ...@@ -28,8 +28,8 @@
%p.light %p.light
You cannot remove your own admin rights. You cannot remove your own admin rights.
.form-group .form-group.row
= f.label :external, class: 'col-form-label' = f.label :external, class: 'col-form-label col-sm-2'
.col-sm-10 .col-sm-10
= f.check_box :external do = f.check_box :external do
External External
......
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
= f.label :linkedin, class: 'col-form-label col-sm-2' = f.label :linkedin, class: 'col-form-label col-sm-2'
.col-sm-10= f.text_field :linkedin, class: 'form-control' .col-sm-10= f.text_field :linkedin, class: 'form-control'
.form-group.row .form-group.row
= f.label :twitter, class: 'col-form-label' = f.label :twitter, class: 'col-form-label col-sm-2'
.col-sm-10= f.text_field :twitter, class: 'form-control' .col-sm-10= f.text_field :twitter, class: 'form-control'
.form-group.row .form-group.row
= f.label :website_url, 'Website', class: 'col-form-label col-sm-2' = f.label :website_url, 'Website', class: 'col-form-label col-sm-2'
......
...@@ -12,11 +12,11 @@ ...@@ -12,11 +12,11 @@
= form_tag personal_access_token_import_gitea_path do = form_tag personal_access_token_import_gitea_path do
.form-group.row .form-group.row
= label_tag :gitea_host_url, 'Gitea Host URL', class: 'col-form-label col-sm-8' = label_tag :gitea_host_url, 'Gitea Host URL', class: 'col-form-label col-sm-2'
.col-sm-4 .col-sm-4
= text_field_tag :gitea_host_url, nil, placeholder: 'https://try.gitea.io', class: 'form-control' = text_field_tag :gitea_host_url, nil, placeholder: 'https://try.gitea.io', class: 'form-control'
.form-group.row .form-group.row
= label_tag :personal_access_token, 'Personal Access Token', class: 'col-form-label col-sm-8' = label_tag :personal_access_token, 'Personal Access Token', class: 'col-form-label col-sm-2'
.col-sm-4 .col-sm-4
= text_field_tag :personal_access_token, nil, class: 'form-control' = text_field_tag :personal_access_token, nil, class: 'form-control'
.form-actions .form-actions
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
= form_tag personal_access_token_import_github_path, method: :post, class: 'form-inline' do = form_tag personal_access_token_import_github_path, method: :post, class: 'form-inline' do
.form-group .form-group
= text_field_tag :personal_access_token, '', class: 'form-control', placeholder: _('Personal Access Token'), size: 40 = text_field_tag :personal_access_token, '', class: 'form-control append-right-8', placeholder: _('Personal Access Token'), size: 40
= submit_tag _('List your GitHub repositories'), class: 'btn btn-success' = submit_tag _('List your GitHub repositories'), class: 'btn btn-success'
- unless github_import_configured? - unless github_import_configured?
......
...@@ -14,9 +14,9 @@ ...@@ -14,9 +14,9 @@
%div{ class: "#{container_class} limit-container-width" } %div{ class: "#{container_class} limit-container-width" }
.content{ id: "content-body" } .content{ id: "content-body" }
.panel.panel-default .card
.panel-heading .card-header
.title .card-title
= brand_header_logo = brand_header_logo
- logo_text = brand_header_logo_type - logo_text = brand_header_logo_type
- if logo_text.present? - if logo_text.present?
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
= form_for @user, url: profile_preferences_path, remote: true, method: :put, html: { class: 'row prepend-top-default js-preferences-form' } do |f| = form_for @user, url: profile_preferences_path, remote: true, method: :put, html: { class: 'row prepend-top-default js-preferences-form' } do |f|
.col-lg-4.application-theme .col-lg-4.application-theme
%h4.prepend-top-0 %h4.prepend-top-0
s_('Preferences|Navigation theme') = s_('Preferences|Navigation theme')
%p Customize the appearance of the application header and navigation sidebar. %p Customize the appearance of the application header and navigation sidebar.
.col-lg-8.application-theme .col-lg-8.application-theme
- Gitlab::Themes.each do |theme| - Gitlab::Themes.each do |theme|
......
...@@ -42,6 +42,10 @@ ...@@ -42,6 +42,10 @@
.project-clone-holder .project-clone-holder
= render "shared/clone_panel" = render "shared/clone_panel"
- if show_xcode_link?(@project)
.project-action-button.project-xcode.inline
= render "projects/buttons/xcode_link"
- if current_user - if current_user
- if can?(current_user, :download_code, @project) - if can?(current_user, :download_code, @project)
= render 'projects/buttons/download', project: @project, ref: @ref = render 'projects/buttons/download', project: @project, ref: @ref
......
.file-content.blob_file.blob-no-preview .file-content.blob_file.blob-no-preview
.center.render-error.vertical-center .center.render-error
= link_to blob_raw_path do = link_to blob_raw_path do
%h1.light %h1.light
= sprite_icon('download') = sprite_icon('download')
......
%a.btn.btn-default{ href: xcode_uri_to_repo(@project) }
= _("Open in Xcode")
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
-# Only show it in the first page -# Only show it in the first page
- hide = @available_labels.empty? || (params[:page].present? && params[:page] != '1') - hide = @available_labels.empty? || (params[:page].present? && params[:page] != '1')
.prioritized-labels{ class: ('hide' if hide) } .prioritized-labels{ class: ('hide' if hide) }
%h5 Prioritized Labels %h5.prepend-top-10 Prioritized Labels
%ul.content-list.manage-labels-list.js-prioritized-labels{ "data-url" => set_priorities_project_labels_path(@project) } %ul.content-list.manage-labels-list.js-prioritized-labels{ "data-url" => set_priorities_project_labels_path(@project) }
#js-priority-labels-empty-state{ class: "#{'hidden' unless @prioritized_labels.empty?}" } #js-priority-labels-empty-state{ class: "#{'hidden' unless @prioritized_labels.empty?}" }
= render 'shared/empty_states/priority_labels' = render 'shared/empty_states/priority_labels'
......
...@@ -29,16 +29,16 @@ ...@@ -29,16 +29,16 @@
.col-lg-9.js-toggle-container .col-lg-9.js-toggle-container
%ul.nav.nav-tabs.nav-links.gitlab-tabs{ role: 'tablist' } %ul.nav.nav-tabs.nav-links.gitlab-tabs{ role: 'tablist' }
%li{ class: active_when(active_tab == 'blank'), role: 'presentation' } %li.nav-item{ role: 'presentation' }
%a{ href: '#blank-project-pane', id: 'blank-project-tab', data: { toggle: 'tab' }, role: 'tab' } %a.nav-link.active{ href: '#blank-project-pane', id: 'blank-project-tab', data: { toggle: 'tab' }, role: 'tab' }
%span.d-none.d-sm-block Blank project %span.d-none.d-sm-block Blank project
%span.d-block.d-sm-none Blank %span.d-block.d-sm-none Blank
%li{ class: active_when(active_tab == 'template'), role: 'presentation' } %li.nav-item{ role: 'presentation' }
%a{ href: '#create-from-template-pane', id: 'create-from-template-tab', data: { toggle: 'tab' }, role: 'tab' } %a.nav-link{ href: '#create-from-template-pane', id: 'create-from-template-tab', data: { toggle: 'tab' }, role: 'tab' }
%span.d-none.d-sm-block Create from template %span.d-none.d-sm-block Create from template
%span.d-block.d-sm-none Template %span.d-block.d-sm-none Template
%li{ class: active_when(active_tab == 'import'), role: 'presentation' } %li.nav-item{ role: 'presentation' }
%a{ href: '#import-project-pane', id: 'import-project-tab', data: { toggle: 'tab' }, role: 'tab' } %a.nav-link{ href: '#import-project-pane', id: 'import-project-tab', data: { toggle: 'tab' }, role: 'tab' }
%span.d-none.d-sm-block Import project %span.d-none.d-sm-block Import project
%span.d-block.d-sm-none Import %span.d-block.d-sm-none Import
......
- file_name, blob = blob - project = find_project_for_result_blob(blob)
.blob-result - file_name, blob = parse_search_result(blob)
.file-holder - blob_link = project_blob_path(project, tree_join(blob.ref, file_name))
.js-file-title.file-title
- ref = @search_results.repository_ref = render partial: 'search/results/blob_data', locals: { blob: blob, project: project, file_name: file_name, blob_link: blob_link }
- blob_link = project_blob_path(@project, tree_join(ref, file_name))
= link_to blob_link do
%i.fa.fa-file
%strong
= file_name
- if blob
.file-content.code.term
= render 'shared/file_highlight', blob: blob, first_line_number: blob.startline, blob_link: blob_link
.blob-result
.file-holder
.js-file-title.file-title
= link_to blob_link do
%i.fa.fa-file
= search_blob_title(project, file_name)
- if blob.data
.file-content.code.term
= render 'shared/file_highlight', blob: blob, first_line_number: blob.startline
- wiki_blob = parse_search_result(wiki_blob) - project = find_project_for_result_blob(wiki_blob)
.blob-result - file_name, wiki_blob = parse_search_result(wiki_blob)
.file-holder - wiki_blob_link = project_wiki_path(project, wiki_blob.basename)
.js-file-title.file-title
= link_to project_wiki_path(@project, wiki_blob.basename) do = render partial: 'search/results/blob_data', locals: { blob: wiki_blob, project: project, file_name: file_name, blob_link: wiki_blob_link }
%i.fa.fa-file
%strong
= wiki_blob.basename
.file-content.code.term
= render 'shared/file_highlight', blob: wiki_blob, first_line_number: wiki_blob.startline
- with_label = local_assigns.fetch(:with_label, true) - with_label = local_assigns.fetch(:with_label, true)
.form-group.visibility-level-setting .form-group.row.visibility-level-setting
- if with_label - if with_label
= f.label :visibility_level, class: 'col-form-label col-sm-2' do = f.label :visibility_level, class: 'col-form-label col-sm-2' do
Visibility Level Visibility Level
= link_to icon('question-circle'), help_page_path("public_access/public_access") = link_to icon('question-circle'), help_page_path("public_access/public_access")
%div{ :class => ("col-sm-10" if with_label) } %div{ :class => (with_label ? "col-sm-10" : "col-sm-12") }
- if can_change_visibility_level - if can_change_visibility_level
= render('shared/visibility_radios', model_method: :visibility_level, form: f, selected_level: visibility_level, form_model: form_model) = render('shared/visibility_radios', model_method: :visibility_level, form: f, selected_level: visibility_level, form_model: form_model)
- else - else
......
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
= _('Contribution') = _('Contribution')
.col-sm-10 .col-sm-10
.form-check .form-check
= form.check_box :allow_maintainer_to_push, disabled: !issuable.can_allow_maintainer_to_push?(current_user), class: 'form-check-input' = form.check_box :allow_collaboration, disabled: !issuable.can_allow_collaboration?(current_user), class: 'form-check-input'
= form.label :allow_maintainer_to_push, class: 'form-check-label' do = form.label :allow_collaboration, class: 'form-check-label' do
= _('Allow edits from maintainers.') = _('Allow commits from members who can merge to the target branch.')
= link_to 'About this feature', help_page_path('user/project/merge_requests/maintainer_access') = link_to 'About this feature', help_page_path('user/project/merge_requests/allow_collaboration')
.form-text.text-muted .form-text.text-muted
= allow_maintainer_push_unavailable_reason(issuable) = allow_collaboration_unavailable_reason(issuable)
...@@ -15,15 +15,15 @@ ...@@ -15,15 +15,15 @@
- else - else
= render "shared/issuable/form/metadata_merge_request_assignee", issuable: issuable, form: form, has_due_date: has_due_date = render "shared/issuable/form/metadata_merge_request_assignee", issuable: issuable, form: form, has_due_date: has_due_date
.form-group.row.issue-milestone .form-group.row.issue-milestone
= form.label :milestone_id, "Milestone", class: "col-form-label #{has_due_date ? "col-md-2 col-lg-4" : "col-2"}" = form.label :milestone_id, "Milestone", class: "col-form-label #{has_due_date ? "col-md-2 col-lg-4" : "col-sm-2"}"
.col-10{ class: ("col-md-8" if has_due_date) } .col-sm-10{ class: ("col-md-8" if has_due_date) }
.issuable-form-select-holder .issuable-form-select-holder
= render "shared/issuable/milestone_dropdown", selected: issuable.milestone, name: "#{issuable.class.model_name.param_key}[milestone_id]", show_any: false, show_upcoming: false, show_started: false, extra_class: "js-issuable-form-dropdown js-dropdown-keep-input", dropdown_title: "Select milestone" = render "shared/issuable/milestone_dropdown", selected: issuable.milestone, name: "#{issuable.class.model_name.param_key}[milestone_id]", show_any: false, show_upcoming: false, show_started: false, extra_class: "js-issuable-form-dropdown js-dropdown-keep-input", dropdown_title: "Select milestone"
.form-group.row .form-group.row
- has_labels = @labels && @labels.any? - has_labels = @labels && @labels.any?
= form.label :label_ids, "Labels", class: "col-form-label #{has_due_date ? "col-md-2 col-lg-4" : "col-2"}" = form.label :label_ids, "Labels", class: "col-form-label #{has_due_date ? "col-md-2 col-lg-4" : "col-sm-2"}"
= form.hidden_field :label_ids, multiple: true, value: '' = form.hidden_field :label_ids, multiple: true, value: ''
.col-10{ class: "#{"col-md-8" if has_due_date} #{'issuable-form-padding-top' if !has_labels}" } .col-sm-10{ class: "#{"col-md-8" if has_due_date} #{'issuable-form-padding-top' if !has_labels}" }
.issuable-form-select-holder .issuable-form-select-holder
= render "shared/issuable/label_dropdown", classes: ["js-issuable-form-dropdown"], selected: issuable.labels, data_options: { field_name: "#{issuable.class.model_name.param_key}[label_ids][]", show_any: false}, dropdown_title: "Select label" = render "shared/issuable/label_dropdown", classes: ["js-issuable-form-dropdown"], selected: issuable.labels, data_options: { field_name: "#{issuable.class.model_name.param_key}[label_ids][]", show_any: false}, dropdown_title: "Select label"
- if has_due_date - if has_due_date
......
- unless can?(current_user, :push_code, @project) - unless can?(current_user, :push_code, @project)
.inline.prepend-left-10 .inline.prepend-left-10
- if @project.branch_allows_maintainer_push?(current_user, selected_branch) - if @project.branch_allows_collaboration?(current_user, selected_branch)
= commit_in_single_accessible_branch = commit_in_single_accessible_branch
- else - else
= commit_in_fork_help = commit_in_fork_help
- redirect_params = { redirect: @redirect } if @redirect - redirect_params = { redirect: @redirect } if @redirect
.panel-content.rendered-terms .card-body.rendered-terms
= markdown_field(@term, :terms) = markdown_field(@term, :terms)
.row-content-block.footer-block.clearfix .card-footer.footer-block.clearfix
- if can?(current_user, :accept_terms, @term) - if can?(current_user, :accept_terms, @term)
.float-right .float-right
= button_to accept_term_path(@term, redirect_params), class: 'btn btn-success prepend-left-8' do = button_to accept_term_path(@term, redirect_params), class: 'btn btn-success prepend-left-8' do
......
---
title: Include milestones from parent groups when assigning a milestone to an issue or merge request
merge_request:
author:
type: changed
---
title: Rephrasing Merge Request's 'allow edits from maintainer' functionality
merge_request: 19061
author:
type: deprecated
---
title: Add Open in Xcode link for xcode repositories
merge_request:
author:
type: added
---
title: Check for nil AutoDevOps when saving project CI/CD settings.
merge_request: 19190
author:
type: fixed
---
title: Update email_spec to 2.2.0
merge_request: 19164
author: Takuya Noguchi
type: other
---
title: Update selenium-webdriver to 3.12.0
merge_request: 19351
author: Takuya Noguchi
type: other
---
title: Add background migrations for archiving legacy job traces
merge_request: 19194
author:
type: performance
---
title: Include username in output when testing SSH to GitLab
merge_request: 19358
author:
type: other
---
title: Fix an N+1 when loading user avatars
merge_request:
author:
type: performance
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment