Commit 6c712667 authored by Shinya Maeda's avatar Shinya Maeda

Merge branch 'refactor-clusters' into move-kubernetes-from-service-to-clusters-page-10-2-ver

parents a0f7819f eba27fe0
image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3.5-golang-1.8-git-2.13-phantomjs-2.1-node-8.x-yarn-1.0-postgresql-9.6" image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3.5-golang-1.8-git-2.13-chrome-62.0-node-8.x-yarn-1.2-postgresql-9.6"
.default-cache: &default-cache .default-cache: &default-cache
key: "ruby-235-with-yarn" key: "ruby-235-with-yarn"
...@@ -23,7 +23,6 @@ variables: ...@@ -23,7 +23,6 @@ variables:
SIMPLECOV: "true" SIMPLECOV: "true"
GIT_DEPTH: "20" GIT_DEPTH: "20"
GIT_SUBMODULE_STRATEGY: "none" GIT_SUBMODULE_STRATEGY: "none"
PHANTOMJS_VERSION: "2.1.1"
GET_SOURCES_ATTEMPTS: "3" GET_SOURCES_ATTEMPTS: "3"
KNAPSACK_RSPEC_SUITE_REPORT_PATH: knapsack/${CI_PROJECT_NAME}/rspec_report-master.json KNAPSACK_RSPEC_SUITE_REPORT_PATH: knapsack/${CI_PROJECT_NAME}/rspec_report-master.json
KNAPSACK_SPINACH_SUITE_REPORT_PATH: knapsack/${CI_PROJECT_NAME}/spinach_report-master.json KNAPSACK_SPINACH_SUITE_REPORT_PATH: knapsack/${CI_PROJECT_NAME}/spinach_report-master.json
...@@ -455,7 +454,7 @@ db:migrate:reset-mysql: ...@@ -455,7 +454,7 @@ db:migrate:reset-mysql:
variables: variables:
SETUP_DB: "false" SETUP_DB: "false"
script: script:
- git fetch origin v9.3.0 - git fetch https://gitlab.com/gitlab-org/gitlab-ce.git v9.3.0
- git checkout -f FETCH_HEAD - git checkout -f FETCH_HEAD
- bundle install $BUNDLE_INSTALL_FLAGS - bundle install $BUNDLE_INSTALL_FLAGS
- cp config/gitlab.yml.example config/gitlab.yml - cp config/gitlab.yml.example config/gitlab.yml
...@@ -551,7 +550,6 @@ karma: ...@@ -551,7 +550,6 @@ karma:
<<: *dedicated-runner <<: *dedicated-runner
<<: *except-docs <<: *except-docs
<<: *pull-cache <<: *pull-cache
image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3.5-golang-1.8-git-2.13-chrome-61.0-node-8.x-yarn-1.0-postgresql-9.6"
stage: test stage: test
variables: variables:
BABEL_ENV: "coverage" BABEL_ENV: "coverage"
......
...@@ -112,7 +112,7 @@ linters: ...@@ -112,7 +112,7 @@ linters:
# Reports when you define the same selector twice in a single sheet. # Reports when you define the same selector twice in a single sheet.
MergeableSelector: MergeableSelector:
enabled: false enabled: true
# Functions, mixins, variables, and placeholders should be declared # Functions, mixins, variables, and placeholders should be declared
# with all lowercase letters and hyphens instead of underscores. # with all lowercase letters and hyphens instead of underscores.
......
...@@ -2,6 +2,30 @@ ...@@ -2,6 +2,30 @@
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.1.1 (2017-10-31)
- [FIXED] Auto Devops kubernetes default namespace is now correctly built out of gitlab project group-name. !14642 (Mircea Danila Dumitrescu)
- [FIXED] Forbid the usage of `Redis#keys`. !14889
- [FIXED] Make the circuitbreaker more robust by adding higher thresholds, and multiple access attempts. !14933
- [FIXED] Only cache last push event for existing projects when pushing to a fork. !14989
- [FIXED] Fix bug preventing secondary emails from being confirmed. !15010
- [FIXED] Fix broken wiki pages that link to a wiki file. !15019
- [FIXED] Don't rename paths that were freed up when upgrading. !15029
- [FIXED] Fix bitbucket login. !15051
- [FIXED] Update gitaly in Gitlab 10.1 to 0.43.1 for temp file cleanup. !15055
- [FIXED] Use the correct visibility attribute for projects in system hooks. !15065
- [FIXED] Normalize LDAP DN when looking up identity.
- [FIXED] Adds callback functions for initial request in clusters page.
- [FIXED] Fix missing Import/Export issue assignees.
- [FIXED] Allow boards as top level route.
- [FIXED] Fix widget of locked merge requests not being presented.
- [FIXED] Fix editing issue description in mobile view.
- [FIXED] Fix deletion of container registry or images returning an error.
- [FIXED] Fix the writing of invalid environment refs.
- [CHANGED] Store circuitbreaker settings in the database instead of config. !14842
- [CHANGED] Update default disabled merge request widget message to reflect a general failure. !14960
- [PERFORMANCE] Stop merge requests with thousands of commits from timing out. !15063
## 10.1.0 (2017-10-22) ## 10.1.0 (2017-10-22)
- [SECURITY] Use a timeout on certain git operations. !14872 - [SECURITY] Use a timeout on certain git operations. !14872
...@@ -194,6 +218,24 @@ entry. ...@@ -194,6 +218,24 @@ entry.
- creation of keys moved to services. !13331 (haseebeqx) - creation of keys moved to services. !13331 (haseebeqx)
- Add username as GL_USERNAME in hooks. - Add username as GL_USERNAME in hooks.
## 10.0.5 (2017-11-03)
- [FIXED] Fix incorrect X-axis labels in Prometheus graphs. !14258
- [FIXED] Fix `rake gitlab:incoming_email:check` and make it report the actual error. !14423
- [FIXED] Does not check if an invariant hashed storage path exists on disk when renaming projects. !14428
- [FIXED] Fix bottom spacing for dropdowns that open upwards. !14535
- [FIXED] Fix the project import with issues and milestones. !14657
- [FIXED] Fix broken Y-axis scaling in some Prometheus graphs. !14693
- [FIXED] Fixed duplicate notifications when added multiple labels on an issue. !14798
- [FIXED] Don't rename paths that were freed up when upgrading. !15029
- [FIXED] Fixed issue/merge request breadcrumb titles not having links.
- [FIXED] Fix application setting to cache nil object.
- [FIXED] Fix missing Import/Export issue assignees.
- [FIXED] Allow boards as top level route.
- [FIXED] Fixed milestone breadcrumb links.
- [FIXED] Fixed merge request widget merged & closed date tooltip text.
- [FIXED] fix merge request widget status icon for failed CI.
## 10.0.4 (2017-10-16) ## 10.0.4 (2017-10-16)
- [SECURITY] Move project repositories between namespaces when renaming users. - [SECURITY] Move project repositories between namespaces when renaming users.
......
...@@ -324,9 +324,9 @@ group :development, :test do ...@@ -324,9 +324,9 @@ group :development, :test do
# Generate Fake data # Generate Fake data
gem 'ffaker', '~> 2.4' gem 'ffaker', '~> 2.4'
gem 'capybara', '~> 2.15.0' gem 'capybara', '~> 2.15'
gem 'capybara-screenshot', '~> 1.0.0' gem 'capybara-screenshot', '~> 1.0.0'
gem 'poltergeist', '~> 1.9.0' gem 'selenium-webdriver', '~> 3.5'
gem 'spring', '~> 2.0.0' gem 'spring', '~> 2.0.0'
gem 'spring-commands-rspec', '~> 1.0.4' gem 'spring-commands-rspec', '~> 1.0.4'
......
...@@ -113,12 +113,13 @@ GEM ...@@ -113,12 +113,13 @@ GEM
mime-types (>= 1.16) mime-types (>= 1.16)
cause (0.1) cause (0.1)
charlock_holmes (0.7.5) charlock_holmes (0.7.5)
childprocess (0.7.0)
ffi (~> 1.0, >= 1.0.11)
chronic (0.10.2) chronic (0.10.2)
chronic_duration (0.10.6) chronic_duration (0.10.6)
numerizer (~> 0.1.1) numerizer (~> 0.1.1)
chunky_png (1.3.5) chunky_png (1.3.5)
citrus (3.0.2) citrus (3.0.2)
cliver (0.3.2)
coderay (1.1.1) coderay (1.1.1)
coercible (1.0.0) coercible (1.0.0)
descendants_tracker (~> 0.0.1) descendants_tracker (~> 0.0.1)
...@@ -604,11 +605,6 @@ GEM ...@@ -604,11 +605,6 @@ GEM
pg (0.18.4) pg (0.18.4)
po_to_json (1.0.1) po_to_json (1.0.1)
json (>= 1.6.0) json (>= 1.6.0)
poltergeist (1.9.0)
capybara (~> 2.1)
cliver (~> 0.3.1)
multi_json (~> 1.0)
websocket-driver (>= 0.2.0)
posix-spawn (0.3.13) posix-spawn (0.3.13)
powerpack (0.1.1) powerpack (0.1.1)
premailer (1.10.4) premailer (1.10.4)
...@@ -818,6 +814,9 @@ GEM ...@@ -818,6 +814,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)
childprocess (~> 0.5)
rubyzip (~> 1.0)
sentry-raven (2.5.3) sentry-raven (2.5.3)
faraday (>= 0.7.6, < 1.0) faraday (>= 0.7.6, < 1.0)
settingslogic (2.0.9) settingslogic (2.0.9)
...@@ -949,9 +948,6 @@ GEM ...@@ -949,9 +948,6 @@ GEM
hashdiff hashdiff
webpack-rails (0.9.10) webpack-rails (0.9.10)
railties (>= 3.2.0) railties (>= 3.2.0)
websocket-driver (0.6.3)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.2)
wikicloth (0.8.1) wikicloth (0.8.1)
builder builder
expression_parser expression_parser
...@@ -988,7 +984,7 @@ DEPENDENCIES ...@@ -988,7 +984,7 @@ DEPENDENCIES
browser (~> 2.2) browser (~> 2.2)
bullet (~> 5.5.0) bullet (~> 5.5.0)
bundler-audit (~> 0.5.0) bundler-audit (~> 0.5.0)
capybara (~> 2.15.0) capybara (~> 2.15)
capybara-screenshot (~> 1.0.0) capybara-screenshot (~> 1.0.0)
carrierwave (~> 1.2) carrierwave (~> 1.2)
charlock_holmes (~> 0.7.5) charlock_holmes (~> 0.7.5)
...@@ -1104,7 +1100,6 @@ DEPENDENCIES ...@@ -1104,7 +1100,6 @@ DEPENDENCIES
peek-redis (~> 1.2.0) peek-redis (~> 1.2.0)
peek-sidekiq (~> 1.0.3) peek-sidekiq (~> 1.0.3)
pg (~> 0.18.2) pg (~> 0.18.2)
poltergeist (~> 1.9.0)
premailer-rails (~> 1.9.7) premailer-rails (~> 1.9.7)
prometheus-client-mmap (~> 0.7.0.beta18) prometheus-client-mmap (~> 0.7.0.beta18)
pry-byebug (~> 3.4.1) pry-byebug (~> 3.4.1)
...@@ -1150,6 +1145,7 @@ DEPENDENCIES ...@@ -1150,6 +1145,7 @@ DEPENDENCIES
scss_lint (~> 0.54.0) scss_lint (~> 0.54.0)
seed-fu (~> 2.3.5) seed-fu (~> 2.3.5)
select2-rails (~> 3.5.9) select2-rails (~> 3.5.9)
selenium-webdriver (~> 3.5)
sentry-raven (~> 2.5.3) sentry-raven (~> 2.5.3)
settingslogic (~> 2.0.9) settingslogic (~> 2.0.9)
sham_rack (~> 1.3.6) sham_rack (~> 1.3.6)
......
...@@ -79,8 +79,6 @@ const Filter = { ...@@ -79,8 +79,6 @@ const Filter = {
this.hook.trigger.addEventListener('keydown.dl', this.eventWrapper.debounceKeydown); this.hook.trigger.addEventListener('keydown.dl', this.eventWrapper.debounceKeydown);
this.hook.trigger.addEventListener('mousedown.dl', this.eventWrapper.debounceKeydown); this.hook.trigger.addEventListener('mousedown.dl', this.eventWrapper.debounceKeydown);
this.debounceKeydown({ detail: { hook: this.hook } });
}, },
destroy: function destroy() { destroy: function destroy() {
......
import 'core-js/es6/map'; import 'core-js/es6/map';
import 'core-js/es6/set'; import 'core-js/es6/set';
import simulateDrag from './simulate_drag'; import simulateDrag from './simulate_drag';
import simulateInput from './simulate_input';
// Export to global space for rspec to use // Export to global space for rspec to use
window.simulateDrag = simulateDrag; window.simulateDrag = simulateDrag;
window.simulateInput = simulateInput;
function triggerEvents(input) {
input.dispatchEvent(new Event('keydown'));
input.dispatchEvent(new Event('keypress'));
input.dispatchEvent(new Event('input'));
input.dispatchEvent(new Event('keyup'));
}
export default function simulateInput(target, text) {
const input = document.querySelector(target);
if (!input || !input.matches('textarea, input')) {
return false;
}
if (text.length > 0) {
Array.prototype.forEach.call(text, (char) => {
input.value += char;
triggerEvents(input);
});
} else {
triggerEvents(input);
}
return true;
}
...@@ -40,6 +40,10 @@ ...@@ -40,6 +40,10 @@
&.top-block { &.top-block {
border-top: none; border-top: none;
.container-fluid {
background-color: inherit;
}
} }
&.middle-block { &.middle-block {
...@@ -98,10 +102,6 @@ ...@@ -98,10 +102,6 @@
background-color: $white-light; background-color: $white-light;
border-top: none; border-top: none;
} }
&.top-block .container-fluid {
background-color: inherit;
}
} }
.sub-header-block { .sub-header-block {
......
...@@ -12,15 +12,15 @@ ...@@ -12,15 +12,15 @@
border-left: 3px solid $border-color; border-left: 3px solid $border-color;
color: $text-color; color: $text-color;
background: $gray-light; background: $gray-light;
}
.bs-callout h4 { h4 {
margin-top: 0; margin-top: 0;
margin-bottom: 5px; margin-bottom: 5px;
} }
.bs-callout p:last-child { p:last-child {
margin-bottom: 0; margin-bottom: 0;
}
} }
/* Variations */ /* Variations */
......
...@@ -53,6 +53,14 @@ hr { ...@@ -53,6 +53,14 @@ hr {
.str-truncated { .str-truncated {
@include str-truncated; @include str-truncated;
&-60 {
@include str-truncated(60%);
}
&-100 {
@include str-truncated(100%);
}
} }
.block-truncated { .block-truncated {
...@@ -78,10 +86,17 @@ hr { ...@@ -78,10 +86,17 @@ hr {
font-size: 14px; font-size: 14px;
} }
table a code { table {
a code {
position: relative; position: relative;
top: -2px; top: -2px;
margin-right: 3px; margin-right: 3px;
}
td.permission-x {
background: $table-permission-x-bg !important;
text-align: center;
}
} }
.loading { .loading {
...@@ -266,13 +281,6 @@ img.emoji { ...@@ -266,13 +281,6 @@ img.emoji {
margin-bottom: 10px; margin-bottom: 10px;
} }
table {
td.permission-x {
background: $table-permission-x-bg !important;
text-align: center;
}
}
.btn-sign-in { .btn-sign-in {
text-shadow: none; text-shadow: none;
...@@ -338,10 +346,11 @@ table { ...@@ -338,10 +346,11 @@ table {
.dropzone .dz-preview .dz-progress { .dropzone .dz-preview .dz-progress {
border-color: $border-color !important; border-color: $border-color !important;
}
.dropzone .dz-preview .dz-progress .dz-upload { .dz-upload {
background: $gl-success !important; background: $gl-success !important;
}
} }
.dz-message { .dz-message {
...@@ -402,16 +411,6 @@ table { ...@@ -402,16 +411,6 @@ table {
border-radius: $border-radius-default; border-radius: $border-radius-default;
} }
.str-truncated {
&-60 {
@include str-truncated(60%);
}
&-100 {
@include str-truncated(100%);
}
}
.tooltip { .tooltip {
.tooltip-inner { .tooltip-inner {
word-wrap: break-word; word-wrap: break-word;
......
...@@ -141,17 +141,17 @@ ...@@ -141,17 +141,17 @@
svg { svg {
fill: $gl-text-color-secondary; fill: $gl-text-color-secondary;
} }
}
.nav-item-name { .nav-item-name {
flex: 1; flex: 1;
} }
li.active { &.active {
> a { > a {
font-weight: $gl-font-weight-bold; font-weight: $gl-font-weight-bold;
} }
} }
}
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
left: (-$contextual-sidebar-width); left: (-$contextual-sidebar-width);
...@@ -484,10 +484,7 @@ ...@@ -484,10 +484,7 @@
height: calc(100vh - #{$header-height}); height: calc(100vh - #{$header-height});
@media (min-width: $screen-sm-min) { @media (min-width: $screen-sm-min) {
height: 475px; // Needed for PhantomJS
// scss-lint:disable DuplicateProperty
height: calc(100vh - 180px); height: calc(100vh - 180px);
// scss-lint:enable DuplicateProperty
} }
} }
......
...@@ -727,11 +727,11 @@ ...@@ -727,11 +727,11 @@
.pika-single.animate-picker.is-bound { .pika-single.animate-picker.is-bound {
@include set-visible; @include set-visible;
}
.pika-single.animate-picker.is-bound.is-hidden { &.is-hidden {
@include set-invisible; @include set-invisible;
overflow: hidden; overflow: hidden;
}
} }
@mixin dropdown-item-hover { @mixin dropdown-item-hover {
...@@ -938,9 +938,7 @@ header.header-content .dropdown-menu.projects-dropdown-menu { ...@@ -938,9 +938,7 @@ header.header-content .dropdown-menu.projects-dropdown-menu {
border-right: 0; border-right: 0;
} }
} }
}
.projects-dropdown-container {
.projects-list-frequent-container, .projects-list-frequent-container,
.projects-list-search-container, { .projects-list-search-container, {
padding: 8px 0; padding: 8px 0;
...@@ -951,11 +949,6 @@ header.header-content .dropdown-menu.projects-dropdown-menu { ...@@ -951,11 +949,6 @@ header.header-content .dropdown-menu.projects-dropdown-menu {
.projects-list-frequent-container li.section-empty, .projects-list-frequent-container li.section-empty,
.projects-list-search-container li.section-empty { .projects-list-search-container li.section-empty {
padding: 0 15px; padding: 0 15px;
}
.section-header,
.projects-list-frequent-container li.section-empty,
.projects-list-search-container li.section-empty {
color: $gl-text-color-secondary; color: $gl-text-color-secondary;
font-size: $gl-font-size; font-size: $gl-font-size;
} }
......
...@@ -165,9 +165,8 @@ ...@@ -165,9 +165,8 @@
&:last-child { &:last-child {
border-right: none; border-right: none;
} }
}
td.blame-commit { &.blame-commit {
padding: 5px 10px; padding: 5px 10px;
min-width: 400px; min-width: 400px;
max-width: 400px; max-width: 400px;
...@@ -184,19 +183,7 @@ ...@@ -184,19 +183,7 @@
} }
} }
@for $i from 0 through 5 { &.line-numbers {
td.blame-commit-age-#{$i} {
border-left-color: mix($blame-cyan, $blame-blue, $i / 5.0 * 100%);
}
}
@for $i from 1 through 4 {
td.blame-commit-age-#{$i + 5} {
border-left-color: mix($blame-gray, $blame-cyan, $i / 4.0 * 100%);
}
}
td.line-numbers {
float: none; float: none;
border-left: 1px solid $blame-line-numbers-border; border-left: 1px solid $blame-line-numbers-border;
...@@ -206,11 +193,24 @@ ...@@ -206,11 +193,24 @@
} }
} }
td.lines { &.lines {
padding: 0; padding: 0;
} }
} }
@for $i from 0 through 5 {
td.blame-commit-age-#{$i} {
border-left-color: mix($blame-cyan, $blame-blue, $i / 5.0 * 100%);
}
}
@for $i from 1 through 4 {
td.blame-commit-age-#{$i + 5} {
border-left-color: mix($blame-gray, $blame-cyan, $i / 4.0 * 100%);
}
}
}
&.logs { &.logs {
background: $logs-bg; background: $logs-bg;
max-height: 700px; max-height: 700px;
......
...@@ -268,12 +268,6 @@ ...@@ -268,12 +268,6 @@
.filtered-search-box-input-container { .filtered-search-box-input-container {
flex: 1; flex: 1;
position: relative; position: relative;
// Fix PhantomJS not supporting `flex: 1;` properly.
// This is important because it can change the expected `e.target` when clicking things in tests.
// See https://gitlab.com/gitlab-org/gitlab-ce/blob/b54acba8b732688c59fe2f38510c469dc86ee499/spec/features/issues/filtered_search/visual_tokens_spec.rb#L61
// - With `width: 100%`: `e.target` = `.tokens-container`, https://i.imgur.com/jGq7wbx.png
// - Without `width: 100%`: `e.target` = `.filtered-search`, https://i.imgur.com/cNI2CyT.png
width: 100%;
min-width: 0; min-width: 0;
} }
...@@ -469,10 +463,10 @@ ...@@ -469,10 +463,10 @@
word-break: break-all; word-break: break-all;
} }
} }
}
.filter-dropdown-item.droplab-item-active .btn { &.droplab-item-active .btn {
@extend %filter-dropdown-item-btn-hover; @extend %filter-dropdown-item-btn-hover;
}
} }
.filter-dropdown-loading { .filter-dropdown-loading {
......
...@@ -352,7 +352,77 @@ ...@@ -352,7 +352,77 @@
.header-user .dropdown-menu-nav, .header-user .dropdown-menu-nav,
.header-new .dropdown-menu-nav { .header-new .dropdown-menu-nav {
margin-top: $dropdown-vertical-offset; margin-top: 4px;
}
.search {
margin: 4px 8px 0;
form {
height: 32px;
border: 0;
border-radius: $border-radius-default;
transition: border-color ease-in-out 0.15s, background-color ease-in-out 0.15s;
&:hover {
box-shadow: none;
}
}
.search-input {
color: $white-light;
background: none;
transition: color ease-in-out 0.15s;
}
.search-input::placeholder {
transition: color ease-in-out 0.15s;
}
.location-badge {
font-size: 12px;
margin: -4px 4px -4px -4px;
line-height: 25px;
padding: 4px 8px;
border-radius: 2px 0 0 2px;
height: 32px;
transition: border-color ease-in-out 0.15s;
}
&.search-active {
form {
background-color: rgba($indigo-200, .3);
box-shadow: none;
.search-input {
color: $gl-text-color;
transition: color ease-in-out 0.15s;
}
.search-input::placeholder {
color: $gl-text-color-tertiary;
}
.search-input-wrap {
.search-icon,
.clear-icon {
color: $gl-text-color-tertiary;
transition: color ease-in-out 0.15s;
}
}
}
.location-badge {
background-color: $nav-badge-bg;
border-color: $border-color;
}
.search-input-wrap {
.clear-icon {
color: $white-light;
}
}
}
} }
.breadcrumbs { .breadcrumbs {
......
...@@ -30,10 +30,10 @@ body { ...@@ -30,10 +30,10 @@ body {
.container { .container {
padding-top: 0; padding-top: 0;
z-index: 5; z-index: 5;
}
.container .content { .content {
margin: 0; margin: 0;
}
} }
.navless-container { .navless-container {
...@@ -82,26 +82,26 @@ body { ...@@ -82,26 +82,26 @@ body {
transition: background-color 0.15s, border-color 0.15s; transition: background-color 0.15s, border-color 0.15s;
background-color: $orange-500; background-color: $orange-500;
border-color: $orange-500; border-color: $orange-500;
&:only-of-type {
background-color: $orange-500;
border-color: $orange-500;
} }
.alert-warning + .alert-warning { + .alert-warning {
background-color: $orange-600; background-color: $orange-600;
border-color: $orange-600; border-color: $orange-600;
}
.alert-warning + .alert-warning + .alert-warning { + .alert-warning {
background-color: $orange-700; background-color: $orange-700;
border-color: $orange-700; border-color: $orange-700;
}
.alert-warning + .alert-warning + .alert-warning + .alert-warning { + .alert-warning {
background-color: $orange-800; background-color: $orange-800;
border-color: $orange-800; border-color: $orange-800;
} }
}
.alert-warning:only-of-type { }
background-color: $orange-500;
border-color: $orange-500;
} }
} }
......
...@@ -299,7 +299,8 @@ ul.indent-list { ...@@ -299,7 +299,8 @@ ul.indent-list {
} }
} }
.group-list-tree .avatar-container.content-loading { .group-list-tree {
.avatar-container.content-loading {
position: relative; position: relative;
> a, > a,
...@@ -310,15 +311,15 @@ ul.indent-list { ...@@ -310,15 +311,15 @@ ul.indent-list {
> a { > a {
padding: 2px; padding: 2px;
}
> a .avatar { .avatar {
border: 2px solid $white-normal; border: 2px solid $white-normal;
&.identicon { &.identicon {
line-height: 30px; line-height: 30px;
} }
} }
}
&::after { &::after {
content: ""; content: "";
...@@ -330,9 +331,8 @@ ul.indent-list { ...@@ -330,9 +331,8 @@ ul.indent-list {
border-radius: 50%; border-radius: 50%;
animation: spin-avatar 3s infinite linear; animation: spin-avatar 3s infinite linear;
} }
} }
.group-list-tree {
.folder-toggle-wrap { .folder-toggle-wrap {
float: left; float: left;
line-height: $list-text-height; line-height: $list-text-height;
......
...@@ -173,21 +173,8 @@ ...@@ -173,21 +173,8 @@
ul > li { ul > li {
white-space: nowrap; white-space: nowrap;
} }
}
@media(max-width: $screen-xs-max) {
.atwho-view-ul {
width: 350px;
}
.atwho-view ul li {
overflow: hidden;
text-overflow: ellipsis;
}
}
// TODO: fallback to global style // TODO: fallback to global style
.atwho-view {
.atwho-view-ul { .atwho-view-ul {
padding: 8px 1px; padding: 8px 1px;
...@@ -220,3 +207,14 @@ ...@@ -220,3 +207,14 @@
} }
} }
} }
@media(max-width: $screen-xs-max) {
.atwho-view-ul {
width: 350px;
}
.atwho-view ul li {
overflow: hidden;
text-overflow: ellipsis;
}
}
...@@ -25,8 +25,11 @@ ...@@ -25,8 +25,11 @@
margin: 0; margin: 0;
padding: $gl-padding 0; padding: $gl-padding 0;
border: none; border: none;
&:not(:last-child) {
border-bottom: 1px solid $white-normal; border-bottom: 1px solid $white-normal;
} }
}
} }
.gl-responsive-table-row-col-span { .gl-responsive-table-row-col-span {
......
...@@ -340,11 +340,64 @@ ...@@ -340,11 +340,64 @@
} }
} }
.project-item-select-holder.btn-group { .page-with-layout-nav {
.right-sidebar {
top: ($header-height + 1) * 2;
}
&.page-with-sub-nav {
.right-sidebar {
top: ($header-height + 1) * 3;
&.affix {
top: $header-height;
}
}
}
}
.with-performance-bar .page-with-layout-nav {
.right-sidebar {
top: ($header-height + 1) * 2 + $performance-bar-height;
}
&.page-with-sub-nav {
.right-sidebar {
top: ($header-height + 1) * 3 + $performance-bar-height;
&.affix {
top: $header-height + $performance-bar-height;
}
}
}
}
@media (max-width: $screen-xs-max) {
.top-area {
flex-flow: row wrap;
.nav-controls {
$controls-margin: $btn-xs-side-margin - 2px;
flex: 0 0 100%;
&.controls-flex {
display: flex; display: flex;
max-width: 350px; flex-flow: row wrap;
overflow: hidden; align-items: center;
float: right; justify-content: center;
padding: 0 0 $gl-padding-top;
}
.controls-item,
.controls-item-full,
.controls-item:last-child {
flex: 1 1 35%;
display: block;
width: 100%;
margin: $controls-margin;
}
}
}
.new-project-item-link { .new-project-item-link {
white-space: nowrap; white-space: nowrap;
......
...@@ -60,22 +60,12 @@ ...@@ -60,22 +60,12 @@
border-radius: $border-radius-base; border-radius: $border-radius-base;
border: 1px solid $dropdown-border-color; border: 1px solid $dropdown-border-color;
min-width: 175px; min-width: 175px;
color: $gl-text-color; color: $gl-grayish-blue;
z-index: 999;
}
.select2-drop-mask {
z-index: 998;
} }
.select2-drop.select2-drop-above.select2-drop-active { .select2-results .select2-result-label,
border-top: 1px solid $dropdown-border-color; .select2-more-results {
margin-top: -6px; padding: 10px 15px;
}
.select2-results li.select2-result-with-children > .select2-result-label {
font-weight: $gl-font-weight-bold;
color: $gl-text-color;
} }
.select2-container-active { .select2-container-active {
...@@ -144,9 +134,8 @@ ...@@ -144,9 +134,8 @@
.select2-drop-auto-width & { .select2-drop-auto-width & {
padding: 15px 15px 5px; padding: 15px 15px 5px;
} }
}
.select2-search input { input {
padding: 2px 25px 2px 5px; padding: 2px 25px 2px 5px;
background: $white-light image-url('select2.png'); background: $white-light image-url('select2.png');
background-repeat: no-repeat; background-repeat: no-repeat;
...@@ -158,44 +147,33 @@ ...@@ -158,44 +147,33 @@
&:focus { &:focus {
border-color: $input-border-focus; border-color: $input-border-focus;
} }
}
.select2-search input.select2-active { &.select2-active {
background-color: $white-light; background-color: $white-light;
background-image: image-url('select2-spinner.gif') !important; background-image: image-url('select2-spinner.gif') !important;
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: right 5px center !important; background-position: right 5px center !important;
background-size: 16px 16px !important; background-size: 16px 16px !important;
}
}
}
.select2-results .select2-no-results,
.select2-results .select2-searching,
.select2-results .select2-ajax-error,
.select2-results .select2-selection-limit {
background: $gray-light;
display: list-item;
padding: 10px 15px;
} }
.select2-results { .select2-results {
margin: 0; margin: 0;
padding: #{$gl-padding / 2} 0; padding: 10px 0;
.select2-no-results,
.select2-searching,
.select2-ajax-error,
.select2-selection-limit {
background: transparent;
padding: #{$gl-padding / 2} $gl-padding;
}
.select2-result-label, li.select2-result-with-children > .select2-result-label {
.select2-more-results { font-weight: $gl-font-weight-bold;
padding: #{$gl-padding / 2} $gl-padding;
}
.select2-highlighted {
background: transparent;
color: $gl-text-color; color: $gl-text-color;
.select2-result-label {
background: $dropdown-item-hover-bg;
}
}
.select2-result {
padding: 0 1px;
} }
} }
...@@ -212,6 +190,8 @@ ...@@ -212,6 +190,8 @@
} }
.select2-highlighted { .select2-highlighted {
background: $gl-link-color !important;
.group-result { .group-result {
.group-path { .group-path {
color: $white-light; color: $white-light;
......
...@@ -217,13 +217,31 @@ $white-gc-bg: #eaf2f5; ...@@ -217,13 +217,31 @@ $white-gc-bg: #eaf2f5;
.cp { color: $white-cp; font-weight: $gl-font-weight-bold; } .cp { color: $white-cp; font-weight: $gl-font-weight-bold; }
.c1 { color: $white-c1; font-style: italic; } .c1 { color: $white-c1; font-style: italic; }
.cs { color: $white-cs; font-weight: $gl-font-weight-bold; font-style: italic; } .cs { color: $white-cs; font-weight: $gl-font-weight-bold; font-style: italic; }
.gd { color: $white-gd; background-color: $white-gd-bg; }
.gd .x { color: $white-gd-x; background-color: $white-gd-x-bg; } .gd {
color: $white-gd;
background-color: $white-gd-bg;
.x {
color: $white-gd-x;
background-color: $white-gd-x-bg;
}
}
.ge { font-style: italic; } .ge { font-style: italic; }
.gr { color: $white-gr; } .gr { color: $white-gr; }
.gh { color: $white-gh; } .gh { color: $white-gh; }
.gi { color: $white-gi; background-color: $white-gi-bg; }
.gi .x { color: $white-gi-x; background-color: $white-gi-x-bg; } .gi {
color: $white-gi;
background-color: $white-gi-bg;
.x {
color: $white-gi-x;
background-color: $white-gi-x-bg;
}
}
.go { color: $white-go; } .go { color: $white-go; }
.gp { color: $white-gp; } .gp { color: $white-gp; }
.gs { font-weight: $gl-font-weight-bold; } .gs { font-weight: $gl-font-weight-bold; }
......
...@@ -158,13 +158,31 @@ span.highlight_word { ...@@ -158,13 +158,31 @@ span.highlight_word {
.cp { color: $highlighted-cp; font-weight: $gl-font-weight-bold; } .cp { color: $highlighted-cp; font-weight: $gl-font-weight-bold; }
.c1 { color: $highlighted-c1; font-style: italic; } .c1 { color: $highlighted-c1; font-style: italic; }
.cs { color: $highlighted-cs; font-weight: $gl-font-weight-bold; font-style: italic; } .cs { color: $highlighted-cs; font-weight: $gl-font-weight-bold; font-style: italic; }
.gd { color: $highlighted-gd; background-color: $highlighted-gd-bg; }
.gd .x { color: $highlighted-gd; background-color: $highlighted-gd-x-bg; } .gd {
color: $highlighted-gd;
background-color: $highlighted-gd-bg;
.x {
color: $highlighted-gd;
background-color: $highlighted-gd-x-bg;
}
}
.ge { font-style: italic; } .ge { font-style: italic; }
.gr { color: $highlighted-gr; } .gr { color: $highlighted-gr; }
.gh { color: $highlighted-gh; } .gh { color: $highlighted-gh; }
.gi { color: $highlighted-gi; background-color: $highlighted-gi-bg; }
.gi .x { color: $highlighted-gi; background-color: $highlighted-gi-x-bg; } .gi {
color: $highlighted-gi;
background-color: $highlighted-gi-bg;
.x {
color: $highlighted-gi;
background-color: $highlighted-gi-x-bg;
}
}
.go { color: $highlighted-go; } .go { color: $highlighted-go; }
.gp { color: $highlighted-gp; } .gp { color: $highlighted-gp; }
.gs { font-weight: $gl-font-weight-bold; } .gs { font-weight: $gl-font-weight-bold; }
......
...@@ -86,10 +86,7 @@ ...@@ -86,10 +86,7 @@
} }
@media (min-width: $screen-md-min) { @media (min-width: $screen-md-min) {
height: 475px; // Needed for PhantomJS
// scss-lint:disable DuplicateProperty
height: calc(100vh - 160px); height: calc(100vh - 160px);
// scss-lint:enable DuplicateProperty
min-height: 475px; min-height: 475px;
} }
} }
......
...@@ -68,19 +68,19 @@ ...@@ -68,19 +68,19 @@
&.affix { &.affix {
top: $header-height; top: $header-height;
}
// with sidebar // with sidebar
&.affix.sidebar-expanded { &.sidebar-expanded {
right: 306px; right: 306px;
left: 16px; left: 16px;
} }
// without sidebar // without sidebar
&.affix.sidebar-collapsed { &.sidebar-collapsed {
right: 16px; right: 16px;
left: 16px; left: 16px;
} }
}
&.affix-top { &.affix-top {
position: absolute; position: absolute;
......
...@@ -22,6 +22,11 @@ ...@@ -22,6 +22,11 @@
} }
} }
} }
svg {
width: 136px;
height: 136px;
}
} }
.col-headers { .col-headers {
...@@ -155,11 +160,6 @@ ...@@ -155,11 +160,6 @@
} }
} }
.landing svg {
width: 136px;
height: 136px;
}
.fa-spinner { .fa-spinner {
font-size: 28px; font-size: 28px;
position: relative; position: relative;
......
...@@ -380,6 +380,10 @@ ...@@ -380,6 +380,10 @@
} }
} }
} }
.line_content {
white-space: pre-wrap;
}
} }
.file-content .diff-file { .file-content .diff-file {
...@@ -387,10 +391,6 @@ ...@@ -387,10 +391,6 @@
border: none; border: none;
} }
.diff-file .line_content {
white-space: pre-wrap;
}
.diff-wrap-lines .line_content { .diff-wrap-lines .line_content {
white-space: pre-wrap; white-space: pre-wrap;
} }
......
...@@ -255,23 +255,6 @@ ...@@ -255,23 +255,6 @@
width: 100%; width: 100%;
padding: 0; padding: 0;
padding-bottom: 100%; padding-bottom: 100%;
}
.prometheus-svg-container > svg {
position: absolute;
height: 100%;
width: 100%;
left: 0;
top: 0;
text {
fill: $gl-text-color;
stroke-width: 0;
}
.text-metric-bold {
font-weight: $gl-font-weight-bold;
}
.label-axis-text { .label-axis-text {
fill: $black; fill: $black;
...@@ -286,19 +269,27 @@ ...@@ -286,19 +269,27 @@
font-size: 12px; font-size: 12px;
} }
.legend-axis-text { > svg {
position: absolute;
height: 100%;
width: 100%;
left: 0;
top: 0;
.label-axis-text,
.text-metric-usage {
fill: $black; fill: $black;
font-weight: $gl-font-weight-normal;
font-size: 12px;
} }
.tick { .legend-axis-text {
> line { fill: $black;
stroke: $gray-darker;
} }
> text { .tick > text {
font-size: 12px; font-size: 12px;
} }
}
.text-metric-title { .text-metric-title {
font-size: 12px; font-size: 12px;
...@@ -324,4 +315,5 @@ ...@@ -324,4 +315,5 @@
font-size: 8px; font-size: 8px;
} }
} }
}
} }
...@@ -127,7 +127,16 @@ ...@@ -127,7 +127,16 @@
} }
.right-sidebar { .right-sidebar {
a:not(.btn-retry), position: absolute;
top: $header-height;
bottom: 0;
right: 0;
transition: width .3s;
background: $gray-light;
z-index: 200;
overflow: hidden;
a,
.btn-link { .btn-link {
color: inherit; color: inherit;
} }
...@@ -228,17 +237,6 @@ ...@@ -228,17 +237,6 @@
.btn-clipboard:hover { .btn-clipboard:hover {
color: $gl-text-color; color: $gl-text-color;
} }
}
.right-sidebar {
position: absolute;
top: $header-height;
bottom: 0;
right: 0;
transition: width $right-sidebar-transition-duration;
background: $gray-light;
z-index: 200;
overflow: hidden;
.issuable-sidebar { .issuable-sidebar {
width: calc(100% + 100px); width: calc(100% + 100px);
......
...@@ -109,6 +109,30 @@ ...@@ -109,6 +109,30 @@
border-top-right-radius: $border-radius-default; border-top-right-radius: $border-radius-default;
border-top-left-radius: $border-radius-default; border-top-left-radius: $border-radius-default;
// Ldap configurations may need more tabs & the tab labels are user generated (arbitrarily long).
// These styles prevent this from breaking the layout, and only applied when providers are configured.
&.custom-provider-tabs {
flex-wrap: wrap;
li {
min-width: 85px;
flex-basis: auto;
// This styles tab elements that have wrapped to a second line. We cannot easily predict when this will happen.
// We are making somewhat of an assumption about the configuration here: that users do not have more than
// 3 LDAP servers configured (in addition to standard login) and they are not using especially long names for any
// of them. If either condition is false, this will work as expected. If both are true, there may be a missing border
// above one of the bottom row elements. If you know a better way, please implement it!
&:nth-child(n+5) {
border-top: 1px solid $border-color;
}
}
a {
font-size: 16px;
}
}
li { li {
flex: 1; flex: 1;
text-align: center; text-align: center;
...@@ -154,32 +178,6 @@ ...@@ -154,32 +178,6 @@
} }
} }
// Ldap configurations may need more tabs & the tab labels are user generated (arbitrarily long).
// These styles prevent this from breaking the layout, and only applied when providers are configured.
.new-session-tabs.custom-provider-tabs {
flex-wrap: wrap;
li {
min-width: 85px;
flex-basis: auto;
// This styles tab elements that have wrapped to a second line. We cannot easily predict when this will happen.
// We are making somewhat of an assumption about the configuration here: that users do not have more than
// 3 LDAP servers configured (in addition to standard login) and they are not using especially long names for any
// of them. If either condition is false, this will work as expected. If both are true, there may be a missing border
// above one of the bottom row elements. If you know a better way, please implement it!
&:nth-child(n+5) {
border-top: 1px solid $border-color;
}
}
a {
font-size: 16px;
}
}
.form-control { .form-control {
&:active, &:active,
&:focus { &:focus {
...@@ -231,10 +229,9 @@ ...@@ -231,10 +229,9 @@
margin: 0; margin: 0;
padding: 0; padding: 0;
height: 100%; height: 100%;
}
// Fixes footer container to bottom of viewport // Fixes footer container to bottom of viewport
.devise-layout-html body { body {
// offset height of fixed header + 1 to avoid scroll // offset height of fixed header + 1 to avoid scroll
height: calc(100% - 51px); height: calc(100% - 51px);
margin: 0; margin: 0;
...@@ -262,4 +259,5 @@ ...@@ -262,4 +259,5 @@
padding: 0 15px 65px; padding: 0 15px 65px;
} }
} }
}
} }
...@@ -49,9 +49,17 @@ ...@@ -49,9 +49,17 @@
width: auto; width: auto;
} }
} }
&.existing-title {
@media (min-width: $screen-sm-min) {
float: left;
}
}
} }
.member-form-control { .member-form-control {
@include new-style-dropdown;
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
padding-bottom: 5px; padding-bottom: 5px;
margin-left: 0; margin-left: 0;
...@@ -64,12 +72,6 @@ ...@@ -64,12 +72,6 @@
line-height: 43px; line-height: 43px;
} }
.member.existing-title {
@media (min-width: $screen-sm-min) {
float: left;
}
}
.member-search-form { .member-search-form {
@include new-style-dropdown; @include new-style-dropdown;
...@@ -281,7 +283,3 @@ ...@@ -281,7 +283,3 @@
} }
} }
} }
.member-form-control {
@include new-style-dropdown;
}
...@@ -156,6 +156,10 @@ ...@@ -156,6 +156,10 @@
&.media > *:first-child { &.media > *:first-child {
margin-right: 10px; margin-right: 10px;
} }
.approve-btn {
margin-right: 5px;
}
} }
.mr-widget-pipeline-graph { .mr-widget-pipeline-graph {
...@@ -191,6 +195,10 @@ ...@@ -191,6 +195,10 @@
overflow: hidden; overflow: hidden;
word-break: break-all; word-break: break-all;
&.media > *:first-child {
margin-right: 10px;
}
&.label-truncated { &.label-truncated {
position: relative; position: relative;
display: inline-block; display: inline-block;
...@@ -208,14 +216,7 @@ ...@@ -208,14 +216,7 @@
background-color: $gray-light; background-color: $gray-light;
} }
} }
}
.mr-widget-help {
padding: 10px 16px 10px 48px;
font-style: italic;
}
.mr-widget-body {
h4 { h4 {
float: left; float: left;
font-weight: $gl-font-weight-bold; font-weight: $gl-font-weight-bold;
...@@ -238,6 +239,10 @@ ...@@ -238,6 +239,10 @@
margin-right: 7px; margin-right: 7px;
} }
.approve-btn {
margin-right: 5px;
}
label { label {
font-weight: $gl-font-weight-normal; font-weight: $gl-font-weight-normal;
} }
...@@ -337,6 +342,22 @@ ...@@ -337,6 +342,22 @@
} }
} }
.mini-pipeline-graph-dropdown-menu .mini-pipeline-graph-dropdown-item {
display: flex;
align-items: center;
.ci-status-text,
.ci-status-icon {
top: 0;
margin-right: 10px;
}
}
.mr-widget-help {
padding: 10px 16px 10px 48px;
font-style: italic;
}
.ci-coverage { .ci-coverage {
float: right; float: right;
} }
...@@ -351,12 +372,6 @@ ...@@ -351,12 +372,6 @@
} }
} }
.mr-state-widget .mr-widget-body {
.approve-btn {
margin-right: 5px;
}
}
.mr-widget-body-controls { .mr-widget-body-controls {
flex-wrap: wrap; flex-wrap: wrap;
} }
...@@ -470,9 +485,8 @@ ...@@ -470,9 +485,8 @@
padding-bottom: 0; padding-bottom: 0;
} }
} }
}
.mr-info-list.mr-memory-usage { &.mr-memory-usage {
p { p {
float: left; float: left;
} }
...@@ -481,6 +495,7 @@ ...@@ -481,6 +495,7 @@
float: left; float: left;
margin-left: 5px; margin-left: 5px;
} }
}
} }
.mr-source-target { .mr-source-target {
......
...@@ -66,6 +66,15 @@ ...@@ -66,6 +66,15 @@
height: 6px; height: 6px;
margin: 0; margin: 0;
} }
.sidebar-collapsed-icon {
clear: both;
padding: 15px 5px 5px;
.progress {
margin: 5px 0;
}
}
} }
.collapsed-milestone-date { .collapsed-milestone-date {
...@@ -93,17 +102,6 @@ ...@@ -93,17 +102,6 @@
margin-right: 0; margin-right: 0;
} }
.milestone-progress {
.sidebar-collapsed-icon {
clear: both;
padding: 15px 5px 5px;
.progress {
margin: 5px 0;
}
}
}
.right-sidebar-collapsed & { .right-sidebar-collapsed & {
.reference { .reference {
border-top: 1px solid $border-gray-normal; border-top: 1px solid $border-gray-normal;
...@@ -156,18 +154,16 @@ ...@@ -156,18 +154,16 @@
.status-box { .status-box {
margin-top: 0; margin-top: 0;
order: 1;
} }
.milestone-buttons { .milestone-buttons {
margin-left: auto; margin-left: auto;
} order: 2;
.status-box { .verbose {
order: 1; display: none;
} }
.milestone-buttons {
order: 2;
} }
.header-text-content { .header-text-content {
...@@ -175,10 +171,6 @@ ...@@ -175,10 +171,6 @@
width: 100%; width: 100%;
} }
.milestone-buttons .verbose {
display: none;
}
@media (min-width: $screen-xs-min) { @media (min-width: $screen-xs-min) {
.milestone-buttons .verbose { .milestone-buttons .verbose {
display: inline; display: inline;
......
...@@ -111,24 +111,9 @@ ...@@ -111,24 +111,9 @@
margin: auto; margin: auto;
align-items: center; align-items: center;
.icon { + .md-area {
margin-right: $issuable-warning-icon-margin; border-top-left-radius: 0;
} border-top-right-radius: 0;
}
.disabled-comment .issuable-note-warning {
border: none;
border-radius: $label-border-radius;
padding-top: $gl-vert-padding;
padding-bottom: $gl-vert-padding;
.icon svg {
position: relative;
top: 2px;
margin-right: $btn-xs-side-margin;
width: $gl-font-size;
height: $gl-font-size;
fill: $orange-600;
} }
} }
...@@ -155,11 +140,6 @@ ...@@ -155,11 +140,6 @@
} }
} }
.issuable-note-warning + .md-area {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.discussion-form { .discussion-form {
background-color: $white-light; background-color: $white-light;
} }
......
...@@ -312,7 +312,21 @@ ul.notes { ...@@ -312,7 +312,21 @@ ul.notes {
} }
} }
.diff-file .notes_holder { .diff-file {
.is-over {
.add-diff-note {
display: inline-block;
}
}
// Merge request notes in diffs
// Diff is inline
.notes_content .note-header .note-headline-light {
display: inline-block;
position: relative;
}
.notes_holder {
font-family: $regular_font; font-family: $regular_font;
td { td {
...@@ -366,6 +380,7 @@ ul.notes { ...@@ -366,6 +380,7 @@ ul.notes {
} }
} }
} }
}
} }
.discussion-header, .discussion-header,
...@@ -457,8 +472,9 @@ ul.notes { ...@@ -457,8 +472,9 @@ ul.notes {
margin-left: 10px; margin-left: 10px;
color: $gray-darkest; color: $gray-darkest;
.btn-group > .discussion-next-btn { @include notes-media('max', $screen-md-max) {
margin-left: -1px; float: none;
margin-left: 0;
} }
} }
...@@ -469,8 +485,6 @@ ul.notes { ...@@ -469,8 +485,6 @@ ul.notes {
flex-shrink: 0; flex-shrink: 0;
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
// For PhantomJS that does not support flex
float: right;
margin-left: 10px; margin-left: 10px;
color: $gray-darkest; color: $gray-darkest;
...@@ -481,7 +495,6 @@ ul.notes { ...@@ -481,7 +495,6 @@ ul.notes {
} }
.more-actions { .more-actions {
float: right; // phantomjs fallback
display: flex; display: flex;
align-items: flex-end; align-items: flex-end;
...@@ -502,13 +515,6 @@ ul.notes { ...@@ -502,13 +515,6 @@ ul.notes {
min-width: 180px; min-width: 180px;
} }
.discussion-actions {
@include notes-media('max', $screen-md-max) {
float: none;
margin-left: 0;
}
}
.note-actions-item { .note-actions-item {
margin-left: 12px; margin-left: 12px;
display: flex; display: flex;
...@@ -665,14 +671,6 @@ ul.notes { ...@@ -665,14 +671,6 @@ ul.notes {
} }
} }
.diff-file {
.is-over {
.add-diff-note {
display: inline-block;
}
}
}
.disabled-comment { .disabled-comment {
background-color: $gray-light; background-color: $gray-light;
border-radius: $border-radius-base; border-radius: $border-radius-base;
...@@ -714,9 +712,8 @@ ul.notes { ...@@ -714,9 +712,8 @@ ul.notes {
svg path { svg path {
fill: $gray-darkest; fill: $gray-darkest;
} }
}
.btn.discussion-create-issue-btn { &.discussion-create-issue-btn {
margin-left: -4px; margin-left: -4px;
border-radius: 0; border-radius: 0;
border-right: 0; border-right: 0;
...@@ -731,6 +728,7 @@ ul.notes { ...@@ -731,6 +728,7 @@ ul.notes {
} }
} }
} }
}
} }
.line-resolve-all { .line-resolve-all {
...@@ -801,12 +799,3 @@ ul.notes { ...@@ -801,12 +799,3 @@ ul.notes {
.line-resolve-text { .line-resolve-text {
vertical-align: middle; vertical-align: middle;
} }
// Merge request notes in diffs
.diff-file {
// Diff is inline
.notes_content .note-header .note-headline-light {
display: inline-block;
position: relative;
}
}
...@@ -175,6 +175,25 @@ ...@@ -175,6 +175,25 @@
} }
} }
/**
* Play button with icon in dropdowns
*/
.no-btn {
border: none;
background: none;
outline: none;
width: 100%;
text-align: left;
.icon-play {
position: relative;
top: 2px;
margin-right: 5px;
height: 13px;
width: 12px;
}
}
.duration, .duration,
.finished-at { .finished-at {
color: $gl-text-color-secondary; color: $gl-text-color-secondary;
...@@ -450,8 +469,13 @@ ...@@ -450,8 +469,13 @@
@extend .build-content:hover; @extend .build-content:hover;
} }
.ci-action-icon-container {
position: absolute;
right: 5px;
top: 5px;
// Action Icons in big pipeline-graph nodes // Action Icons in big pipeline-graph nodes
.ci-action-icon-container.ci-action-icon-wrapper { &.ci-action-icon-wrapper {
height: 30px; height: 30px;
width: 30px; width: 30px;
background: $white-light; background: $white-light;
...@@ -462,6 +486,10 @@ ...@@ -462,6 +486,10 @@
&:hover { &:hover {
background-color: $stage-hover-bg; background-color: $stage-hover-bg;
border: 1px solid $dropdown-toggle-active-border-color; border: 1px solid $dropdown-toggle-active-border-color;
svg {
fill: $gl-text-color;
}
} }
svg { svg {
...@@ -480,16 +508,7 @@ ...@@ -480,16 +508,7 @@
left: 8px; left: 8px;
} }
} }
&:hover svg {
fill: $gl-text-color;
}
} }
.ci-action-icon-container {
position: absolute;
right: 5px;
top: 5px;
} }
.ci-status-icon svg { .ci-status-icon svg {
...@@ -735,43 +754,44 @@ button.mini-pipeline-graph-dropdown-toggle { ...@@ -735,43 +754,44 @@ button.mini-pipeline-graph-dropdown-toggle {
left: -3px; left: -3px;
position: relative; position: relative;
top: -2px; top: -2px;
}
&:hover svg,
&:focus svg {
fill: $gl-text-color;
}
&.icon-action-retry,
&.icon-action-play {
svg {
width: #{$ci-action-icon-size - 6};
height: #{$ci-action-icon-size - 6};
left: 8px;
}
}
svg.icon-action-stop, &.icon-action-stop,
svg.icon-action-cancel { &.icon-action-cancel {
width: 12px; width: 12px;
height: 12px; height: 12px;
top: 1px; top: 1px;
left: -1px; left: -1px;
} }
svg.icon-action-play { &.icon-action-play {
width: 11px; width: 11px;
height: 11px; height: 11px;
top: 1px; top: 1px;
left: 1px; left: 1px;
} }
svg.icon-action-retry { &.icon-action-retry {
width: 16px; width: 16px;
height: 16px; height: 16px;
top: 0; top: 0;
left: -3px; left: -3px;
} }
}
&:hover svg,
&:focus svg {
fill: $gl-text-color;
}
&.icon-action-retry,
&.icon-action-play {
svg {
width: #{$ci-action-icon-size - 6};
height: #{$ci-action-icon-size - 6};
left: 8px;
}
}
} }
...@@ -840,13 +860,10 @@ button.mini-pipeline-graph-dropdown-toggle { ...@@ -840,13 +860,10 @@ button.mini-pipeline-graph-dropdown-toggle {
left: 100%; left: 100%;
top: -10px; top: -10px;
box-shadow: 0 1px 5px $black-transparent; box-shadow: 0 1px 5px $black-transparent;
}
/** /**
* Top arrow in the dropdown in the big pipeline graph * Top arrow in the dropdown in the big pipeline graph
*/ */
.big-pipeline-graph-dropdown-menu {
&::before, &::before,
&::after { &::after {
content: ''; content: '';
...@@ -908,12 +925,11 @@ button.mini-pipeline-graph-dropdown-toggle { ...@@ -908,12 +925,11 @@ button.mini-pipeline-graph-dropdown-toggle {
margin-top: 1px; margin-top: 1px;
border-bottom-color: $white-light; border-bottom-color: $white-light;
} }
}
/** /**
* Center dropdown menu in mini graph * Center dropdown menu in mini graph
*/ */
.mini-pipeline-graph-dropdown-menu.dropdown-menu { &.dropdown-menu {
transform: translate(-80%, 0); transform: translate(-80%, 0);
min-width: 150px; min-width: 150px;
...@@ -923,7 +939,9 @@ button.mini-pipeline-graph-dropdown-toggle { ...@@ -923,7 +939,9 @@ button.mini-pipeline-graph-dropdown-toggle {
left: 50%; left: 50%;
min-width: 240px; min-width: 240px;
} }
}
} }
/** /**
* Terminal * Terminal
*/ */
...@@ -947,25 +965,6 @@ button.mini-pipeline-graph-dropdown-toggle { ...@@ -947,25 +965,6 @@ button.mini-pipeline-graph-dropdown-toggle {
} }
} }
/**
* Play button with icon in dropdowns
*/
.ci-table .no-btn {
border: none;
background: none;
outline: none;
width: 100%;
text-align: left;
.icon-play {
position: relative;
top: 2px;
margin-right: 5px;
height: 13px;
width: 12px;
}
}
.ci-header-container { .ci-header-container {
min-height: 55px; min-height: 55px;
......
...@@ -88,7 +88,8 @@ ...@@ -88,7 +88,8 @@
transition: background 2s ease-out; transition: background 2s ease-out;
&:disabled { &:disabled {
opacity: 0.75; opacity: 0.5;
pointer-events: none;
} }
.highlight-changes & { .highlight-changes & {
...@@ -778,9 +779,8 @@ a.deploy-project-label { ...@@ -778,9 +779,8 @@ a.deploy-project-label {
.nav { .nav {
padding-top: 12px; padding-top: 12px;
padding-bottom: 12px; padding-bottom: 12px;
}
.nav > li { > li {
display: inline-block; display: inline-block;
&:not(:last-child) { &:not(:last-child) {
...@@ -795,9 +795,8 @@ a.deploy-project-label { ...@@ -795,9 +795,8 @@ a.deploy-project-label {
float: right; float: right;
} }
} }
}
.nav > li > a { > a {
padding: 0; padding: 0;
background-color: transparent; background-color: transparent;
font-size: 14px; font-size: 14px;
...@@ -809,6 +808,8 @@ a.deploy-project-label { ...@@ -809,6 +808,8 @@ a.deploy-project-label {
color: $gl-text-color; color: $gl-text-color;
} }
} }
}
}
li.missing { li.missing {
border: 1px dashed $border-gray-normal-dashed; border: 1px dashed $border-gray-normal-dashed;
...@@ -1160,13 +1161,6 @@ pre.light-well { ...@@ -1160,13 +1161,6 @@ pre.light-well {
} }
} }
.project-repo-select {
&.disabled {
opacity: 0.5;
pointer-events: none;
}
}
.variables-table { .variables-table {
table-layout: fixed; table-layout: fixed;
......
...@@ -78,6 +78,10 @@ input[type="checkbox"]:hover { ...@@ -78,6 +78,10 @@ input[type="checkbox"]:hover {
} }
.search-input-wrap { .search-input-wrap {
// Fallback if flexbox is not supported
display: inline-block;
width: 100%;
.search-icon, .search-icon,
.clear-icon { .clear-icon {
position: absolute; position: absolute;
......
...@@ -241,11 +241,11 @@ ...@@ -241,11 +241,11 @@
margin-left: 5px; margin-left: 5px;
background: $badge-bg; background: $badge-bg;
} }
}
/* Ensure we don't add border if there's only single li */ /* Ensure we don't add border if there's only single li */
li + li { + li {
border-top: 1px solid $border-color; border-top: 1px solid $border-color;
} }
} }
}
} }
...@@ -5,11 +5,11 @@ table .sherlock-code { ...@@ -5,11 +5,11 @@ table .sherlock-code {
.sherlock-code { .sherlock-code {
pre { pre {
word-wrap: normal; word-wrap: normal;
}
pre code { code {
white-space: pre; white-space: pre;
} }
}
} }
.sherlock-line-samples-table { .sherlock-line-samples-table {
...@@ -21,13 +21,13 @@ table .sherlock-code { ...@@ -21,13 +21,13 @@ table .sherlock-code {
text-align: right; text-align: right;
padding: 0 10px !important; padding: 0 10px !important;
} }
.slow {
color: $red-500;
font-weight: $gl-font-weight-bold;
}
} }
.sherlock-file-sample pre { .sherlock-file-sample pre {
padding-top: 28px !important; padding-top: 28px !important;
} }
.sherlock-line-samples-table .slow {
color: $red-500;
font-weight: $gl-font-weight-bold;
}
...@@ -40,17 +40,17 @@ ...@@ -40,17 +40,17 @@
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
width: 100%; width: 100%;
} }
}
.person .spark { .spark {
display: block; display: block;
background: $stat-graph-common-bg; background: $stat-graph-common-bg;
width: 100%; width: 100%;
} }
.person .area-contributor { .area-contributor {
fill: $stat-graph-orange-fill; fill: $stat-graph-orange-fill;
} }
}
} }
.selection rect { .selection rect {
......
...@@ -161,11 +161,11 @@ ul.wiki-pages-list.content-list { ...@@ -161,11 +161,11 @@ ul.wiki-pages-list.content-list {
list-style: none; list-style: none;
margin-left: 0; margin-left: 0;
padding-left: 15px; padding-left: 15px;
}
ul li { li {
padding: 5px 0; padding: 5px 0;
} }
}
} }
.wiki { .wiki {
......
...@@ -4,11 +4,6 @@ ...@@ -4,11 +4,6 @@
-ms-transition: none !important; -ms-transition: none !important;
-webkit-transition: none !important; -webkit-transition: none !important;
transition: none !important; transition: none !important;
-o-transform: none !important;
-moz-transform: none !important;
-ms-transform: none !important;
-webkit-transform: none !important;
transform: none !important;
-webkit-animation: none !important; -webkit-animation: none !important;
-moz-animation: none !important; -moz-animation: none !important;
-o-animation: none !important; -o-animation: none !important;
......
...@@ -94,10 +94,9 @@ module LfsRequest ...@@ -94,10 +94,9 @@ module LfsRequest
@storage_project ||= begin @storage_project ||= begin
result = project result = project
loop do # TODO: Make this go to the fork_network root immeadiatly
break unless result.forked? # dependant on the discussion in: https://gitlab.com/gitlab-org/gitlab-ce/issues/39769
result = result.forked_from_project result = result.fork_source while result.forked?
end
result result
end end
......
...@@ -4,6 +4,7 @@ module NotesActions ...@@ -4,6 +4,7 @@ module NotesActions
included do included do
before_action :set_polling_interval_header, only: [:index] before_action :set_polling_interval_header, only: [:index]
before_action :noteable, only: :index
before_action :authorize_admin_note!, only: [:update, :destroy] before_action :authorize_admin_note!, only: [:update, :destroy]
before_action :note_project, only: [:create] before_action :note_project, only: [:create]
end end
...@@ -188,7 +189,7 @@ module NotesActions ...@@ -188,7 +189,7 @@ module NotesActions
end end
def noteable def noteable
@noteable ||= notes_finder.target @noteable ||= notes_finder.target || render_404
end end
def last_fetched_at def last_fetched_at
......
...@@ -110,7 +110,15 @@ module ProjectsHelper ...@@ -110,7 +110,15 @@ module ProjectsHelper
def remove_fork_project_message(project) def remove_fork_project_message(project)
_("You are going to remove the fork relationship to source project %{forked_from_project}. Are you ABSOLUTELY sure?") % _("You are going to remove the fork relationship to source project %{forked_from_project}. Are you ABSOLUTELY sure?") %
{ forked_from_project: @project.forked_from_project.name_with_namespace } { forked_from_project: fork_source_name(project) }
end
def fork_source_name(project)
if @project.fork_source
@project.fork_source.full_name
else
@project.fork_network&.deleted_root_project_name
end
end end
def project_nav_tabs def project_nav_tabs
...@@ -140,8 +148,8 @@ module ProjectsHelper ...@@ -140,8 +148,8 @@ module ProjectsHelper
def can_change_visibility_level?(project, current_user) def can_change_visibility_level?(project, current_user)
return false unless can?(current_user, :change_visibility_level, project) return false unless can?(current_user, :change_visibility_level, project)
if project.forked? if project.fork_source
project.forked_from_project.visibility_level > Gitlab::VisibilityLevel::PRIVATE project.fork_source.visibility_level > Gitlab::VisibilityLevel::PRIVATE
else else
true true
end end
......
...@@ -12,4 +12,8 @@ class ForkNetwork < ActiveRecord::Base ...@@ -12,4 +12,8 @@ class ForkNetwork < ActiveRecord::Base
def find_forks_in(other_projects) def find_forks_in(other_projects)
projects.where(id: other_projects) projects.where(id: other_projects)
end end
def merge_requests
MergeRequest.where(target_project: projects)
end
end end
...@@ -42,6 +42,7 @@ class Group < Namespace ...@@ -42,6 +42,7 @@ class Group < Namespace
after_create :post_create_hook after_create :post_create_hook
after_destroy :post_destroy_hook after_destroy :post_destroy_hook
after_save :update_two_factor_requirement after_save :update_two_factor_requirement
after_update :path_changed_hook, if: :path_changed?
class << self class << self
def supports_nested_groups? def supports_nested_groups?
...@@ -295,6 +296,12 @@ class Group < Namespace ...@@ -295,6 +296,12 @@ class Group < Namespace
list_of_ids.reverse.map { |group| variables[group.id] }.compact.flatten list_of_ids.reverse.map { |group| variables[group.id] }.compact.flatten
end end
def full_path_was
return path_was unless has_parent?
"#{parent.full_path}/#{path_was}"
end
private private
def update_two_factor_requirement def update_two_factor_requirement
...@@ -303,6 +310,10 @@ class Group < Namespace ...@@ -303,6 +310,10 @@ class Group < Namespace
users.find_each(&:update_two_factor_requirement) users.find_each(&:update_two_factor_requirement)
end end
def path_changed_hook
system_hook_service.execute_hooks_for(self, :rename)
end
def visibility_level_allowed_by_parent def visibility_level_allowed_by_parent
return if visibility_level_allowed_by_parent? return if visibility_level_allowed_by_parent?
......
...@@ -1042,6 +1042,10 @@ class Project < ActiveRecord::Base ...@@ -1042,6 +1042,10 @@ class Project < ActiveRecord::Base
!(forked_project_link.nil? || forked_project_link.forked_from_project.nil?) !(forked_project_link.nil? || forked_project_link.forked_from_project.nil?)
end end
def fork_source
forked_from_project || fork_network&.root_project
end
def personal? def personal?
!group !group
end end
...@@ -1490,7 +1494,8 @@ class Project < ActiveRecord::Base ...@@ -1490,7 +1494,8 @@ class Project < ActiveRecord::Base
{ key: 'CI_PROJECT_PATH', value: full_path, public: true }, { key: 'CI_PROJECT_PATH', value: full_path, public: true },
{ key: 'CI_PROJECT_PATH_SLUG', value: full_path_slug, public: true }, { key: 'CI_PROJECT_PATH_SLUG', value: full_path_slug, public: true },
{ key: 'CI_PROJECT_NAMESPACE', value: namespace.full_path, public: true }, { key: 'CI_PROJECT_NAMESPACE', value: namespace.full_path, public: true },
{ key: 'CI_PROJECT_URL', value: web_url, public: true } { key: 'CI_PROJECT_URL', value: web_url, public: true },
{ key: 'CI_PROJECT_VISIBILITY', value: Gitlab::VisibilityLevel.string_level(visibility_level), public: true }
] ]
end end
......
...@@ -168,6 +168,7 @@ class User < ActiveRecord::Base ...@@ -168,6 +168,7 @@ class User < ActiveRecord::Base
before_save :skip_reconfirmation!, if: ->(user) { user.email_changed? && user.read_only_attribute?(:email) } before_save :skip_reconfirmation!, if: ->(user) { user.email_changed? && user.read_only_attribute?(:email) }
before_save :check_for_verified_email, if: ->(user) { user.email_changed? && !user.new_record? } before_save :check_for_verified_email, if: ->(user) { user.email_changed? && !user.new_record? }
after_save :ensure_namespace_correct after_save :ensure_namespace_correct
after_update :username_changed_hook, if: :username_changed?
after_destroy :post_destroy_hook after_destroy :post_destroy_hook
after_commit :update_emails_with_primary_email, on: :update, if: -> { previous_changes.key?('email') } after_commit :update_emails_with_primary_email, on: :update, if: -> { previous_changes.key?('email') }
after_commit :update_invalid_gpg_signatures, on: :update, if: -> { previous_changes.key?('email') } after_commit :update_invalid_gpg_signatures, on: :update, if: -> { previous_changes.key?('email') }
...@@ -871,6 +872,10 @@ class User < ActiveRecord::Base ...@@ -871,6 +872,10 @@ class User < ActiveRecord::Base
end end
end end
def username_changed_hook
system_hook_service.execute_hooks_for(self, :rename)
end
def post_destroy_hook def post_destroy_hook
log_info("User \"#{name}\" (#{email}) was removed") log_info("User \"#{name}\" (#{email}) was removed")
system_hook_service.execute_hooks_for(self, :destroy) system_hook_service.execute_hooks_for(self, :destroy)
......
...@@ -3,18 +3,24 @@ module Projects ...@@ -3,18 +3,24 @@ module Projects
def execute def execute
return unless @project.forked? return unless @project.forked?
@project.forked_from_project.lfs_objects.find_each do |lfs_object| if fork_source = @project.fork_source
fork_source.lfs_objects.find_each do |lfs_object|
lfs_object.projects << @project lfs_object.projects << @project
end end
merge_requests = @project.forked_from_project.merge_requests.opened.from_project(@project) refresh_forks_count(fork_source)
end
merge_requests = @project.fork_network
.merge_requests
.opened
.where.not(target_project: @project)
.from_project(@project)
merge_requests.each do |mr| merge_requests.each do |mr|
::MergeRequests::CloseService.new(@project, @current_user).execute(mr) ::MergeRequests::CloseService.new(@project, @current_user).execute(mr)
end end
refresh_forks_count(@project.forked_from_project)
@project.fork_network_member.destroy @project.fork_network_member.destroy
@project.forked_project_link.destroy @project.forked_project_link.destroy
end end
......
...@@ -35,24 +35,22 @@ class SystemHooksService ...@@ -35,24 +35,22 @@ class SystemHooksService
data[:old_path_with_namespace] = model.old_path_with_namespace data[:old_path_with_namespace] = model.old_path_with_namespace
end end
when User when User
data.merge!({ data.merge!(user_data(model))
name: model.name,
email: model.email, if event == :rename
user_id: model.id, data[:old_username] = model.username_was
username: model.username end
})
when ProjectMember when ProjectMember
data.merge!(project_member_data(model)) data.merge!(project_member_data(model))
when Group when Group
owner = model.owner data.merge!(group_data(model))
if event == :rename
data.merge!( data.merge!(
name: model.name, old_path: model.path_was,
path: model.path, old_full_path: model.full_path_was
group_id: model.id,
owner_name: owner.respond_to?(:name) ? owner.name : nil,
owner_email: owner.respond_to?(:email) ? owner.email : nil
) )
end
when GroupMember when GroupMember
data.merge!(group_member_data(model)) data.merge!(group_member_data(model))
end end
...@@ -104,6 +102,19 @@ class SystemHooksService ...@@ -104,6 +102,19 @@ class SystemHooksService
} }
end end
def group_data(model)
owner = model.owner
{
name: model.name,
path: model.path,
full_path: model.full_path,
group_id: model.id,
owner_name: owner.try(:name),
owner_email: owner.try(:email)
}
end
def group_member_data(model) def group_member_data(model)
{ {
group_name: model.group.name, group_name: model.group.name,
...@@ -116,4 +127,13 @@ class SystemHooksService ...@@ -116,4 +127,13 @@ class SystemHooksService
group_access: model.human_access group_access: model.human_access
} }
end end
def user_data(model)
{
name: model.name,
email: model.email,
user_id: model.id,
username: model.username
}
end
end end
- empty_repo = @project.empty_repo? - empty_repo = @project.empty_repo?
- fork_network = @project.fork_network - fork_network = @project.fork_network
- forked_from_project = @project.forked_from_project || fork_network&.root_project
.project-home-panel.text-center{ class: ("empty-project" if empty_repo) } .project-home-panel.text-center{ class: ("empty-project" if empty_repo) }
.limit-container-width{ class: container_class } .limit-container-width{ class: container_class }
.avatar-container.s70.project-avatar .avatar-container.s70.project-avatar
...@@ -16,13 +15,13 @@ ...@@ -16,13 +15,13 @@
- if @project.forked? - if @project.forked?
%p %p
- if forked_from_project - if @project.fork_source
#{ s_('ForkedFromProjectPath|Forked from') } #{ s_('ForkedFromProjectPath|Forked from') }
= link_to project_path(forked_from_project) do = link_to project_path(@project.fork_source) do
= forked_from_project.full_name = fork_source_name(@project)
- else - else
- deleted_message = s_('ForkedFromProjectPath|Forked from %{project_name} (deleted)') - deleted_message = s_('ForkedFromProjectPath|Forked from %{project_name} (deleted)')
= deleted_message % { project_name: fork_network.deleted_root_project_name } = deleted_message % { project_name: fork_source_name(@project) }
.project-repo-buttons .project-repo-buttons
.count-buttons .count-buttons
......
...@@ -10,9 +10,9 @@ ...@@ -10,9 +10,9 @@
cluster_status: @cluster.status_name, cluster_status: @cluster.status_name,
cluster_status_reason: @cluster.status_reason } } cluster_status_reason: @cluster.status_reason } }
%section.settings %section.settings.no-animate.expanded
%h4= s_('ClusterIntegration|Enable cluster integration') %h4= s_('ClusterIntegration|Enable cluster integration')
.settings-content.expanded .settings-content
.hidden.js-cluster-error.alert.alert-danger.alert-block.append-bottom-10{ role: 'alert' } .hidden.js-cluster-error.alert.alert-danger.alert-block.append-bottom-10{ role: 'alert' }
= s_('ClusterIntegration|Something went wrong while creating your cluster on Google Container Engine') = s_('ClusterIntegration|Something went wrong while creating your cluster on Google Container Engine')
...@@ -49,14 +49,14 @@ ...@@ -49,14 +49,14 @@
.form-group .form-group
= field.submit _('Save'), class: 'btn btn-success' = field.submit _('Save'), class: 'btn btn-success'
%section.settings#js-cluster-details %section.settings.no-animate#js-cluster-details{ class: ('expanded' if expanded) }
.settings-header .settings-header
%h4= s_('ClusterIntegration|Cluster details') %h4= s_('ClusterIntegration|Cluster details')
%button.btn.js-settings-toggle %button.btn.js-settings-toggle
= expanded ? 'Collapse' : 'Expand' = expanded ? 'Collapse' : 'Expand'
%p= s_('ClusterIntegration|See and edit the details for your cluster') %p= s_('ClusterIntegration|See and edit the details for your cluster')
.settings-content.no-animate{ class: ('expanded' if expanded) } .settings-content
.form_group.append-bottom-20 .form_group.append-bottom-20
%label.append-bottom-10{ for: 'cluter-name' } %label.append-bottom-10{ for: 'cluter-name' }
...@@ -66,11 +66,11 @@ ...@@ -66,11 +66,11 @@
%span.input-group-addon.clipboard-addon %span.input-group-addon.clipboard-addon
= clipboard_button(text: @cluster.name, title: s_('ClusterIntegration|Copy cluster name')) = clipboard_button(text: @cluster.name, title: s_('ClusterIntegration|Copy cluster name'))
%section.settings#js-cluster-advanced-settings %section.settings.no-animate#js-cluster-advanced-settings{ class: ('expanded' if expanded) }
.settings-header .settings-header
%h4= _('Advanced settings') %h4= _('Advanced settings')
%button.btn.js-settings-toggle %button.btn.js-settings-toggle
= expanded ? 'Collapse' : 'Expand' = expanded ? 'Collapse' : 'Expand'
%p= s_('ClusterIntegration|Manage Cluster integration on your GitLab project') %p= s_('ClusterIntegration|Manage Cluster integration on your GitLab project')
.settings-content.no-animate{ class: ('expanded' if expanded) } .settings-content
= render 'advanced_settings' = render 'advanced_settings'
...@@ -173,7 +173,10 @@ ...@@ -173,7 +173,10 @@
%p %p
This will remove the fork relationship to source project This will remove the fork relationship to source project
= succeed "." do = succeed "." do
= link_to @project.forked_from_project.name_with_namespace, project_path(@project.forked_from_project) - if @project.fork_source
= link_to(fork_source_name(@project), project_path(@project.fork_source))
- else
= fork_source_name(@project)
= form_for([@project.namespace.becomes(Namespace), @project], url: remove_fork_project_path(@project), method: :delete, remote: true, html: { class: 'transfer-project' }) do |f| = form_for([@project.namespace.becomes(Namespace), @project], url: remove_fork_project_path(@project), method: :delete, remote: true, html: { class: 'transfer-project' }) do |f|
%p %p
%strong Once removed, the fork relationship cannot be restored and you will no longer be able to send merge requests to the source. %strong Once removed, the fork relationship cannot be restored and you will no longer be able to send merge requests to the source.
......
---
title: Expose project visibility as CI variable - CI_PROJECT_VISIBILITY
merge_request: 15193
author:
type: added
---
title: Stop merge requests with thousands of commits from timing out
merge_request: 15063
author:
type: performance
---
title: Update default disabled merge request widget message to reflect a general failure
merge_request: 14960
author:
type: changed
---
title: 'Fix bug preventing secondary emails from being confirmed'
merge_request: 15010
author:
type: fixed
---
title: Fix editing issue description in mobile view
merge_request:
author:
type: fixed
---
title: Fix bitbucket login
merge_request: 15051
author:
type: fixed
--- ---
title: Normalize LDAP DN when looking up identity title: Fix double border UI bug on pipelines/environments table and pagination
merge_request: merge_request:
author: author:
type: fixed type: fixed
---
title: Make the circuitbreaker more robust by adding higher thresholds, and multiple
access attempts.
merge_request: 14933
author:
type: fixed
---
title: Store circuitbreaker settings in the database instead of config
merge_request: 14842
author:
type: changed
---
title: Forbid the usage of `Redis#keys`
merge_request: 14889
author:
type: fixed
---
title: Don't rename paths that were freed up when upgrading
merge_request: 15029
author:
type: fixed
---
title: Only cache last push event for existing projects when pushing to a fork
merge_request: 14989
author:
type: fixed
---
title: Use the correct visibility attribute for projects in system hooks
merge_request: 15065
author:
type: fixed
---
title: Fix issues with forked projects of which the source was deleted
merge_request: 15150
author:
type: fixed
---
title: Enable MergeableSelector in scss-lint
merge_request: 12810
author: Takuya Noguchi
---
title: Fix broken wiki pages that link to a wiki file
merge_request: 15019
author:
type: fixed
---
title: Allow boards as top level route
merge_request:
author:
type: fixed
--- ---
title: Fix missing Import/Export issue assignees title: Fix a migration that adds merge_requests_ff_only_enabled column to MR table
merge_request: merge_request:
author: author:
type: fixed type: fixed
--- ---
title: Adds callback functions for initial request in clusters page title: Render 404 when polling commit notes without having permissions
merge_request: merge_request:
author: author:
type: fixed type: fixed
---
title: Fix widget of locked merge requests not being presented
merge_request:
author:
type: fixed
---
title: Auto Devops kubernetes default namespace is now correctly built out of gitlab
project group-name
merge_request: 14642
author: Mircea Danila Dumitrescu
type: fixed
---
title: Fix deletion of container registry or images returning an error
merge_request:
author:
type: fixed
---
title: Fix the writing of invalid environment refs
merge_request:
author:
type: fixed
---
title: Add system hooks user_rename and group_rename
merge_request: 15123
author:
type: changed
Rails.application.configure do Rails.application.configure do
# Make sure the middleware is inserted first in middleware chain # Make sure the middleware is inserted first in middleware chain
config.middleware.insert_before('ActionDispatch::Static', 'Gitlab::Testing::RequestBlockerMiddleware') config.middleware.insert_before('ActionDispatch::Static', 'Gitlab::Testing::RequestBlockerMiddleware')
config.middleware.insert_before('ActionDispatch::Static', 'Gitlab::Testing::RequestInspectorMiddleware')
# Settings specified here will take precedence over those in config/application.rb # Settings specified here will take precedence over those in config/application.rb
......
...@@ -8,8 +8,12 @@ class AddFastForwardOptionToProject < ActiveRecord::Migration ...@@ -8,8 +8,12 @@ class AddFastForwardOptionToProject < ActiveRecord::Migration
disable_ddl_transaction! disable_ddl_transaction!
def up def up
# We put condition here because of a mistake we made a couple of years ago
# see https://gitlab.com/gitlab-org/gitlab-ce/issues/39382#note_45716103
unless column_exists?(:projects, :merge_requests_ff_only_enabled)
add_column_with_default(:projects, :merge_requests_ff_only_enabled, :boolean, default: false) add_column_with_default(:projects, :merge_requests_ff_only_enabled, :boolean, default: false)
end end
end
def down def down
if column_exists?(:projects, :merge_requests_ff_only_enabled) if column_exists?(:projects, :merge_requests_ff_only_enabled)
......
...@@ -71,7 +71,7 @@ class MigrateGcpClustersToNewClustersArchitectures < ActiveRecord::Migration ...@@ -71,7 +71,7 @@ class MigrateGcpClustersToNewClustersArchitectures < ActiveRecord::Migration
operation_id: gcp_cluster.gcp_operation_id, operation_id: gcp_cluster.gcp_operation_id,
endpoint: gcp_cluster.endpoint, endpoint: gcp_cluster.endpoint,
encrypted_access_token: gcp_cluster.encrypted_gcp_token, encrypted_access_token: gcp_cluster.encrypted_gcp_token,
encrypted_access_token_iv: gcp_cluster.encrypted_gcp_token_iv, encrypted_access_token_iv: gcp_cluster.encrypted_gcp_token_iv
}, },
platform_kubernetes_attributes: { platform_kubernetes_attributes: {
cluster_id: gcp_cluster.id, cluster_id: gcp_cluster.id,
......
...@@ -66,6 +66,7 @@ future GitLab releases.** ...@@ -66,6 +66,7 @@ future GitLab releases.**
| **CI_PROJECT_PATH** | 8.10 | 0.5 | The namespace with project name | | **CI_PROJECT_PATH** | 8.10 | 0.5 | The namespace with project name |
| **CI_PROJECT_PATH_SLUG** | 9.3 | all | `$CI_PROJECT_PATH` lowercased and with everything except `0-9` and `a-z` replaced with `-`. Use in URLs and domain names. | | **CI_PROJECT_PATH_SLUG** | 9.3 | all | `$CI_PROJECT_PATH` lowercased and with everything except `0-9` and `a-z` replaced with `-`. Use in URLs and domain names. |
| **CI_PROJECT_URL** | 8.10 | 0.5 | The HTTP address to access project | | **CI_PROJECT_URL** | 8.10 | 0.5 | The HTTP address to access project |
| **CI_PROJECT_VISIBILITY** | 10.3 | all | The project visibility (internal, private, public) |
| **CI_REGISTRY** | 8.10 | 0.5 | If the Container Registry is enabled it returns the address of GitLab's Container Registry | | **CI_REGISTRY** | 8.10 | 0.5 | If the Container Registry is enabled it returns the address of GitLab's Container Registry |
| **CI_REGISTRY_IMAGE** | 8.10 | 0.5 | If the Container Registry is enabled for the project it returns the address of the registry tied to the specific project | | **CI_REGISTRY_IMAGE** | 8.10 | 0.5 | If the Container Registry is enabled for the project it returns the address of the registry tied to the specific project |
| **CI_REGISTRY_PASSWORD** | 9.0 | all | The password to use to push containers to the GitLab Container Registry | | **CI_REGISTRY_PASSWORD** | 9.0 | all | The password to use to push containers to the GitLab Container Registry |
......
# System hooks # System hooks
Your GitLab instance can perform HTTP POST requests on the following events: `project_create`, `project_destroy`, `project_rename`, `project_transfer`, `project_update`, `user_add_to_team`, `user_remove_from_team`, `user_create`, `user_destroy`, `key_create`, `key_destroy`, `group_create`, `group_destroy`, `user_add_to_group` and `user_remove_from_group`. Your GitLab instance can perform HTTP POST requests on the following events:
- `project_create`
- `project_destroy`
- `project_rename`
- `project_transfer`
- `project_update`
- `user_add_to_team`
- `user_remove_from_team`
- `user_create`
- `user_destroy`
- `user_rename`
- `key_create`
- `key_destroy`
- `group_create`
- `group_destroy`
- `group_rename`
- `user_add_to_group`
- `user_remove_from_group`
The triggers for most of these are self-explanatory, but `project_update` and `project_rename` deserve some clarification: `project_update` is fired any time an attribute of a project is changed (name, description, tags, etc.) *unless* the `path` attribute is also changed. In that case, a `project_rename` is triggered instead (so that, for instance, if all you care about is the repo URL, you can just listen for `project_rename`). The triggers for most of these are self-explanatory, but `project_update` and `project_rename` deserve some clarification: `project_update` is fired any time an attribute of a project is changed (name, description, tags, etc.) *unless* the `path` attribute is also changed. In that case, a `project_rename` is triggered instead (so that, for instance, if all you care about is the repo URL, you can just listen for `project_rename`).
...@@ -72,6 +90,9 @@ X-Gitlab-Event: System Hook ...@@ -72,6 +90,9 @@ X-Gitlab-Event: System Hook
} }
``` ```
Note that `project_rename` is not triggered if the namespace changes.
Please refer to `group_rename` and `user_rename` for that case.
**Project transferred:** **Project transferred:**
```json ```json
...@@ -175,6 +196,21 @@ X-Gitlab-Event: System Hook ...@@ -175,6 +196,21 @@ X-Gitlab-Event: System Hook
} }
``` ```
**User renamed:**
```json
{
"event_name": "user_rename",
"created_at": "2017-11-01T11:21:04Z",
"updated_at": "2017-11-01T14:04:47Z",
"name": "new-name",
"email": "best-email@example.tld",
"user_id": 58,
"username": "new-exciting-name",
"old_username": "old-boring-name"
}
```
**Key added** **Key added**
```json ```json
...@@ -209,13 +245,15 @@ X-Gitlab-Event: System Hook ...@@ -209,13 +245,15 @@ X-Gitlab-Event: System Hook
"updated_at": "2012-07-21T07:38:22Z", "updated_at": "2012-07-21T07:38:22Z",
"event_name": "group_create", "event_name": "group_create",
"name": "StoreCloud", "name": "StoreCloud",
"owner_email": "johnsmith@gmail.com", "owner_email": null,
"owner_name": "John Smith", "owner_name": null,
"path": "storecloud", "path": "storecloud",
"group_id": 78 "group_id": 78
} }
``` ```
`owner_name` and `owner_email` are always `null`. Please see https://gitlab.com/gitlab-org/gitlab-ce/issues/39675.
**Group removed:** **Group removed:**
```json ```json
...@@ -224,13 +262,35 @@ X-Gitlab-Event: System Hook ...@@ -224,13 +262,35 @@ X-Gitlab-Event: System Hook
"updated_at": "2012-07-21T07:38:22Z", "updated_at": "2012-07-21T07:38:22Z",
"event_name": "group_destroy", "event_name": "group_destroy",
"name": "StoreCloud", "name": "StoreCloud",
"owner_email": "johnsmith@gmail.com", "owner_email": null,
"owner_name": "John Smith", "owner_name": null,
"path": "storecloud", "path": "storecloud",
"group_id": 78 "group_id": 78
} }
``` ```
`owner_name` and `owner_email` are always `null`. Please see https://gitlab.com/gitlab-org/gitlab-ce/issues/39675.
**Group renamed:**
```json
{
"event_name": "group_rename",
"created_at": "2017-10-30T15:09:00Z",
"updated_at": "2017-11-01T10:23:52Z",
"name": "Better Name",
"path": "better-name",
"full_path": "parent-group/better-name",
"group_id": 64,
"owner_name": null,
"owner_email": null,
"old_path": "old-name",
"old_full_path": "parent-group/old-name"
}
```
`owner_name` and `owner_email` are always `null`. Please see https://gitlab.com/gitlab-org/gitlab-ce/issues/39675.
**New Group Member:** **New Group Member:**
```json ```json
......
...@@ -144,6 +144,12 @@ has a `.gitlab-ci.yml` or not: ...@@ -144,6 +144,12 @@ has a `.gitlab-ci.yml` or not:
All you need to do is remove your existing `.gitlab-ci.yml`, and you can even All you need to do is remove your existing `.gitlab-ci.yml`, and you can even
do that in a branch to test Auto DevOps before committing to `master`. do that in a branch to test Auto DevOps before committing to `master`.
NOTE: **Note:**
If you are a GitLab Administrator, you can enable Auto DevOps instance wide
in **Admin Area > Settings > Continuous Integration and Deployment**. Doing that,
all the projects that haven't explicitly set an option will have Auto DevOps
enabled by default.
## Stages of Auto DevOps ## Stages of Auto DevOps
The following sections describe the stages of Auto DevOps. Read them carefully The following sections describe the stages of Auto DevOps. Read them carefully
......
...@@ -11,7 +11,7 @@ class Spinach::Features::ProfileNotifications < Spinach::FeatureSteps ...@@ -11,7 +11,7 @@ class Spinach::Features::ProfileNotifications < Spinach::FeatureSteps
end end
step 'I select Mention setting from dropdown' do step 'I select Mention setting from dropdown' do
first(:link, "On mention").trigger('click') first(:link, "On mention").click
end end
step 'I should see Notification saved message' do step 'I should see Notification saved message' do
......
...@@ -40,6 +40,7 @@ class Spinach::Features::ProjectCommitsBranches < Spinach::FeatureSteps ...@@ -40,6 +40,7 @@ class Spinach::Features::ProjectCommitsBranches < Spinach::FeatureSteps
step 'I submit new branch form with invalid name' do step 'I submit new branch form with invalid name' do
fill_in 'branch_name', with: '1.0 stable' fill_in 'branch_name', with: '1.0 stable'
page.find("body").click # defocus the branch_name input
select_branch('master') select_branch('master')
click_button 'Create branch' click_button 'Create branch'
end end
...@@ -70,17 +71,16 @@ class Spinach::Features::ProjectCommitsBranches < Spinach::FeatureSteps ...@@ -70,17 +71,16 @@ class Spinach::Features::ProjectCommitsBranches < Spinach::FeatureSteps
step "I click branch 'improve/awesome' delete link" do step "I click branch 'improve/awesome' delete link" do
page.within '.js-branch-improve\/awesome' do page.within '.js-branch-improve\/awesome' do
find('.btn-remove').click accept_alert { find('.btn-remove').click }
sleep 0.05
end end
end end
step "I should not see branch 'improve/awesome'" do step "I should not see branch 'improve/awesome'" do
expect(page.all(visible: true)).not_to have_content 'improve/awesome' expect(page).to have_css('.js-branch-improve\\/awesome', visible: :hidden)
end end
def select_branch(branch_name) def select_branch(branch_name)
click_button 'master' find('.git-revision-dropdown-toggle').click
page.within '#new-branch-form .dropdown-menu' do page.within '#new-branch-form .dropdown-menu' do
click_link branch_name click_link branch_name
......
...@@ -16,7 +16,7 @@ class Spinach::Features::ProjectIssuesLabels < Spinach::FeatureSteps ...@@ -16,7 +16,7 @@ class Spinach::Features::ProjectIssuesLabels < Spinach::FeatureSteps
step 'I delete all labels' do step 'I delete all labels' do
page.within '.labels' do page.within '.labels' do
page.all('.remove-row').each do page.all('.remove-row').each do
first('.remove-row').click accept_confirm { first('.remove-row').click }
end end
end end
end end
......
...@@ -3,6 +3,7 @@ class Spinach::Features::ProjectIssuesMilestones < Spinach::FeatureSteps ...@@ -3,6 +3,7 @@ class Spinach::Features::ProjectIssuesMilestones < Spinach::FeatureSteps
include SharedProject include SharedProject
include SharedPaths include SharedPaths
include SharedMarkdown include SharedMarkdown
include CapybaraHelpers
step 'I should see milestone "v2.2"' do step 'I should see milestone "v2.2"' do
milestone = @project.milestones.find_by(title: "v2.2") milestone = @project.milestones.find_by(title: "v2.2")
...@@ -65,7 +66,7 @@ class Spinach::Features::ProjectIssuesMilestones < Spinach::FeatureSteps ...@@ -65,7 +66,7 @@ class Spinach::Features::ProjectIssuesMilestones < Spinach::FeatureSteps
end end
step 'I click link to remove milestone' do step 'I click link to remove milestone' do
click_link 'Delete' confirm_modal_if_present { click_link 'Delete' }
end end
step 'I should see no milestones' do step 'I should see no milestones' do
......
...@@ -215,7 +215,7 @@ module SharedDiffNote ...@@ -215,7 +215,7 @@ module SharedDiffNote
end end
step 'I click side-by-side diff button' do step 'I click side-by-side diff button' do
find('#parallel-diff-btn').trigger('click') find('#parallel-diff-btn').click
end end
step 'I see side-by-side diff button' do step 'I see side-by-side diff button' do
...@@ -227,12 +227,11 @@ module SharedDiffNote ...@@ -227,12 +227,11 @@ module SharedDiffNote
end end
def click_diff_line(code) def click_diff_line(code)
find(".line_holder[id='#{code}'] td:nth-of-type(1)").trigger 'mouseover' find(".line_holder[id='#{code}'] button").click
find(".line_holder[id='#{code}'] button").trigger 'click'
end end
def click_parallel_diff_line(code, line_type) def click_parallel_diff_line(code, line_type)
find(".line_holder.parallel td[id='#{code}']").find(:xpath, 'preceding-sibling::*[1][self::td]').trigger 'mouseover' find(".line_holder.parallel td[id='#{code}']").find(:xpath, 'preceding-sibling::*[1][self::td]').hover
find(".line_holder.parallel button[data-line-code='#{code}']").trigger 'click' find(".line_holder.parallel button[data-line-code='#{code}']").click
end end
end end
...@@ -14,7 +14,7 @@ module SharedNote ...@@ -14,7 +14,7 @@ module SharedNote
find('.more-actions').click find('.more-actions').click
find('.more-actions .dropdown-menu li', match: :first) find('.more-actions .dropdown-menu li', match: :first)
find(".js-note-delete").click accept_confirm { find(".js-note-delete").click }
end end
end end
......
require 'capybara/poltergeist'
require 'capybara-screenshot/spinach' require 'capybara-screenshot/spinach'
# Give CI some extra time # Give CI some extra time
timeout = (ENV['CI'] || ENV['CI_SERVER']) ? 60 : 30 timeout = (ENV['CI'] || ENV['CI_SERVER']) ? 60 : 30
Capybara.javascript_driver = :poltergeist Capybara.javascript_driver = :chrome
Capybara.register_driver :poltergeist do |app| Capybara.register_driver :chrome do |app|
Capybara::Poltergeist::Driver.new( extra_args = []
app, extra_args << 'headless' unless ENV['CHROME_HEADLESS'] =~ /^(false|no|0)$/i
js_errors: true,
timeout: timeout, capabilities = Selenium::WebDriver::Remote::Capabilities.chrome(
window_size: [1366, 768], chromeOptions: {
url_whitelist: %w[localhost 127.0.0.1], 'args' => %w[no-sandbox disable-gpu --window-size=1240,1400] + extra_args
url_blacklist: %w[.mp4 .png .gif .avi .bmp .jpg .jpeg], }
phantomjs_options: [
'--load-images=yes'
]
) )
Capybara::Selenium::Driver
.new(app, browser: :chrome, desired_capabilities: capabilities)
end end
Capybara.default_max_wait_time = timeout Capybara.default_max_wait_time = timeout
...@@ -24,6 +23,10 @@ Capybara.ignore_hidden_elements = false ...@@ -24,6 +23,10 @@ Capybara.ignore_hidden_elements = false
# Keep only the screenshots generated from the last failing test suite # Keep only the screenshots generated from the last failing test suite
Capybara::Screenshot.prune_strategy = :keep_last_run Capybara::Screenshot.prune_strategy = :keep_last_run
# From https://github.com/mattheworiordan/capybara-screenshot/issues/84#issuecomment-41219326
Capybara::Screenshot.register_driver(:chrome) do |driver, path|
driver.browser.save_screenshot(path)
end
Spinach.hooks.before_run do Spinach.hooks.before_run do
TestEnv.eager_load_driver_server TestEnv.eager_load_driver_server
......
module CapybaraHelpers
def confirm_modal_if_present
if Capybara.current_driver == Capybara.javascript_driver
accept_confirm { yield }
return
end
yield
end
end
...@@ -46,14 +46,14 @@ module Gitlab ...@@ -46,14 +46,14 @@ module Gitlab
# Returns the current real time in a given precision. # Returns the current real time in a given precision.
# #
# Returns the time as a Float. # Returns the time as a Fixnum.
def self.real_time(precision = :millisecond) def self.real_time(precision = :millisecond)
Process.clock_gettime(Process::CLOCK_REALTIME, precision) Process.clock_gettime(Process::CLOCK_REALTIME, precision)
end end
# Returns the current monotonic clock time in a given precision. # Returns the current monotonic clock time in a given precision.
# #
# Returns the time as a Float. # Returns the time as a Fixnum.
def self.monotonic_time(precision = :millisecond) def self.monotonic_time(precision = :millisecond)
Process.clock_gettime(Process::CLOCK_MONOTONIC, precision) Process.clock_gettime(Process::CLOCK_MONOTONIC, precision)
end end
......
...@@ -36,7 +36,7 @@ module Gitlab ...@@ -36,7 +36,7 @@ module Gitlab
end end
def track_query(raw_query, bindings, start, finish) def track_query(raw_query, bindings, start, finish)
duration = finish - start duration = (finish - start) * 1000.0
query_info = { duration: duration.round(3), sql: raw_query } query_info = { duration: duration.round(3), sql: raw_query }
PEEK_DB_CLIENT.query_details << query_info PEEK_DB_CLIENT.query_details << query_info
......
...@@ -89,9 +89,11 @@ module Gitlab ...@@ -89,9 +89,11 @@ module Gitlab
ActiveSupport::Notifications.subscribe('sql.active_record') do |_, start, finish, _, data| ActiveSupport::Notifications.subscribe('sql.active_record') do |_, start, finish, _, data|
next unless same_thread? next unless same_thread?
unless data.fetch(:cached, data[:name] == 'CACHE')
track_query(data[:sql].strip, data[:binds], start, finish) track_query(data[:sql].strip, data[:binds], start, finish)
end end
end end
end
def subscribe_to_action_view def subscribe_to_action_view
regex = /render_(template|partial)\.action_view/ regex = /render_(template|partial)\.action_view/
......
...@@ -7,6 +7,7 @@ module Gitlab ...@@ -7,6 +7,7 @@ module Gitlab
class RequestBlockerMiddleware class RequestBlockerMiddleware
@@num_active_requests = Concurrent::AtomicFixnum.new(0) @@num_active_requests = Concurrent::AtomicFixnum.new(0)
@@block_requests = Concurrent::AtomicBoolean.new(false) @@block_requests = Concurrent::AtomicBoolean.new(false)
@@slow_requests = Concurrent::AtomicBoolean.new(false)
# Returns the number of requests the server is currently processing. # Returns the number of requests the server is currently processing.
def self.num_active_requests def self.num_active_requests
...@@ -19,9 +20,15 @@ module Gitlab ...@@ -19,9 +20,15 @@ module Gitlab
@@block_requests.value = true @@block_requests.value = true
end end
# Slows down incoming requests (useful for race conditions).
def self.slow_requests!
@@slow_requests.value = true
end
# Allows the server to accept requests again. # Allows the server to accept requests again.
def self.allow_requests! def self.allow_requests!
@@block_requests.value = false @@block_requests.value = false
@@slow_requests.value = false
end end
def initialize(app) def initialize(app)
...@@ -33,6 +40,7 @@ module Gitlab ...@@ -33,6 +40,7 @@ module Gitlab
if block_requests? if block_requests?
block_request(env) block_request(env)
else else
sleep 0.2 if slow_requests?
@app.call(env) @app.call(env)
end end
ensure ensure
...@@ -45,6 +53,10 @@ module Gitlab ...@@ -45,6 +53,10 @@ module Gitlab
@@block_requests.true? @@block_requests.true?
end end
def slow_requests?
@@slow_requests.true?
end
def block_request(env) def block_request(env)
[503, {}, []] [503, {}, []]
end end
......
# rubocop:disable Style/ClassVars
module Gitlab
module Testing
class RequestInspectorMiddleware
@@log_requests = Concurrent::AtomicBoolean.new(false)
@@logged_requests = Concurrent::Array.new
@@inject_headers = Concurrent::Hash.new
# Resets the current request log and starts logging requests
def self.log_requests!(headers = {})
@@inject_headers.replace(headers)
@@logged_requests.replace([])
@@log_requests.value = true
end
# Stops logging requests
def self.stop_logging!
@@log_requests.value = false
end
def self.requests
@@logged_requests
end
def initialize(app)
@app = app
end
def call(env)
return @app.call(env) unless @@log_requests.true?
url = env['REQUEST_URI']
env.merge! http_headers_env(@@inject_headers) if @@inject_headers.any?
request_headers = env_http_headers(env)
status, headers, body = @app.call(env)
request = OpenStruct.new(
url: url,
status_code: status,
request_headers: request_headers,
response_headers: headers
)
log_request request
[status, headers, body]
end
private
def env_http_headers(env)
Hash[*env.select { |k, v| k.start_with? 'HTTP_' }
.collect { |k, v| [k.sub(/^HTTP_/, ''), v] }
.collect { |k, v| [k.split('_').collect(&:capitalize).join('-'), v] }
.sort
.flatten]
end
def http_headers_env(headers)
Hash[*headers
.collect { |k, v| [k.split('-').collect(&:upcase).join('_'), v] }
.collect { |k, v| [k.prepend('HTTP_'), v] }
.flatten]
end
def log_request(response)
@@logged_requests.push(response)
end
end
end
end
require 'spec_helper'
describe LfsRequest do
include ProjectForksHelper
controller(Projects::GitHttpClientController) do
# `described_class` is not available in this context
include LfsRequest # rubocop:disable RSpec/DescribedClass
def show
storage_project
render nothing: true
end
def project
@project ||= Project.find(params[:id])
end
def download_request?
true
end
def ci?
false
end
end
let(:project) { create(:project, :public) }
before do
stub_lfs_setting(enabled: true)
end
describe '#storage_project' do
it 'assigns the project as storage project' do
get :show, id: project.id
expect(assigns(:storage_project)).to eq(project)
end
it 'assigns the source of a forked project' do
forked_project = fork_project(project)
get :show, id: forked_project.id
expect(assigns(:storage_project)).to eq(project)
end
end
end
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