diff options
author | Douwe Maan <douwe@selenight.nl> | 2017-08-31 18:02:19 +0200 |
---|---|---|
committer | Douwe Maan <douwe@selenight.nl> | 2017-08-31 18:02:19 +0200 |
commit | 92edb3edab89dcb7b87bad3ac0fe7fed404fea85 (patch) | |
tree | b96e7b9d37a789ad252ee5c01a6c2811b9bc88d5 | |
parent | 7c215dd23dfa942d6b83252403ce326df96ab3ea (diff) | |
parent | 9aef0427eb9986fc27a399ea6b47e1518d6ebdac (diff) | |
download | gitlab-ce-92edb3edab89dcb7b87bad3ac0fe7fed404fea85.tar.gz |
Merge branch 'master' into issue-discussions-refactor
# Conflicts:
# app/models/issue.rb
140 files changed, 1100 insertions, 626 deletions
diff --git a/.rubocop.yml b/.rubocop.yml index 3edd1643d48..16f2e4484fc 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -624,7 +624,7 @@ Style/PredicateName: # branches, and conditions. Metrics/AbcSize: Enabled: true - Max: 56.96 + Max: 55.25 # This cop checks if the length of a block exceeds some maximum value. Metrics/BlockLength: @@ -665,7 +665,7 @@ Metrics/ParameterLists: # A complexity metric geared towards measuring complexity for a human reader. Metrics/PerceivedComplexity: Enabled: true - Max: 18 + Max: 17 # Lint ######################################################################## diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index be386c9ede3..85e60ed180c 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -0.33.0 +0.34.0 @@ -27,7 +27,7 @@ gem 'doorkeeper-openid_connect', '~> 1.1.0' gem 'omniauth', '~> 1.4.2' gem 'omniauth-auth0', '~> 1.4.1' gem 'omniauth-azure-oauth2', '~> 0.0.6' -gem 'omniauth-cas3', '~> 1.1.2' +gem 'omniauth-cas3', '~> 1.1.4' gem 'omniauth-facebook', '~> 4.0.0' gem 'omniauth-github', '~> 1.1.1' gem 'omniauth-gitlab', '~> 1.0.2' @@ -126,12 +126,9 @@ gem 'wikicloth', '0.8.1' gem 'asciidoctor', '~> 1.5.2' gem 'asciidoctor-plantuml', '0.0.7' gem 'rouge', '~> 2.0' -gem 'truncato', '~> 0.7.8' +gem 'truncato', '~> 0.7.9' gem 'bootstrap_form', '~> 2.7.0' - -# See https://groups.google.com/forum/#!topic/ruby-security-ann/aSbgDiwb24s -# and https://groups.google.com/forum/#!topic/ruby-security-ann/Dy7YiKb_pMM -gem 'nokogiri', '~> 1.6.7', '>= 1.6.7.2' +gem 'nokogiri', '~> 1.8.0' # Diffs gem 'diffy', '~> 3.1.0' @@ -245,7 +242,7 @@ gem 'uglifier', '~> 2.7.2' gem 'addressable', '~> 2.3.8' gem 'bootstrap-sass', '~> 3.3.0' gem 'font-awesome-rails', '~> 4.7' -gem 'gemojione', '~> 3.0' +gem 'gemojione', '~> 3.3' gem 'gon', '~> 6.1.0' gem 'jquery-atwho-rails', '~> 1.3.2' gem 'jquery-rails', '~> 4.1.0' diff --git a/Gemfile.lock b/Gemfile.lock index 3cb458c1707..8634a9e8822 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -261,7 +261,7 @@ GEM ruby-progressbar (~> 1.4) gemnasium-gitlab-service (0.2.6) rugged (~> 0.21) - gemojione (3.0.1) + gemojione (3.3.0) json get_process_mem (0.2.0) gettext (3.2.2) @@ -283,7 +283,7 @@ GEM escape_utils (~> 1.1.0) mime-types (>= 1.19) rugged (>= 0.23.0b) - github-markup (1.4.0) + github-markup (1.6.1) gitlab-flowdock-git-hook (1.0.1) flowdock (~> 0.7) gitlab-grit (>= 2.4.1) @@ -303,13 +303,14 @@ GEM activesupport (>= 4.1.0) gollum-grit_adapter (1.0.1) gitlab-grit (~> 2.7, >= 2.7.1) - gollum-lib (4.2.1) - github-markup (~> 1.4.0) + gollum-lib (4.2.7) + gemojione (~> 3.2) + github-markup (~> 1.6) gollum-grit_adapter (~> 1.0) - nokogiri (~> 1.6.4) - rouge (~> 2.0) - sanitize (~> 2.1.0) - stringex (~> 2.5.1) + nokogiri (>= 1.6.1, < 2.0) + rouge (~> 2.1) + sanitize (~> 2.1) + stringex (~> 2.6) gollum-rugged_adapter (0.4.4) mime-types (>= 1.15) rugged (~> 0.25) @@ -329,7 +330,7 @@ GEM multi_json (~> 1.10) retriable (~> 1.4) signet (~> 0.6) - google-protobuf (3.3.0) + google-protobuf (3.4.0.2) googleauth (0.5.1) faraday (~> 0.9) jwt (~> 1.4) @@ -468,7 +469,7 @@ GEM railties (>= 4, < 5.2) loofah (2.0.3) nokogiri (>= 1.5.9) - mail (2.6.5) + mail (2.6.6) mime-types (>= 1.16, < 4) mail_room (0.9.1) memoist (0.15.0) @@ -477,7 +478,7 @@ GEM method_source (0.8.2) mime-types (2.99.3) mimemagic (0.3.0) - mini_portile2 (2.1.0) + mini_portile2 (2.2.0) minitest (5.7.0) mmap2 (2.2.7) mousetrap-rails (1.4.6) @@ -491,8 +492,8 @@ GEM net-ldap (0.16.0) net-ssh (4.1.0) netrc (0.11.0) - nokogiri (1.6.8.1) - mini_portile2 (~> 2.1.0) + nokogiri (1.8.0) + mini_portile2 (~> 2.2.0) numerizer (0.1.1) oauth (0.5.1) oauth2 (1.4.0) @@ -515,9 +516,9 @@ GEM jwt (~> 1.0) omniauth (~> 1.0) omniauth-oauth2 (~> 1.1) - omniauth-cas3 (1.1.3) + omniauth-cas3 (1.1.4) addressable (~> 2.3) - nokogiri (~> 1.6.6) + nokogiri (~> 1.7, >= 1.7.1) omniauth (~> 1.2) omniauth-facebook (4.0.0) omniauth-oauth2 (~> 1.2) @@ -605,7 +606,7 @@ GEM cliver (~> 0.3.1) multi_json (~> 1.0) websocket-driver (>= 0.2.0) - posix-spawn (0.3.11) + posix-spawn (0.3.13) powerpack (0.1.1) premailer (1.10.4) addressable @@ -871,7 +872,7 @@ GEM state_machines-activerecord (0.4.0) activerecord (>= 4.1, < 5.1) state_machines-activemodel (>= 0.3.0) - stringex (2.5.2) + stringex (2.7.1) sys-filesystem (1.1.6) ffi sysexits (1.2.0) @@ -890,9 +891,9 @@ GEM timfel-krb5-auth (0.8.3) toml-rb (0.3.15) citrus (~> 3.0, > 3.0) - truncato (0.7.8) + truncato (0.7.10) htmlentities (~> 4.3.1) - nokogiri (~> 1.6.1) + nokogiri (~> 1.8.0, >= 1.7.0) tzinfo (1.2.3) thread_safe (~> 0.1) u2f (0.2.1) @@ -1014,7 +1015,7 @@ DEPENDENCIES foreman (~> 0.78.0) fuubar (~> 2.2.0) gemnasium-gitlab-service (~> 0.2) - gemojione (~> 3.0) + gemojione (~> 3.3) gettext (~> 3.2.2) gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails_js (~> 1.2.0) @@ -1060,7 +1061,7 @@ DEPENDENCIES mysql2 (~> 0.4.5) net-ldap net-ssh (~> 4.1.0) - nokogiri (~> 1.6.7, >= 1.6.7.2) + nokogiri (~> 1.8.0) oauth2 (~> 1.4) octokit (~> 4.6.2) oj (~> 2.17.4) @@ -1068,7 +1069,7 @@ DEPENDENCIES omniauth-auth0 (~> 1.4.1) omniauth-authentiq (~> 0.3.1) omniauth-azure-oauth2 (~> 0.0.6) - omniauth-cas3 (~> 1.1.2) + omniauth-cas3 (~> 1.1.4) omniauth-facebook (~> 4.0.0) omniauth-github (~> 1.1.1) omniauth-gitlab (~> 1.0.2) @@ -1159,7 +1160,7 @@ DEPENDENCIES thin (~> 1.7.0) timecop (~> 0.8.0) toml-rb (~> 0.3.15) - truncato (~> 0.7.8) + truncato (~> 0.7.9) u2f (~> 0.2.1) uglifier (~> 2.7.2) unf (~> 0.1.4) diff --git a/app/assets/javascripts/fly_out_nav.js b/app/assets/javascripts/fly_out_nav.js index 32cb42c8b10..81697af189b 100644 --- a/app/assets/javascripts/fly_out_nav.js +++ b/app/assets/javascripts/fly_out_nav.js @@ -1,4 +1,3 @@ -import Cookies from 'js-cookie'; import bp from './breakpoints'; const HIDE_INTERVAL_TIMEOUT = 300; @@ -8,9 +7,11 @@ const IS_SHOWING_FLY_OUT_CLASS = 'is-showing-fly-out'; let currentOpenMenu = null; let menuCornerLocs; let timeoutId; +let sidebar; export const mousePos = []; +export const setSidebar = (el) => { sidebar = el; }; export const setOpenMenu = (menu = null) => { currentOpenMenu = menu; }; export const slope = (a, b) => (b.y - a.y) / (b.x - a.x); @@ -20,10 +21,8 @@ let headerHeight = 50; export const getHeaderHeight = () => headerHeight; export const canShowActiveSubItems = (el) => { - const isHiddenByMedia = bp.getBreakpointSize() === 'sm' || bp.getBreakpointSize() === 'md'; - - if (el.classList.contains('active') && !isHiddenByMedia) { - return Cookies.get('sidebar_collapsed') === 'true'; + if (el.classList.contains('active') && (sidebar && !sidebar.classList.contains('sidebar-icons-only'))) { + return false; } return true; @@ -143,13 +142,13 @@ export const documentMouseMove = (e) => { }; export default () => { - const sidebar = document.querySelector('.sidebar-top-level-items'); + sidebar = document.querySelector('.nav-sidebar'); if (!sidebar) return; const items = [...sidebar.querySelectorAll('.sidebar-top-level-items > li')]; - sidebar.addEventListener('mouseleave', () => { + sidebar.querySelector('.sidebar-top-level-items').addEventListener('mouseleave', () => { clearTimeout(timeoutId); timeoutId = setTimeout(() => { diff --git a/app/assets/javascripts/issue_show/components/edited.vue b/app/assets/javascripts/issue_show/components/edited.vue index d59e6d11032..992b7064c13 100644 --- a/app/assets/javascripts/issue_show/components/edited.vue +++ b/app/assets/javascripts/issue_show/components/edited.vue @@ -37,7 +37,7 @@ export default { Edited <time-ago-tooltip v-if="updatedAt" - placement="bottom" + tooltip-placement="bottom" :time="updatedAt" /> <span diff --git a/app/assets/javascripts/monitoring/components/monitoring.vue b/app/assets/javascripts/monitoring/components/dashboard.vue index a6a2d3119e3..74244faa5d9 100644 --- a/app/assets/javascripts/monitoring/components/monitoring.vue +++ b/app/assets/javascripts/monitoring/components/dashboard.vue @@ -3,8 +3,9 @@ import _ from 'underscore'; import statusCodes from '../../lib/utils/http_status'; import MonitoringService from '../services/monitoring_service'; - import monitoringRow from './monitoring_row.vue'; - import monitoringState from './monitoring_state.vue'; + import GraphGroup from './graph_group.vue'; + import GraphRow from './graph_row.vue'; + import EmptyState from './empty_state.vue'; import MonitoringStore from '../stores/monitoring_store'; import eventHub from '../event_hub'; @@ -31,8 +32,9 @@ }, components: { - monitoringRow, - monitoringState, + GraphGroup, + GraphRow, + EmptyState, }, methods: { @@ -94,7 +96,6 @@ this.updatedAspectRatios = 0; } }, - }, created() { @@ -118,40 +119,27 @@ }, }; </script> + <template> - <div - class="prometheus-graphs" - v-if="!showEmptyState"> - <div - class="row" + <div v-if="!showEmptyState" class="prometheus-graphs"> + <graph-group v-for="(groupData, index) in store.groups" - :key="index"> - <div - class="col-md-12"> - <div - class="panel panel-default prometheus-panel"> - <div - class="panel-heading"> - <h4>{{groupData.group}}</h4> - </div> - <div - class="panel-body"> - <monitoring-row - v-for="(row, index) in groupData.metrics" - :key="index" - :row-data="row" - :update-aspect-ratio="updateAspectRatio" - :deployment-data="store.deploymentData" - /> - </div> - </div> - </div> - </div> + :key="index" + :name="groupData.group" + > + <graph-row + v-for="(row, index) in groupData.metrics" + :key="index" + :row-data="row" + :update-aspect-ratio="updateAspectRatio" + :deployment-data="store.deploymentData" + /> + </graph-group> </div> - <monitoring-state + <empty-state + v-else :selected-state="state" :documentation-path="documentationPath" :settings-path="settingsPath" - v-else /> </template> diff --git a/app/assets/javascripts/monitoring/components/monitoring_state.vue b/app/assets/javascripts/monitoring/components/empty_state.vue index 598021aa4df..a8708be76de 100644 --- a/app/assets/javascripts/monitoring/components/monitoring_state.vue +++ b/app/assets/javascripts/monitoring/components/empty_state.vue @@ -62,49 +62,33 @@ }, }; </script> + <template> - <div - class="prometheus-state"> - <div - class="row"> - <div - class="col-md-4 col-md-offset-4 state-svg" - v-html="currentState.svg"> - </div> + <div class="prometheus-state"> + <div class="row"> + <div class="col-md-4 col-md-offset-4 state-svg" v-html="currentState.svg"></div> </div> - <div - class="row"> - <div - class="col-md-6 col-md-offset-3"> - <h4 - class="text-center state-title"> + <div class="row"> + <div class="col-md-6 col-md-offset-3"> + <h4 class="text-center state-title"> {{currentState.title}} </h4> </div> </div> - <div - class="row"> - <div - class="col-md-6 col-md-offset-3"> - <div - class="description-text text-center state-description"> - {{currentState.description}} - <a - :href="settingsPath" - v-if="showButtonDescription"> - Prometheus server - </a> + <div class="row"> + <div class="col-md-6 col-md-offset-3"> + <div class="description-text text-center state-description"> + {{currentState.description}} + <a v-if="showButtonDescription" :href="settingsPath"> + Prometheus server + </a> </div> </div> </div> - <div - class="row state-button-section"> - <div - class="col-md-4 col-md-offset-4 text-center state-button"> - <a - class="btn btn-success" - :href="buttonPath"> - {{currentState.buttonText}} + <div class="row state-button-section"> + <div class="col-md-4 col-md-offset-4 text-center state-button"> + <a class="btn btn-success" :href="buttonPath"> + {{currentState.buttonText}} </a> </div> </div> diff --git a/app/assets/javascripts/monitoring/components/monitoring_column.vue b/app/assets/javascripts/monitoring/components/graph.vue index a31c26fb4fc..6f6da9e1463 100644 --- a/app/assets/javascripts/monitoring/components/monitoring_column.vue +++ b/app/assets/javascripts/monitoring/components/graph.vue @@ -1,8 +1,8 @@ <script> import d3 from 'd3'; - import monitoringLegends from './monitoring_legends.vue'; - import monitoringFlag from './monitoring_flag.vue'; - import monitoringDeployment from './monitoring_deployment.vue'; + import GraphLegend from './graph/legend.vue'; + import GraphFlag from './graph/flag.vue'; + import GraphDeployment from './graph/deployment.vue'; import MonitoringMixin from '../mixins/monitoring_mixins'; import eventHub from '../event_hub'; import measurements from '../utils/measurements'; @@ -14,7 +14,7 @@ export default { props: { - columnData: { + graphData: { type: Object, required: true, }, @@ -66,9 +66,9 @@ }, components: { - monitoringLegends, - monitoringFlag, - monitoringDeployment, + GraphLegend, + GraphFlag, + GraphDeployment, }, computed: { @@ -97,7 +97,7 @@ methods: { draw() { const breakpointSize = bp.getBreakpointSize(); - const query = this.columnData.queries[0]; + const query = this.graphData.queries[0]; this.margin = measurements.large.margin; if (breakpointSize === 'xs' || breakpointSize === 'sm') { this.graphHeight = 300; @@ -106,7 +106,7 @@ } this.data = query.result[0].values; this.unitOfDisplay = query.unit || ''; - this.yAxisLabel = this.columnData.y_label || 'Values'; + this.yAxisLabel = this.graphData.y_label || 'Values'; this.legendTitle = query.label || 'Average'; this.graphWidth = this.$refs.baseSvg.clientWidth - this.margin.left - this.margin.right; @@ -224,7 +224,7 @@ :class="classType"> <h5 class="text-center graph-title"> - {{columnData.title}} + {{graphData.title}} </h5> <div class="prometheus-svg-container" @@ -240,7 +240,7 @@ class="y-axis" transform="translate(70, 20)"> </g> - <monitoring-legends + <graph-legend :graph-width="graphWidth" :graph-height="graphHeight" :margin="margin" @@ -268,13 +268,13 @@ stroke-width="2" transform="translate(-5, 20)"> </path> - <monitoring-deployment + <graph-deployment :show-deploy-info="showDeployInfo" :deployment-data="reducedDeploymentData" :graph-height="graphHeight" :graph-height-offset="graphHeightOffset" /> - <monitoring-flag + <graph-flag v-if="showFlag" :current-x-coordinate="currentXCoordinate" :current-y-coordinate="currentYCoordinate" diff --git a/app/assets/javascripts/monitoring/components/monitoring_deployment.vue b/app/assets/javascripts/monitoring/components/graph/deployment.vue index dadbcd1aaa6..3623d2ed946 100644 --- a/app/assets/javascripts/monitoring/components/monitoring_deployment.vue +++ b/app/assets/javascripts/monitoring/components/graph/deployment.vue @@ -1,5 +1,5 @@ <script> - import { dateFormat, timeFormat } from '../utils/date_time_formatters'; + import { dateFormat, timeFormat } from '../../utils/date_time_formatters'; export default { props: { diff --git a/app/assets/javascripts/monitoring/components/monitoring_flag.vue b/app/assets/javascripts/monitoring/components/graph/flag.vue index 61cbeeebb17..c4d4647d240 100644 --- a/app/assets/javascripts/monitoring/components/monitoring_flag.vue +++ b/app/assets/javascripts/monitoring/components/graph/flag.vue @@ -1,5 +1,5 @@ <script> - import { dateFormat, timeFormat } from '../utils/date_time_formatters'; + import { dateFormat, timeFormat } from '../../utils/date_time_formatters'; export default { props: { diff --git a/app/assets/javascripts/monitoring/components/monitoring_legends.vue b/app/assets/javascripts/monitoring/components/graph/legend.vue index 922a5e1bf0e..d08f9cbffd4 100644 --- a/app/assets/javascripts/monitoring/components/monitoring_legends.vue +++ b/app/assets/javascripts/monitoring/components/graph/legend.vue @@ -74,7 +74,7 @@ }; </script> <template> - <g + <g class="axis-label-container"> <line class="label-x-axis-line" @@ -100,7 +100,7 @@ :width="yLabelWidth" :height="yLabelHeight"> </rect> - <text + <text class="label-axis-text y-label-text" text-anchor="middle" :transform="textTransform" diff --git a/app/assets/javascripts/monitoring/components/graph_group.vue b/app/assets/javascripts/monitoring/components/graph_group.vue new file mode 100644 index 00000000000..32c90fda8cc --- /dev/null +++ b/app/assets/javascripts/monitoring/components/graph_group.vue @@ -0,0 +1,21 @@ +<script> +export default { + props: { + name: { + type: String, + required: true, + }, + }, +}; +</script> + +<template> + <div class="panel panel-default prometheus-panel"> + <div class="panel-heading"> + <h4>{{name}}</h4> + </div> + <div class="panel-body"> + <slot /> + </div> + </div> +</template> diff --git a/app/assets/javascripts/monitoring/components/monitoring_row.vue b/app/assets/javascripts/monitoring/components/graph_row.vue index e5528f17880..bdb9149c3b4 100644 --- a/app/assets/javascripts/monitoring/components/monitoring_row.vue +++ b/app/assets/javascripts/monitoring/components/graph_row.vue @@ -1,5 +1,5 @@ <script> - import monitoringColumn from './monitoring_column.vue'; + import Graph from './graph.vue'; export default { props: { @@ -17,7 +17,7 @@ }, }, components: { - monitoringColumn, + Graph, }, computed: { bootstrapClass() { @@ -26,12 +26,12 @@ }, }; </script> + <template> - <div - class="prometheus-row row"> - <monitoring-column - v-for="(column, index) in rowData" - :column-data="column" + <div class="prometheus-row row"> + <graph + v-for="(graphData, index) in rowData" + :graph-data="graphData" :class-type="bootstrapClass" :key="index" :update-aspect-ratio="updateAspectRatio" diff --git a/app/assets/javascripts/monitoring/monitoring_bundle.js b/app/assets/javascripts/monitoring/monitoring_bundle.js index 5d5cb56af72..ef280e02092 100644 --- a/app/assets/javascripts/monitoring/monitoring_bundle.js +++ b/app/assets/javascripts/monitoring/monitoring_bundle.js @@ -1,10 +1,10 @@ import Vue from 'vue'; -import Monitoring from './components/monitoring.vue'; +import Dashboard from './components/dashboard.vue'; document.addEventListener('DOMContentLoaded', () => new Vue({ el: '#prometheus-graphs', components: { - 'monitoring-dashboard': Monitoring, + Dashboard, }, - render: createElement => createElement('monitoring-dashboard'), + render: createElement => createElement('dashboard'), })); diff --git a/app/assets/javascripts/project_select_combo_button.js b/app/assets/javascripts/project_select_combo_button.js index 46a26fb91f4..99cea683d9a 100644 --- a/app/assets/javascripts/project_select_combo_button.js +++ b/app/assets/javascripts/project_select_combo_button.js @@ -14,7 +14,14 @@ export default class ProjectSelectComboButton { bindEvents() { this.projectSelectInput.siblings('.new-project-item-select-button') - .on('click', this.openDropdown); + .on('click', e => this.openDropdown(e)); + + this.newItemBtn.on('click', (e) => { + if (!this.getProjectFromLocalStorage()) { + e.preventDefault(); + this.openDropdown(e); + } + }); this.projectSelectInput.on('change', () => this.selectProject()); } @@ -28,8 +35,9 @@ export default class ProjectSelectComboButton { } } - openDropdown() { - $(this).siblings('.project-item-select').select2('open'); + // eslint-disable-next-line class-methods-use-this + openDropdown(event) { + $(event.currentTarget).siblings('.project-item-select').select2('open'); } selectProject() { @@ -56,10 +64,8 @@ export default class ProjectSelectComboButton { if (project) { this.newItemBtn.attr('href', project.url); this.newItemBtn.text(`${this.formattedText.defaultTextPrefix} in ${project.name}`); - this.newItemBtn.enable(); } else { this.newItemBtn.text(`Select project to create ${this.formattedText.presetTextSuffix}`); - this.newItemBtn.disable(); } } diff --git a/app/assets/javascripts/vue_shared/components/commit.vue b/app/assets/javascripts/vue_shared/components/commit.vue index 262584769e0..50d14282cad 100644 --- a/app/assets/javascripts/vue_shared/components/commit.vue +++ b/app/assets/javascripts/vue_shared/components/commit.vue @@ -1,6 +1,7 @@ <script> import commitIconSvg from 'icons/_icon_commit.svg'; import userAvatarLink from './user_avatar/user_avatar_link.vue'; + import tooltip from '../directives/tooltip'; export default { props: { @@ -100,17 +101,22 @@ this.author.username ? `${this.author.username}'s avatar` : null; }, }, - data() { - return { commitIconSvg }; + directives: { + tooltip, }, components: { userAvatarLink, }, + created() { + this.commitIconSvg = commitIconSvg; + }, }; </script> <template> <div class="branch-commit"> - <div v-if="hasCommitRef" class="icon-container hidden-xs"> + <div + v-if="hasCommitRef" + class="icon-container hidden-xs"> <i v-if="tag" class="fa fa-tag" @@ -126,7 +132,10 @@ <a v-if="hasCommitRef" class="ref-name hidden-xs" - :href="commitRef.ref_url"> + :href="commitRef.ref_url" + v-tooltip + data-container="body" + :title="commitRef.name"> {{commitRef.name}} </a> @@ -153,7 +162,8 @@ :img-alt="userImageAltDescription" :tooltip-text="author.username" /> - <a class="commit-row-message" + <a + class="commit-row-message" :href="commitUrl"> {{title}} </a> diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss index f79261dfd61..27d9d17bfc4 100644 --- a/app/assets/stylesheets/framework/dropdowns.scss +++ b/app/assets/stylesheets/framework/dropdowns.scss @@ -189,7 +189,7 @@ width: auto; top: 100%; left: 0; - z-index: 9; + z-index: 200; min-width: 240px; max-width: 500px; margin-top: 2px; @@ -801,3 +801,5 @@ margin-top: 2px; } } + +@include new-style-dropdown('.js-namespace-select + '); diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss index 8018eb8ba84..a39927eb0df 100644 --- a/app/assets/stylesheets/framework/selects.scss +++ b/app/assets/stylesheets/framework/selects.scss @@ -267,6 +267,7 @@ // TODO: change global style .ajax-project-dropdown, +body[data-page="projects:new"] #select2-drop, body[data-page="projects:blob:new"] #select2-drop, body[data-page="profiles:show"] #select2-drop, body[data-page="projects:blob:edit"] #select2-drop { diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index 334bec8dd7e..9d51c0b7a8a 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -612,6 +612,8 @@ } .mr-version-controls { + @include new-style-dropdown; + position: relative; background: $gray-light; color: $gl-text-color; diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index fa1bc72560e..a99563b7100 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -117,11 +117,14 @@ class Admin::UsersController < Admin::ApplicationController user_params_with_pass = user_params.dup if params[:user][:password].present? - user_params_with_pass.merge!( + password_params = { password: params[:user][:password], - password_confirmation: params[:user][:password_confirmation], - password_expires_at: Time.now - ) + password_confirmation: params[:user][:password_confirmation] + } + + password_params[:password_expires_at] = Time.now unless changing_own_password? + + user_params_with_pass.merge!(password_params) end respond_to do |format| @@ -167,6 +170,10 @@ class Admin::UsersController < Admin::ApplicationController protected + def changing_own_password? + user == current_user + end + def user @user ||= User.find_by!(username: params[:id]) end diff --git a/app/controllers/concerns/requires_whitelisted_monitoring_client.rb b/app/controllers/concerns/requires_whitelisted_monitoring_client.rb index ad2f4bbc486..0218ac83441 100644 --- a/app/controllers/concerns/requires_whitelisted_monitoring_client.rb +++ b/app/controllers/concerns/requires_whitelisted_monitoring_client.rb @@ -1,5 +1,8 @@ module RequiresWhitelistedMonitoringClient extend ActiveSupport::Concern + + include Gitlab::CurrentSettings + included do before_action :validate_ip_whitelisted_or_valid_token! end diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb index 221e01b415a..d7dd8ddcb7d 100644 --- a/app/controllers/projects/application_controller.rb +++ b/app/controllers/projects/application_controller.rb @@ -94,6 +94,6 @@ class Projects::ApplicationController < ApplicationController end def require_pages_enabled! - not_found unless Gitlab.config.pages.enabled + not_found unless @project.pages_available? end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 07775a8b159..36bb7015fa1 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -202,7 +202,7 @@ module ApplicationHelper end def support_url - current_application_settings.help_page_support_url.presence || promo_url + '/getting-help/' + Gitlab::CurrentSettings.current_application_settings.help_page_support_url.presence || promo_url + '/getting-help/' end def page_filter_path(options = {}) diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 3b76da238e0..04955ed625e 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -1,5 +1,8 @@ module ApplicationSettingsHelper extend self + + include Gitlab::CurrentSettings + delegate :gravatar_enabled?, :signup_enabled?, :password_authentication_enabled?, diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb index 9c71d6c7f4c..66dc0b1e6f7 100644 --- a/app/helpers/auth_helper.rb +++ b/app/helpers/auth_helper.rb @@ -1,4 +1,6 @@ module AuthHelper + include Gitlab::CurrentSettings + PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2 facebook azure_oauth2 authentiq).freeze FORM_BASED_PROVIDERS = [/\Aldap/, 'crowd'].freeze diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index bee4950e414..c5490a2d1a8 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -1,4 +1,6 @@ module ProjectsHelper + include Gitlab::CurrentSettings + def link_to_project(project) link_to [project.namespace.becomes(Namespace), project], title: h(project.name) do title = content_tag(:span, project.name, class: 'project-name') diff --git a/app/mailers/base_mailer.rb b/app/mailers/base_mailer.rb index 654468bc7fe..8e99db444d6 100644 --- a/app/mailers/base_mailer.rb +++ b/app/mailers/base_mailer.rb @@ -1,11 +1,13 @@ class BaseMailer < ActionMailer::Base + include Gitlab::CurrentSettings + around_action :render_with_default_locale helper ApplicationHelper helper MarkupHelper attr_accessor :current_user - helper_method :current_user, :can? + helper_method :current_user, :can?, :current_application_settings default from: proc { default_sender_address.format } default reply_to: proc { default_reply_to_address.format } diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 095192e9894..8adaafe6439 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -387,7 +387,9 @@ module Ci [ { key: 'GITLAB_USER_ID', value: user.id.to_s, public: true }, - { key: 'GITLAB_USER_EMAIL', value: user.email, public: true } + { key: 'GITLAB_USER_EMAIL', value: user.email, public: true }, + { key: 'GITLAB_USER_LOGIN', value: user.username, public: true }, + { key: 'GITLAB_USER_NAME', value: user.name, public: true } ] end diff --git a/app/models/concerns/spammable.rb b/app/models/concerns/spammable.rb index f2707022a4b..731d9b9a745 100644 --- a/app/models/concerns/spammable.rb +++ b/app/models/concerns/spammable.rb @@ -28,7 +28,7 @@ module Spammable def submittable_as_spam? if user_agent_detail - user_agent_detail.submittable? && current_application_settings.akismet_enabled + user_agent_detail.submittable? && Gitlab::CurrentSettings.current_application_settings.akismet_enabled else false end diff --git a/app/models/issue.rb b/app/models/issue.rb index 5820e57e531..8c7d492e605 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -273,7 +273,13 @@ class Issue < ActiveRecord::Base true end + def update_project_counter_caches? + state_changed? || confidential_changed? + end + def update_project_counter_caches + return unless update_project_counter_caches? + Projects::OpenIssuesCountService.new(project).refresh_cache end diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 5be2f6d4e82..ca3a1806ee8 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -942,7 +942,13 @@ class MergeRequest < ActiveRecord::Base true end + def update_project_counter_caches? + state_changed? + end + def update_project_counter_caches + return unless update_project_counter_caches? + Projects::OpenMergeRequestsCountService.new(target_project).refresh_cache end diff --git a/app/models/namespace.rb b/app/models/namespace.rb index e7bc1d1b080..e7cbc5170e8 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -195,6 +195,10 @@ class Namespace < ActiveRecord::Base parent.present? end + def subgroup? + has_parent? + end + def soft_delete_without_removing_associations # We can't use paranoia's `#destroy` since this will hard-delete projects. # Project uses `pending_delete` instead of the acts_as_paranoia gem. diff --git a/app/models/project.rb b/app/models/project.rb index 9d7bea4eb66..5b4904a5c51 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -19,6 +19,7 @@ class Project < ActiveRecord::Base include Routable extend Gitlab::ConfigHelper + extend Gitlab::CurrentSettings BoardLimitExceeded = Class.new(StandardError) @@ -1231,6 +1232,10 @@ class Project < ActiveRecord::Base File.join(pages_path, 'public') end + def pages_available? + Gitlab.config.pages.enabled && !namespace.subgroup? + end + def remove_private_deploy_keys exclude_keys_linked_to_other_projects = <<-SQL NOT EXISTS ( diff --git a/app/models/protected_branch.rb b/app/models/protected_branch.rb index 5f0d0802ac9..89bfc5f9a9c 100644 --- a/app/models/protected_branch.rb +++ b/app/models/protected_branch.rb @@ -2,6 +2,8 @@ class ProtectedBranch < ActiveRecord::Base include Gitlab::ShellAdapter include ProtectedRef + extend Gitlab::CurrentSettings + protected_ref_access_levels :merge, :push # Check if branch name is marked as protected in the system diff --git a/app/models/repository.rb b/app/models/repository.rb index d29d2a83708..b3fa51a14f7 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -1044,7 +1044,7 @@ class Repository end def fetch_remote(remote, forced: false, no_tags: false) - gitlab_shell.fetch_remote(repository_storage_path, disk_path, remote, forced: forced, no_tags: no_tags) + gitlab_shell.fetch_remote(raw_repository, remote, forced: forced, no_tags: no_tags) end def fetch_ref(source_path, source_ref, target_ref) diff --git a/app/models/snippet.rb b/app/models/snippet.rb index 09d5ff46618..9533aa7f555 100644 --- a/app/models/snippet.rb +++ b/app/models/snippet.rb @@ -10,6 +10,8 @@ class Snippet < ActiveRecord::Base include Spammable include Editable + extend Gitlab::CurrentSettings + cache_markdown_field :title, pipeline: :single_line cache_markdown_field :description cache_markdown_field :content diff --git a/app/models/user.rb b/app/models/user.rb index 70787de4b40..78e7c750c3b 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -2,6 +2,7 @@ require 'carrierwave/orm/activerecord' class User < ActiveRecord::Base extend Gitlab::ConfigHelper + extend Gitlab::CurrentSettings include Gitlab::ConfigHelper include Gitlab::CurrentSettings diff --git a/app/policies/base_policy.rb b/app/policies/base_policy.rb index a605a3457c8..8fa7b2753c7 100644 --- a/app/policies/base_policy.rb +++ b/app/policies/base_policy.rb @@ -1,8 +1,6 @@ require_dependency 'declarative_policy' class BasePolicy < DeclarativePolicy::Base - include Gitlab::CurrentSettings - desc "User is an instance admin" with_options scope: :user, score: 0 condition(:admin) { @user&.admin? } @@ -15,6 +13,6 @@ class BasePolicy < DeclarativePolicy::Base desc "The application is restricted from public visibility" condition(:restricted_public_level, scope: :global) do - current_application_settings.restricted_visibility_levels.include?(Gitlab::VisibilityLevel::PUBLIC) + Gitlab::CurrentSettings.current_application_settings.restricted_visibility_levels.include?(Gitlab::VisibilityLevel::PUBLIC) end end diff --git a/app/services/akismet_service.rb b/app/services/akismet_service.rb index 7b5482b3cd1..aa6f0e841c9 100644 --- a/app/services/akismet_service.rb +++ b/app/services/akismet_service.rb @@ -1,4 +1,6 @@ class AkismetService + include Gitlab::CurrentSettings + attr_accessor :owner, :text, :options def initialize(owner, text, options = {}) diff --git a/app/services/auth/container_registry_authentication_service.rb b/app/services/auth/container_registry_authentication_service.rb index 7dae5880931..9a636346899 100644 --- a/app/services/auth/container_registry_authentication_service.rb +++ b/app/services/auth/container_registry_authentication_service.rb @@ -1,6 +1,6 @@ module Auth class ContainerRegistryAuthenticationService < BaseService - include Gitlab::CurrentSettings + extend Gitlab::CurrentSettings AUDIENCE = 'container_registry'.freeze diff --git a/app/services/projects/update_pages_service.rb b/app/services/projects/update_pages_service.rb index 394b336a638..f6b83a2f621 100644 --- a/app/services/projects/update_pages_service.rb +++ b/app/services/projects/update_pages_service.rb @@ -1,5 +1,7 @@ module Projects class UpdatePagesService < BaseService + include Gitlab::CurrentSettings + BLOCK_SIZE = 32.kilobytes MAX_SIZE = 1.terabyte SITE_PATH = 'public/'.freeze diff --git a/app/services/upload_service.rb b/app/services/upload_service.rb index 6c5b2baff41..76700dfcdee 100644 --- a/app/services/upload_service.rb +++ b/app/services/upload_service.rb @@ -1,4 +1,6 @@ class UploadService + include Gitlab::CurrentSettings + def initialize(model, file, uploader_class = FileUploader) @model, @file, @uploader_class = model, file, uploader_class end diff --git a/app/services/users/build_service.rb b/app/services/users/build_service.rb index ff234a3440f..6f05500adea 100644 --- a/app/services/users/build_service.rb +++ b/app/services/users/build_service.rb @@ -1,5 +1,7 @@ module Users class BuildService < BaseService + include Gitlab::CurrentSettings + def initialize(current_user, params = {}) @current_user = current_user @params = params.dup diff --git a/app/views/layouts/nav/_new_project_sidebar.html.haml b/app/views/layouts/nav/_new_project_sidebar.html.haml index 53dbf9e2f2b..f5361c7af0c 100644 --- a/app/views/layouts/nav/_new_project_sidebar.html.haml +++ b/app/views/layouts/nav/_new_project_sidebar.html.haml @@ -208,7 +208,7 @@ = link_to project_settings_ci_cd_path(@project), title: 'CI / CD' do %span CI / CD - - if Gitlab.config.pages.enabled + - if @project.pages_available? = nav_link(controller: :pages) do = link_to project_pages_path(@project), title: 'Pages' do %span diff --git a/app/views/projects/settings/_head.html.haml b/app/views/projects/settings/_head.html.haml index 15ba09b10ba..7d24c6a9122 100644 --- a/app/views/projects/settings/_head.html.haml +++ b/app/views/projects/settings/_head.html.haml @@ -23,7 +23,7 @@ = link_to project_settings_ci_cd_path(@project), title: 'Pipelines' do %span Pipelines - - if Gitlab.config.pages.enabled + - if @project.pages_available? = nav_link(controller: :pages) do = link_to project_pages_path(@project), title: 'Pages' do %span diff --git a/changelogs/unreleased/26692-predefined-variable-gitlab-user-name.yml b/changelogs/unreleased/26692-predefined-variable-gitlab-user-name.yml new file mode 100644 index 00000000000..fa1ca3d25b2 --- /dev/null +++ b/changelogs/unreleased/26692-predefined-variable-gitlab-user-name.yml @@ -0,0 +1,5 @@ +--- +title: Add CI/CD job predefined variables with user name and login +merge_request: 13824 +author: +type: added diff --git a/changelogs/unreleased/28202_decrease_abc_threshold_step3.yml b/changelogs/unreleased/28202_decrease_abc_threshold_step3.yml new file mode 100644 index 00000000000..ed38fd37103 --- /dev/null +++ b/changelogs/unreleased/28202_decrease_abc_threshold_step3.yml @@ -0,0 +1,5 @@ +--- +title: Decrease ABC threshold to 55.25 +merge_request: 13904 +author: Maxim Rydkin +type: other diff --git a/changelogs/unreleased/28938-password-change-workflow-for-admins.yml b/changelogs/unreleased/28938-password-change-workflow-for-admins.yml new file mode 100644 index 00000000000..0781e1a2fce --- /dev/null +++ b/changelogs/unreleased/28938-password-change-workflow-for-admins.yml @@ -0,0 +1,5 @@ +--- +title: Changes the password change workflow for admins. +merge_request: 13901 +author: +type: fixed diff --git a/changelogs/unreleased/31470-fix-api-files-raw.yml b/changelogs/unreleased/31470-fix-api-files-raw.yml new file mode 100644 index 00000000000..271a945a998 --- /dev/null +++ b/changelogs/unreleased/31470-fix-api-files-raw.yml @@ -0,0 +1,5 @@ +--- +title: Fix the /projects/:id/repository/files/:file_path/raw endpoint to handle dots in the file_path +merge_request: 13512 +author: mahcsig +type: fixed diff --git a/changelogs/unreleased/36917-branch-tooltip.yml b/changelogs/unreleased/36917-branch-tooltip.yml new file mode 100644 index 00000000000..2d37de50cec --- /dev/null +++ b/changelogs/unreleased/36917-branch-tooltip.yml @@ -0,0 +1,5 @@ +--- +title: Adds tooltip to the branch name and improves performance +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/37179-dashboard-project-dropdown.yml b/changelogs/unreleased/37179-dashboard-project-dropdown.yml new file mode 100644 index 00000000000..3ef080b8eae --- /dev/null +++ b/changelogs/unreleased/37179-dashboard-project-dropdown.yml @@ -0,0 +1,5 @@ +--- +title: Removes disabled state from dashboard project button +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/fix-gem-security-updates.yml b/changelogs/unreleased/fix-gem-security-updates.yml new file mode 100644 index 00000000000..dce11d08402 --- /dev/null +++ b/changelogs/unreleased/fix-gem-security-updates.yml @@ -0,0 +1,5 @@ +--- +title: Upgrade mail and nokogiri gems due to security issues +merge_request: 13662 +author: Markus Koller +type: security diff --git a/changelogs/unreleased/mk-default-ldap-verify-certificates-secure.yml b/changelogs/unreleased/mk-default-ldap-verify-certificates-secure.yml new file mode 100644 index 00000000000..865b57fb284 --- /dev/null +++ b/changelogs/unreleased/mk-default-ldap-verify-certificates-secure.yml @@ -0,0 +1,5 @@ +--- +title: Default LDAP config "verify_certificates" to true for security +merge_request: 13915 +author: +type: changed diff --git a/changelogs/unreleased/sh-filter-csrf-params.yml b/changelogs/unreleased/sh-filter-csrf-params.yml new file mode 100644 index 00000000000..70eb3321e77 --- /dev/null +++ b/changelogs/unreleased/sh-filter-csrf-params.yml @@ -0,0 +1,5 @@ +--- +title: Filter additional secrets from Rails logs +merge_request: +author: +type: security diff --git a/changelogs/unreleased/sidebar-cache-updates.yml b/changelogs/unreleased/sidebar-cache-updates.yml new file mode 100644 index 00000000000..aebe53ba5b2 --- /dev/null +++ b/changelogs/unreleased/sidebar-cache-updates.yml @@ -0,0 +1,5 @@ +--- +title: Only update the sidebar count caches when needed +merge_request: +author: +type: other diff --git a/changelogs/unreleased/zj-disable-pages-in-subgroups.yml b/changelogs/unreleased/zj-disable-pages-in-subgroups.yml new file mode 100644 index 00000000000..22c36214e1f --- /dev/null +++ b/changelogs/unreleased/zj-disable-pages-in-subgroups.yml @@ -0,0 +1,5 @@ +--- +title: Remove pages settings when not available +merge_request: +author: +type: changed diff --git a/config/application.rb b/config/application.rb index f69dab4de39..32a290f2002 100644 --- a/config/application.rb +++ b/config/application.rb @@ -51,31 +51,24 @@ module Gitlab # Configure sensitive parameters which will be filtered from the log file. # # Parameters filtered: - # - Password (:password, :password_confirmation) - # - Private tokens + # - Any parameter ending with `_token` + # - Any parameter containing `password` + # - Any parameter containing `secret` # - Two-factor tokens (:otp_attempt) # - Repo/Project Import URLs (:import_url) # - Build variables (:variables) # - GitLab Pages SSL cert/key info (:certificate, :encrypted_key) # - Webhook URLs (:hook) - # - GitLab-shell secret token (:secret_token) # - Sentry DSN (:sentry_dsn) # - Deploy keys (:key) + config.filter_parameters += [/_token$/, /password/, /secret/] config.filter_parameters += %i( - authentication_token certificate encrypted_key hook import_url - incoming_email_token - rss_token key otp_attempt - password - password_confirmation - private_token - runners_token - secret_token sentry_dsn variables ) diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 25285525846..545c01e1156 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -273,9 +273,8 @@ production: &base encryption: 'plain' # Enables SSL certificate verification if encryption method is - # "start_tls" or "simple_tls". (Defaults to false for backward- - # compatibility) - verify_certificates: false + # "start_tls" or "simple_tls". Defaults to true. + verify_certificates: true # Specifies the path to a file containing a PEM-format CA certificate, # e.g. if you need to use an internal CA. diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index abaabad5d65..360b72cdea3 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -155,18 +155,11 @@ if Settings.ldap['enabled'] || Rails.env.test? server['encryption'] = 'simple_tls' if server['encryption'] == 'ssl' server['encryption'] = 'start_tls' if server['encryption'] == 'tls' - # Certificates are not verified for backwards compatibility. - # This default should be flipped to true in 9.5. - if server['verify_certificates'].nil? - server['verify_certificates'] = false - - message = <<-MSG.strip_heredoc - LDAP SSL certificate verification is disabled for backwards-compatibility. - Please add the "verify_certificates" option to gitlab.yml for each LDAP - server. Certificate verification will be enabled by default in GitLab 9.5. - MSG - Rails.logger.warn(message) - end + # Certificate verification was added in 9.4.2, and defaulted to false for + # backwards-compatibility. + # + # Since GitLab 10.0, verify_certificates defaults to true for security. + server['verify_certificates'] = true if server['verify_certificates'].nil? Settings.ldap['servers'][key] = server end diff --git a/config/initializers/sentry.rb b/config/initializers/sentry.rb index 6b0cff75653..62d0967009a 100644 --- a/config/initializers/sentry.rb +++ b/config/initializers/sentry.rb @@ -1,19 +1,18 @@ # Be sure to restart your server when you modify this file. require 'gitlab/current_settings' -include Gitlab::CurrentSettings if Rails.env.production? # allow it to fail: it may do so when create_from_defaults is executed before migrations are actually done begin - sentry_enabled = current_application_settings.sentry_enabled + sentry_enabled = Gitlab::CurrentSettings.current_application_settings.sentry_enabled rescue sentry_enabled = false end if sentry_enabled Raven.configure do |config| - config.dsn = current_application_settings.sentry_dsn + config.dsn = Gitlab::CurrentSettings.current_application_settings.sentry_dsn config.release = Gitlab::REVISION # Sanitize fields based on those sanitized from Rails. diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb index e8213ac8ba4..f2fde1e0048 100644 --- a/config/initializers/session_store.rb +++ b/config/initializers/session_store.rb @@ -1,11 +1,10 @@ # Be sure to restart your server when you modify this file. require 'gitlab/current_settings' -include Gitlab::CurrentSettings # allow it to fail: it may do so when create_from_defaults is executed before migrations are actually done begin - Settings.gitlab['session_expire_delay'] = current_application_settings.session_expire_delay || 10080 + Settings.gitlab['session_expire_delay'] = Gitlab::CurrentSettings.current_application_settings.session_expire_delay || 10080 rescue Settings.gitlab['session_expire_delay'] ||= 10080 end diff --git a/doc/administration/auth/ldap.md b/doc/administration/auth/ldap.md index 425c924cdf2..d22815dfa5e 100644 --- a/doc/administration/auth/ldap.md +++ b/doc/administration/auth/ldap.md @@ -87,9 +87,12 @@ main: # 'main' is the GitLab 'provider ID' of this LDAP server encryption: 'plain' # Enables SSL certificate verification if encryption method is - # "start_tls" or "simple_tls". (Defaults to false for backward- - # compatibility) - verify_certificates: false + # "start_tls" or "simple_tls". Defaults to true since GitLab 10.0 for + # security. This may break installations upon upgrade to 10.0, that did + # not know their LDAP SSL certificates were not setup properly. For + # example, when using self-signed certificates, the ca_file path may + # need to be specified. + verify_certificates: true # Specifies the path to a file containing a PEM-format CA certificate, # e.g. if you need to use an internal CA. diff --git a/doc/ci/ssh_keys/README.md b/doc/ci/ssh_keys/README.md index cf25a8b618f..cdb9858e179 100644 --- a/doc/ci/ssh_keys/README.md +++ b/doc/ci/ssh_keys/README.md @@ -42,7 +42,7 @@ It is also good practice to check the server's own public key to make sure you are not being targeted by a man-in-the-middle attack. To do this, add another variable named `SSH_SERVER_HOSTKEYS`. To find out the hostkeys of your server, run the `ssh-keyscan YOUR_SERVER` command from a trusted network (ideally, from the -server itself), and paste its output into the `SSH_SERVER_HOSTKEY` variable. If +server itself), and paste its output into the `SSH_SERVER_HOSTKEYS` variable. If you need to connect to multiple servers, concatenate all the server public keys that you collected into the **Value** of the variable. There must be one key per line. diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md index 234dc530db0..6513b31826a 100644 --- a/doc/ci/variables/README.md +++ b/doc/ci/variables/README.md @@ -78,6 +78,8 @@ future GitLab releases.** | **GITLAB_CI** | all | all | Mark that job is executed in GitLab CI environment | | **GITLAB_USER_ID** | 8.12 | all | The id of the user who started the job | | **GITLAB_USER_EMAIL** | 8.12 | all | The email of the user who started the job | +| **GITLAB_USER_LOGIN** | 10.0 | all | The login username of the user who started the job | +| **GITLAB_USER_NAME** | 10.0 | all | The real name of the user who started the job | | **RESTORE_CACHE_ATTEMPTS** | 8.15 | 1.9 | Number of attempts to restore the cache running a job | ## 9.0 Renaming diff --git a/doc/install/kubernetes/gitlab_chart.md b/doc/install/kubernetes/gitlab_chart.md index 81057736e3a..6bcc58bb805 100644 --- a/doc/install/kubernetes/gitlab_chart.md +++ b/doc/install/kubernetes/gitlab_chart.md @@ -1,7 +1,7 @@ # GitLab Helm Chart -> These Helm charts are in beta. GitLab is working on a [cloud-native](http://docs.gitlab.com/omnibus/package-information/cloud_native.html) set of [Charts](https://gitlab.com/charts/helm.gitlab.io) which will replace these. - -> Officially supported cloud providers are Google Container Service and Azure Container Service. +> **Note:** +* GitLab is working on a [cloud native set of Charts](https://gitlab.com/charts/helm.gitlab.io/blob/master/README.md) which will replace these. +* Officially supported cloud providers are Google Container Service and Azure Container Service. The `gitlab` Helm chart deploys GitLab into your Kubernetes cluster. @@ -22,9 +22,7 @@ This chart includes the following: - [Persistent Volume](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) provisioner support in the underlying infrastructure - The ability to point a DNS entry or URL at your GitLab install - The `kubectl` CLI installed locally and authenticated for the cluster -- The Helm Client installed locally -- The Helm Server (Tiller) already installed and running in the cluster, by running `helm init` -- The GitLab Helm Repo [added to your Helm Client](index.md#add-the-gitlab-helm-repository) +- The [Helm client](https://github.com/kubernetes/helm/blob/master/docs/quickstart.md) installed locally on your machine ## Configuring GitLab @@ -428,7 +426,7 @@ ingress: ## Installing GitLab using the Helm Chart > You may see a temporary error message `SchedulerPredicates failed due to PersistentVolumeClaim is not bound` while storage provisions. Once the storage provisions, the pods will automatically restart. This may take a couple minutes depending on your cloud provider. If the error persists, please review the [prerequisites](#prerequisites) to ensure you have enough RAM, CPU, and storage. -Ensure the GitLab repo has been added and re-initialize Helm: +Add the GitLab Helm repository and initialize Helm: ```bash helm repo add gitlab https://charts.gitlab.io diff --git a/doc/install/kubernetes/gitlab_omnibus.md b/doc/install/kubernetes/gitlab_omnibus.md index 05e0a59ffeb..8636ce2507c 100644 --- a/doc/install/kubernetes/gitlab_omnibus.md +++ b/doc/install/kubernetes/gitlab_omnibus.md @@ -1,7 +1,8 @@ # GitLab-Omnibus Helm Chart -> These Helm charts are in beta. GitLab is working on a [cloud-native](http://docs.gitlab.com/omnibus/package-information/cloud_native.html) set of [Charts](https://gitlab.com/charts/helm.gitlab.io) which will replace these. - -> Officially supported cloud providers are Google Container Service and Azure Container Service. +> **Note:** +* This Helm chart is in beta, while [additional features](https://gitlab.com/charts/charts.gitlab.io/issues/68) are being worked on. +* GitLab is working on a [cloud native set of Charts](https://gitlab.com/charts/helm.gitlab.io/blob/master/README.md) which will eventually replace these. +* Officially supported cloud providers are Google Container Service and Azure Container Service. This work is based partially on: https://github.com/lwolf/kubernetes-gitlab/. GitLab would like to thank Sergey Nuzhdin for his work. @@ -29,53 +30,51 @@ Terms: ## Prerequisites -- _At least_ 4 GB of RAM available on your cluster, in chunks of 1 GB. 41GB of storage and 2 CPU are also required. +- _At least_ 4 GB of RAM available on your cluster. 41GB of storage and 2 CPU are also required. - Kubernetes 1.4+ with Beta APIs enabled - [Persistent Volume](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) provisioner support in the underlying infrastructure -- An [external IP address](#networking-prerequisites) - A [wildcard DNS entry](#networking-prerequisites), which resolves to the external IP address - The `kubectl` CLI installed locally and authenticated for the cluster -- The Helm Client installed locally -- The Helm Server (Tiller) already installed and running in the cluster, by running `helm init` -- The GitLab Helm Repo [added to your Helm Client](index.md#add-the-gitlab-helm-repository) +- The [Helm client](https://github.com/kubernetes/helm/blob/master/docs/quickstart.md) installed locally on your machine ### Networking Prerequisites This chart configures a GitLab server and Kubernetes cluster which can support dynamic [Review Apps](https://docs.gitlab.com/ee/ci/review_apps/index.html), as well as services like the integrated [Container Registry](https://docs.gitlab.com/ee/user/project/container_registry.html) and [Mattermost](https://docs.gitlab.com/omnibus/gitlab-mattermost/). -To support the GitLab services and dynamic environments, a wildcard DNS entry is required which resolves to the external Load Balancer IP. +To support the GitLab services and dynamic environments, a wildcard DNS entry is required which resolves to the [Load Balancer](#load-balancer-ip) or [External IP](#external-ip). Configuration of the DNS entry will depend upon the DNS service being used. + +#### External IP (Recommended) To provision an external IP on GCP and Azure, simply request a new address from the Networking section. Ensure that the region matches the region your container cluster is created in. Note, it is important that the IP is not assigned at this point in time. It will be automatically assigned once the Helm chart is installed, and assigned to the Load Balancer. Now that an external IP address has been allocated, ensure that the wildcard DNS entry you would like to use resolves to this IP. Please consult the documentation for your DNS service for more information on creating DNS records. +Finally, set the `baseIP` setting to this IP address when [deploying GitLab](#configuring-and-installing-gitlab). + +#### Load Balancer IP + +If you do not specify a `baseIP`, an ephemeral IP will be assigned to the Load Balancer or Ingress. You can retrieve this IP by running the following command *after* deploying GitLab: + +`kubectl get svc -w --namespace nginx-ingress nginx` + +The IP address will be displayed in the `EXTERNAL-IP` field, and should be used to configure the Wildcard DNS entry. For more information on creating a wildcard DNS entry, consult the documentation for the DNS server you are using. + +For production deployments of GitLab, we strongly recommend using an [External IP](#external-ip). + ## Configuring and Installing GitLab For most installations, only two parameters are required: -- `baseIP`: the desired [external IP address](#networking-prerequisites) - `baseDomain`: the [base domain](#networking-prerequisites) with the wildcard host entry resolving to the `baseIP`. For example, `mycompany.io`. +- `legoEmail`: Email address to use when requesting new SSL certificates from Let's Encrypt Other common configuration options: +- `baseIP`: the desired [external IP address](#networking-prerequisites) - `gitlab`: Choose the [desired edition](https://about.gitlab.com/products), either `ee` or `ce`. `ce` is the default. - `gitlabEELicense`: For Enterprise Edition, the [license](https://docs.gitlab.com/ee/user/admin_area/license.html) can be installed directly via the Chart - `provider`: Optimizes the deployment for a cloud provider. The default is `gke` for GCP, with `acs` also supported for Azure. -- `legoEmail`: Email address to use when requesting new SSL certificates from Let's Encrypt For additional configuration options, consult the [values.yaml](https://gitlab.com/charts/charts.gitlab.io/blob/master/charts/gitlab-omnibus/values.yaml). -These settings can either be passed directly on the command line: -```bash -helm install --name gitlab --set baseDomain=gitlab.io,baseIP=1.1.1.1,gitlab=ee,gitlabEELicense=$LICENSE,legoEmail=email@gitlab.com gitlab/gitlab-omnibus -``` - -or within a YAML file: -```bash -helm install --name gitlab -f values.yaml gitlab/gitlab-omnibus -``` - -> **Note:** -If you are using a machine type with support for less than 4 attached disks, like an Azure trial, you should disable dedicated storage for [Postgres and Redis](#persistent-storage). - ### Choosing a different GitLab release version The version of GitLab installed is based on the `gitlab` setting (see [section](#choosing-gitlab-edition) above), and @@ -95,6 +94,8 @@ There is no guarantee that other release versions of GitLab, other than what are used by default in the chart, will be supported by a chart install. ### Persistent storage +> **Note:** +If you are using a machine type with support for less than 4 attached disks, like an Azure trial, you should disable dedicated storage for [Postgres and Redis](#persistent-storage). By default, persistent storage is enabled for GitLab and the charts it depends on (Redis and PostgreSQL). @@ -124,9 +125,10 @@ Ingress routing and SSL are automatically configured within this Chart. An NGINX Let's Encrypt limits a single TLD to five certificate requests within a single week. This means that common DNS wildcard services like [xip.io](http://xip.io) and [nip.io](http://nip.io) are unlikely to work. ## Installing GitLab using the Helm Chart -> You may see a temporary error message `SchedulerPredicates failed due to PersistentVolumeClaim is not bound` while storage provisions. Once the storage provisions, the pods will automatically restart. This may take a couple minutes depending on your cloud provider. If the error persists, please review the [prerequisites](#prerequisites) to ensure you have enough RAM, CPU, and storage. +> **Note:** +You may see a temporary error message `SchedulerPredicates failed due to PersistentVolumeClaim is not bound` while storage provisions. Once the storage provisions, the pods will automatically start. This may take a couple minutes depending on your cloud provider. If the error persists, please review the [prerequisites](#prerequisites) to ensure you have enough RAM, CPU, and storage. -Ensure the GitLab repo has been added and re-initialize Helm: +Add the GitLab Helm repository and initialize Helm: ```bash helm repo add gitlab https://charts.gitlab.io diff --git a/doc/install/kubernetes/gitlab_runner_chart.md b/doc/install/kubernetes/gitlab_runner_chart.md index 51f94a33109..d31c763ed64 100644 --- a/doc/install/kubernetes/gitlab_runner_chart.md +++ b/doc/install/kubernetes/gitlab_runner_chart.md @@ -1,7 +1,6 @@ # GitLab Runner Helm Chart -> These Helm charts are in beta. GitLab is working on a [cloud-native](http://docs.gitlab.com/omnibus/package-information/cloud_native.html) set of [Charts](https://gitlab.com/charts/helm.gitlab.io) which will replace these. - -> Officially supported cloud providers are Google Container Service and Azure Container Service. +> **Note:** +Officially supported cloud providers are Google Container Service and Azure Container Service. The `gitlab-runner` Helm chart deploys a GitLab Runner instance into your Kubernetes cluster. @@ -17,9 +16,7 @@ This chart configures the Runner to: - Your GitLab Server's API is reachable from the cluster - Kubernetes 1.4+ with Beta APIs enabled - The `kubectl` CLI installed locally and authenticated for the cluster -- The Helm Client installed locally -- The Helm Server (Tiller) already installed and running in the cluster, by running `helm init` -- The GitLab Helm Repo added to your Helm Client. See [Adding GitLab Helm Repo](index.md#add-the-gitlab-helm-repository) +- The [Helm client](https://github.com/kubernetes/helm/blob/master/docs/quickstart.md) installed locally on your machine ## Configuring GitLab Runner using the Helm Chart @@ -36,6 +33,8 @@ In order for GitLab Runner to function, your config file **must** specify the fo - `runnerRegistrationToken` - The Registration Token for adding new Runners to the GitLab Server. This must be retrieved from your GitLab Instance. See the [GitLab Runner Documentation](../../ci/runners/README.md#creating-and-registering-a-runner) for more information. +Unless you need to specify additional configuration, you are [ready to install](#installing-gitlab-runner-using-the-helm-chart). + ### Other configuration The rest of the configuration is [documented in the `values.yaml`](https://gitlab.com/charts/charts.gitlab.io/blob/master/charts/gitlab-runner/values.yaml) in the chart repository. @@ -115,6 +114,17 @@ runners: ``` +### Controlling maximum Runner concurrency + +A single GitLab Runner deployed on Kubernetes is able to execute multiple jobs in parallel by automatically starting additional Runner pods. The [`concurrent` setting](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-global-section) controls the maximum number of pods allowed at a single time, and defaults to `10`. + +```yaml +## Configure the maximum number of concurrent jobs +## ref: https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-global-section +## +concurrent: 10 +``` + ### Running Docker-in-Docker containers with GitLab Runners See [Running Privileged Containers for the Runners](#running-privileged-containers-for-the-runners) for how to enable it, @@ -190,7 +200,7 @@ certsSecretName: <SECRET NAME> ## Installing GitLab Runner using the Helm Chart -Ensure the GitLab repo has been added and re-initialize Helm: +Add the GitLab Helm repository and initialize Helm: ```bash helm repo add gitlab https://charts.gitlab.io diff --git a/doc/install/kubernetes/index.md b/doc/install/kubernetes/index.md index eb98dc06a18..8418b04936b 100644 --- a/doc/install/kubernetes/index.md +++ b/doc/install/kubernetes/index.md @@ -1,48 +1,52 @@ # Installing GitLab on Kubernetes -> These Helm charts are in beta. GitLab is working on a [cloud-native](http://docs.gitlab.com/omnibus/package-information/cloud_native.html) set of [Charts](https://gitlab.com/charts/helm.gitlab.io) which will replace these. - > Officially supported cloud providers are Google Container Service and Azure Container Service. The easiest method to deploy GitLab in [Kubernetes](https://kubernetes.io/) is -to take advantage of the official GitLab Helm charts. [Helm] is a package +to take advantage of GitLab's Helm charts. [Helm] is a package management tool for Kubernetes, allowing apps to be easily managed via their Charts. A [Chart] is a detailed description of the application including how it should be deployed, upgraded, and configured. -The GitLab Helm repository is located at https://charts.gitlab.io. -You can report any issues related to GitLab's Helm Charts at +GitLab provides [official Helm Charts](#official-gitlab-helm-charts-recommended) which is the recommended way to run GitLab with Kubernetes. + +There are also two other sets of charts: +* Our [upcoming cloud native Charts](#upcoming-cloud-native-helm-charts), which are in development but will eventually replace the current official charts. +* [Community contributed charts](#community-contributed-helm-charts). These charts should be considered deprecated, in favor of the official charts. + +## Official GitLab Helm Charts (Recommended) + +These charts utilize our [GitLab Omnibus Docker images](https://docs.gitlab.com/omnibus/docker/README.html). You can report any issues and feedback related to these charts at https://gitlab.com/charts/charts.gitlab.io/issues. -Contributions and improvements are also very welcome. -## Prerequisites +### Deploying GitLab on Kubernetes (Recommended) +> *Note*: This chart will eventually be replaced by the [cloud native charts](#upcoming-cloud-native-helm-charts), which are presently in development. + +The best way to deploy GitLab on Kubernetes is to use the [gitlab-omnibus](gitlab_omnibus.md) chart. It includes everything needed to run GitLab, including: a [Runner](https://docs.gitlab.com/runner/), [Container Registry](https://docs.gitlab.com/ee/user/project/container_registry.html#gitlab-container-registry), [automatic SSL](https://github.com/kubernetes/charts/tree/master/stable/kube-lego), and an [Ingress](https://github.com/kubernetes/ingress/tree/master/controllers/nginx). This chart is in beta while [additional features](https://gitlab.com/charts/charts.gitlab.io/issues/68) are being completed. -To use the charts, the Helm tool must be installed and initialized. The best -place to start is by reviewing the [Helm Quick Start Guide][helm-quick]. +### Deploying just the GitLab Runner -## Add the GitLab Helm repository +To deploy just the GitLab Runner, utilize the [gitlab-runner](gitlab_runner_chart.md) chart. It offers a quick way to configure and deploy the Runner on Kubernetes, regardless of where your GitLab server may be running. -Once Helm has been installed, the GitLab chart repository must be added: +### Advanced deployment of GitLab (Not recommended) +> *Note*: This chart will eventually be replaced by the [cloud native charts](#upcoming-cloud-native-helm-charts), which are presently in development. -```bash -helm repo add gitlab https://charts.gitlab.io -``` +If advanced configuration of GitLab is required, the beta [gitlab](gitlab_chart.md) chart can be used which deploys the GitLab service along with optional Postgres and Redis. It offers extensive configuration, but requires deep knowledge of Kubernetes and Helm to use. -After adding the repository, Helm must be re-initialized: +## Upcoming Cloud Native Helm Charts -```bash -helm init -``` +GitLab is working towards a building a [cloud native deployment method](https://gitlab.com/charts/helm.gitlab.io/blob/master/README.md). A key part of this effort is to isolate each service into it's [own Docker container and Helm chart](https://gitlab.com/gitlab-org/omnibus-gitlab/issues/2420), rather than utilizing the all-in-one container image of the [current charts](#official-gitlab-helm-charts-recommended). -## Using the GitLab Helm Charts +By offering individual containers and charts, we will be able to provide a number of benefits: +* Easier horizontal scaling of each service +* Smaller more efficient images +* Potential for rolling updates and canaries within a service +* and plenty more. -GitLab makes available three Helm Charts. +This is a large project and will be worked on over the span of multiple releases. For the most up to date status and release information, please see our [tracking issue](https://gitlab.com/gitlab-org/omnibus-gitlab/issues/2420). -- [gitlab-omnibus](gitlab_omnibus.md): **Recommended** and the easiest way to get started. Includes everything needed to run GitLab, including: a [Runner](https://docs.gitlab.com/runner/), [Container Registry](https://docs.gitlab.com/ee/user/project/container_registry.html#gitlab-container-registry), [automatic SSL](https://github.com/kubernetes/charts/tree/master/stable/kube-lego), and an [Ingress](https://github.com/kubernetes/ingress/tree/master/controllers/nginx). -- [gitlab](gitlab_chart.md): Just the GitLab service, with optional Postgres and Redis. -- [gitlab-runner](gitlab_runner_chart.md): GitLab Runner, to process CI jobs. +## Community Contributed Helm Charts -We are also working on a new set of [cloud native Charts](https://gitlab.com/charts/helm.gitlab.io) which will eventually replace these. +The community has also [contributed GitLab charts](https://github.com/kubernetes/charts/tree/master/stable/gitlab-ce) to the [Helm Stable Repository](https://github.com/kubernetes/charts#repository-structure). These charts should be considered [deprecated](https://github.com/kubernetes/charts/issues/1138) in favor of the [official Charts](#official-gitlab-helm-charts-recommended). [chart]: https://github.com/kubernetes/charts -[helm-quick]: https://github.com/kubernetes/helm/blob/master/docs/quickstart.md [helm]: https://github.com/kubernetes/helm/blob/master/README.md diff --git a/doc/install/requirements.md b/doc/install/requirements.md index 175dfc62096..f672b358096 100644 --- a/doc/install/requirements.md +++ b/doc/install/requirements.md @@ -82,7 +82,9 @@ errors during usage. We recommend having at least 2GB of swap on your server, even if you currently have enough available RAM. Having swap will help reduce the chance of errors occurring -if your available memory changes. +if your available memory changes. We also recommend [configuring the kernels swappiness setting](https://askubuntu.com/a/103916) +to a low value like `10` to make the most of your RAM while still having the swap +available when needed. Notice: The 25 workers of Sidekiq will show up as separate processes in your process overview (such as top or htop) but they share the same RAM allocation since Sidekiq is a multithreaded application. Please see the section below about Unicorn workers for information about many you need of those. diff --git a/doc/user/project/pipelines/job_artifacts.md b/doc/user/project/pipelines/job_artifacts.md index e853bfff444..4e93e680fd2 100644 --- a/doc/user/project/pipelines/job_artifacts.md +++ b/doc/user/project/pipelines/job_artifacts.md @@ -100,16 +100,21 @@ inside GitLab that make that possible. It is possible to download the latest artifacts of a job via a well known URL so you can use it for scripting purposes. +>**Note:** +The latest artifacts are considered as the artifacts created by jobs in the +latest pipeline that succeeded for the specific ref. +Artifacts for other pipelines can be accessed with direct access to them. + The structure of the URL to download the whole artifacts archive is the following: ``` -https://example.com/<namespace>/<project>/builds/artifacts/<ref>/download?job=<job_name> +https://example.com/<namespace>/<project>/-/jobs/artifacts/<ref>/download?job=<job_name> ``` To download a single file from the artifacts use the following URL: ``` -https://example.com/<namespace>/<project>/builds/artifacts/<ref>/raw/<path_to_file>?job=<job_name> +https://example.com/<namespace>/<project>/-/jobs/artifacts/<ref>/raw/<path_to_file>?job=<job_name> ``` For example, to download the latest artifacts of the job named `coverage` of @@ -117,26 +122,26 @@ the `master` branch of the `gitlab-ce` project that belongs to the `gitlab-org` namespace, the URL would be: ``` -https://gitlab.com/gitlab-org/gitlab-ce/builds/artifacts/master/download?job=coverage +https://gitlab.com/gitlab-org/gitlab-ce/-/jobs/artifacts/master/download?job=coverage ``` To download the file `coverage/index.html` from the same artifacts use the following URL: ``` -https://gitlab.com/gitlab-org/gitlab-ce/builds/artifacts/master/raw/coverage/index.html?job=coverage +https://gitlab.com/gitlab-org/gitlab-ce/-/jobs/artifacts/master/raw/coverage/index.html?job=coverage ``` There is also a URL to browse the latest job artifacts: ``` -https://example.com/<namespace>/<project>/builds/artifacts/<ref>/browse?job=<job_name> +https://example.com/<namespace>/<project>/-/jobs/artifacts/<ref>/browse?job=<job_name> ``` For example: ``` -https://gitlab.com/gitlab-org/gitlab-ce/builds/artifacts/master/browse?job=coverage +https://gitlab.com/gitlab-org/gitlab-ce/-/jobs/artifacts/master/browse?job=coverage ``` The latest builds are also exposed in the UI in various places. Specifically, diff --git a/lib/api/files.rb b/lib/api/files.rb index e2ac7142bc4..1598d3c00b8 100644 --- a/lib/api/files.rb +++ b/lib/api/files.rb @@ -1,5 +1,7 @@ module API class Files < Grape::API + FILE_ENDPOINT_REQUIREMENTS = API::PROJECT_ENDPOINT_REQUIREMENTS.merge(file_path: API::NO_SLASH_URL_PART_REGEX) + # Prevents returning plain/text responses for files with .txt extension after_validation { content_type "application/json" } @@ -58,13 +60,13 @@ module API params do requires :id, type: String, desc: 'The project ID' end - resource :projects, requirements: { id: %r{[^/]+} } do + resource :projects, requirements: FILE_ENDPOINT_REQUIREMENTS do desc 'Get raw file contents from the repository' params do requires :file_path, type: String, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb' requires :ref, type: String, desc: 'The name of branch, tag commit' end - get ":id/repository/files/:file_path/raw" do + get ":id/repository/files/:file_path/raw", requirements: FILE_ENDPOINT_REQUIREMENTS do assign_file_vars! send_git_blob @repo, @blob @@ -75,7 +77,7 @@ module API requires :file_path, type: String, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb' requires :ref, type: String, desc: 'The name of branch, tag or commit' end - get ":id/repository/files/:file_path", requirements: { file_path: /.+/ } do + get ":id/repository/files/:file_path", requirements: FILE_ENDPOINT_REQUIREMENTS do assign_file_vars! { @@ -95,7 +97,7 @@ module API params do use :extended_file_params end - post ":id/repository/files/:file_path", requirements: { file_path: /.+/ } do + post ":id/repository/files/:file_path", requirements: FILE_ENDPOINT_REQUIREMENTS do authorize! :push_code, user_project file_params = declared_params(include_missing: false) @@ -113,7 +115,7 @@ module API params do use :extended_file_params end - put ":id/repository/files/:file_path", requirements: { file_path: /.+/ } do + put ":id/repository/files/:file_path", requirements: FILE_ENDPOINT_REQUIREMENTS do authorize! :push_code, user_project file_params = declared_params(include_missing: false) @@ -137,7 +139,7 @@ module API params do use :simple_file_params end - delete ":id/repository/files/:file_path", requirements: { file_path: /.+/ } do + delete ":id/repository/files/:file_path", requirements: FILE_ENDPOINT_REQUIREMENTS do authorize! :push_code, user_project file_params = declared_params(include_missing: false) diff --git a/lib/api/helpers/runner.rb b/lib/api/helpers/runner.rb index f8645e364ce..282af32ca94 100644 --- a/lib/api/helpers/runner.rb +++ b/lib/api/helpers/runner.rb @@ -1,6 +1,8 @@ module API module Helpers module Runner + include Gitlab::CurrentSettings + JOB_TOKEN_HEADER = 'HTTP_JOB_TOKEN'.freeze JOB_TOKEN_PARAM = :token UPDATE_RUNNER_EVERY = 10 * 60 diff --git a/lib/email_template_interceptor.rb b/lib/email_template_interceptor.rb index 63f9f8d7a5a..f2bf3d0fb2b 100644 --- a/lib/email_template_interceptor.rb +++ b/lib/email_template_interceptor.rb @@ -1,6 +1,6 @@ # Read about interceptors in http://guides.rubyonrails.org/action_mailer_basics.html#intercepting-emails class EmailTemplateInterceptor - include Gitlab::CurrentSettings + extend Gitlab::CurrentSettings def self.delivering_email(message) # Remove HTML part if HTML emails are disabled. diff --git a/lib/github/import.rb b/lib/github/import.rb index 7b848081e85..9354e142d3d 100644 --- a/lib/github/import.rb +++ b/lib/github/import.rb @@ -226,49 +226,51 @@ module Github while url response = Github::Client.new(options).get(url, state: :all, sort: :created, direction: :asc) - response.body.each do |raw| - representation = Github::Representation::Issue.new(raw, options) + response.body.each { |raw| populate_issue(raw) } - begin - # Every pull request is an issue, but not every issue - # is a pull request. For this reason, "shared" actions - # for both features, like manipulating assignees, labels - # and milestones, are provided within the Issues API. - if representation.pull_request? - next unless representation.has_labels? - - merge_request = MergeRequest.find_by!(target_project_id: project.id, iid: representation.iid) - merge_request.update_attribute(:label_ids, label_ids(representation.labels)) - else - next if Issue.where(iid: representation.iid, project_id: project.id).exists? - - author_id = user_id(representation.author, project.creator_id) - issue = Issue.new - issue.iid = representation.iid - issue.project_id = project.id - issue.title = representation.title - issue.description = format_description(representation.description, representation.author) - issue.state = representation.state - issue.label_ids = label_ids(representation.labels) - issue.milestone_id = milestone_id(representation.milestone) - issue.author_id = author_id - issue.assignee_ids = [user_id(representation.assignee)] - issue.created_at = representation.created_at - issue.updated_at = representation.updated_at - issue.save!(validate: false) - - # Fetch comments - if representation.has_comments? - comments_url = "/repos/#{repo}/issues/#{issue.iid}/comments" - fetch_comments(issue, :comment, comments_url) - end - end - rescue => e - error(:issue, representation.url, e.message) + url = response.rels[:next] + end + end + + def populate_issue(raw) + representation = Github::Representation::Issue.new(raw, options) + + begin + # Every pull request is an issue, but not every issue + # is a pull request. For this reason, "shared" actions + # for both features, like manipulating assignees, labels + # and milestones, are provided within the Issues API. + if representation.pull_request? + return unless representation.has_labels? + + merge_request = MergeRequest.find_by!(target_project_id: project.id, iid: representation.iid) + merge_request.update_attribute(:label_ids, label_ids(representation.labels)) + else + return if Issue.where(iid: representation.iid, project_id: project.id).exists? + + author_id = user_id(representation.author, project.creator_id) + issue = Issue.new + issue.iid = representation.iid + issue.project_id = project.id + issue.title = representation.title + issue.description = format_description(representation.description, representation.author) + issue.state = representation.state + issue.label_ids = label_ids(representation.labels) + issue.milestone_id = milestone_id(representation.milestone) + issue.author_id = author_id + issue.assignee_ids = [user_id(representation.assignee)] + issue.created_at = representation.created_at + issue.updated_at = representation.updated_at + issue.save!(validate: false) + + # Fetch comments + if representation.has_comments? + comments_url = "/repos/#{repo}/issues/#{issue.iid}/comments" + fetch_comments(issue, :comment, comments_url) end end - - url = response.rels[:next] + rescue => e + error(:issue, representation.url, e.message) end end diff --git a/lib/gitlab/asciidoc.rb b/lib/gitlab/asciidoc.rb index 3d41ac76406..cead1c7eacd 100644 --- a/lib/gitlab/asciidoc.rb +++ b/lib/gitlab/asciidoc.rb @@ -6,6 +6,8 @@ module Gitlab # Parser/renderer for the AsciiDoc format that uses Asciidoctor and filters # the resulting HTML through HTML pipeline filters. module Asciidoc + extend Gitlab::CurrentSettings + DEFAULT_ADOC_ATTRS = [ 'showtitle', 'idprefix=user-content-', 'idseparator=-', 'env=gitlab', 'env-gitlab', 'source-highlighter=html-pipeline', 'icons=font' diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb index 8cb4060cd97..1790f380c33 100644 --- a/lib/gitlab/auth.rb +++ b/lib/gitlab/auth.rb @@ -19,6 +19,8 @@ module Gitlab OPTIONAL_SCOPES = (AVAILABLE_SCOPES + OPENID_SCOPES - DEFAULT_SCOPES).freeze class << self + include Gitlab::CurrentSettings + def find_for_git_client(login, password, project:, ip:) raise "Must provide an IP for rate limiting" if ip.nil? diff --git a/lib/gitlab/ci/config/entry/attributable.rb b/lib/gitlab/ci/config/entry/attributable.rb index 1c8b55ee4c4..3e87a09704e 100644 --- a/lib/gitlab/ci/config/entry/attributable.rb +++ b/lib/gitlab/ci/config/entry/attributable.rb @@ -8,6 +8,10 @@ module Gitlab class_methods do def attributes(*attributes) attributes.flatten.each do |attribute| + if method_defined?(attribute) + raise ArgumentError, 'Method already defined!' + end + define_method(attribute) do return unless config.is_a?(Hash) diff --git a/lib/gitlab/ci/config/entry/configurable.rb b/lib/gitlab/ci/config/entry/configurable.rb index e05aca9881b..68b6742385a 100644 --- a/lib/gitlab/ci/config/entry/configurable.rb +++ b/lib/gitlab/ci/config/entry/configurable.rb @@ -15,9 +15,10 @@ module Gitlab # module Configurable extend ActiveSupport::Concern - include Validatable included do + include Validatable + validations do validates :config, type: Hash end diff --git a/lib/gitlab/ci/config/entry/job.rb b/lib/gitlab/ci/config/entry/job.rb index 32f5c6ab142..91aac6df4b1 100644 --- a/lib/gitlab/ci/config/entry/job.rb +++ b/lib/gitlab/ci/config/entry/job.rb @@ -59,10 +59,10 @@ module Gitlab entry :services, Entry::Services, description: 'Services that will be used to execute this job.' - entry :only, Entry::Trigger, + entry :only, Entry::Policy, description: 'Refs policy this job will be executed for.' - entry :except, Entry::Trigger, + entry :except, Entry::Policy, description: 'Refs policy this job will be executed for.' entry :variables, Entry::Variables, diff --git a/lib/gitlab/ci/config/entry/node.rb b/lib/gitlab/ci/config/entry/node.rb index a6a914d79c1..c868943c42e 100644 --- a/lib/gitlab/ci/config/entry/node.rb +++ b/lib/gitlab/ci/config/entry/node.rb @@ -16,8 +16,9 @@ module Gitlab @metadata = metadata @entries = {} - @validator = self.class.validator.new(self) - @validator.validate(:new) + self.class.aspects.to_a.each do |aspect| + instance_exec(&aspect) + end end def [](key) @@ -47,7 +48,7 @@ module Gitlab end def errors - @validator.messages + descendants.flat_map(&:errors) + [] end def value @@ -70,6 +71,13 @@ module Gitlab true end + def location + name = @key.presence || self.class.name.to_s.demodulize + .underscore.humanize.downcase + + ancestors.map(&:key).append(name).compact.join(':') + end + def inspect val = leaf? ? config : descendants unspecified = specified? ? '' : '(unspecified) ' @@ -79,8 +87,8 @@ module Gitlab def self.default end - def self.validator - Validator + def self.aspects + @aspects ||= [] end end end diff --git a/lib/gitlab/ci/config/entry/policy.rb b/lib/gitlab/ci/config/entry/policy.rb new file mode 100644 index 00000000000..3cdae1cee4f --- /dev/null +++ b/lib/gitlab/ci/config/entry/policy.rb @@ -0,0 +1,31 @@ +module Gitlab + module Ci + class Config + module Entry + ## + # Entry that represents an only/except trigger policy for the job. + # + class Policy < Simplifiable + strategy :RefsPolicy, if: -> (config) { config.is_a?(Array) } + + class RefsPolicy < Entry::Node + include Entry::Validatable + + validations do + validates :config, array_of_strings_or_regexps: true + end + end + + class UnknownStrategy < Entry::Node + def errors + ["#{location} has to be either an array of conditions or a hash"] + end + end + + def self.default + end + end + end + end + end +end diff --git a/lib/gitlab/ci/config/entry/simplifiable.rb b/lib/gitlab/ci/config/entry/simplifiable.rb new file mode 100644 index 00000000000..12764629686 --- /dev/null +++ b/lib/gitlab/ci/config/entry/simplifiable.rb @@ -0,0 +1,43 @@ +module Gitlab + module Ci + class Config + module Entry + class Simplifiable < SimpleDelegator + EntryStrategy = Struct.new(:name, :condition) + + def initialize(config, **metadata) + unless self.class.const_defined?(:UnknownStrategy) + raise ArgumentError, 'UndefinedStrategy not available!' + end + + strategy = self.class.strategies.find do |variant| + variant.condition.call(config) + end + + entry = self.class.entry_class(strategy) + + super(entry.new(config, metadata)) + end + + def self.strategy(name, **opts) + EntryStrategy.new(name, opts.fetch(:if)).tap do |strategy| + strategies.append(strategy) + end + end + + def self.strategies + @strategies ||= [] + end + + def self.entry_class(strategy) + if strategy.present? + self.const_get(strategy.name) + else + self::UnknownStrategy + end + end + end + end + end + end +end diff --git a/lib/gitlab/ci/config/entry/trigger.rb b/lib/gitlab/ci/config/entry/trigger.rb deleted file mode 100644 index 16b234e6c59..00000000000 --- a/lib/gitlab/ci/config/entry/trigger.rb +++ /dev/null @@ -1,18 +0,0 @@ -module Gitlab - module Ci - class Config - module Entry - ## - # Entry that represents a trigger policy for the job. - # - class Trigger < Node - include Validatable - - validations do - validates :config, array_of_strings_or_regexps: true - end - end - end - end - end -end diff --git a/lib/gitlab/ci/config/entry/validatable.rb b/lib/gitlab/ci/config/entry/validatable.rb index f7f1b111571..5ced778d311 100644 --- a/lib/gitlab/ci/config/entry/validatable.rb +++ b/lib/gitlab/ci/config/entry/validatable.rb @@ -5,6 +5,17 @@ module Gitlab module Validatable extend ActiveSupport::Concern + def self.included(node) + node.aspects.append -> do + @validator = self.class.validator.new(self) + @validator.validate(:new) + end + end + + def errors + @validator.messages + descendants.flat_map(&:errors) + end + class_methods do def validator @validator ||= Class.new(Entry::Validator).tap do |validator| diff --git a/lib/gitlab/ci/config/entry/validator.rb b/lib/gitlab/ci/config/entry/validator.rb index 55343005fe3..2df23a3edcd 100644 --- a/lib/gitlab/ci/config/entry/validator.rb +++ b/lib/gitlab/ci/config/entry/validator.rb @@ -8,7 +8,6 @@ module Gitlab def initialize(entry) super(entry) - @entry = entry end def messages @@ -20,21 +19,6 @@ module Gitlab def self.name 'Validator' end - - private - - def location - predecessors = ancestors.map(&:key).compact - predecessors.append(key_name).join(':') - end - - def key_name - if key.blank? - @entry.class.name.demodulize.underscore.humanize - else - key - end - end end end end diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb index 7fa02f3d7b3..642f0944354 100644 --- a/lib/gitlab/current_settings.rb +++ b/lib/gitlab/current_settings.rb @@ -1,5 +1,7 @@ module Gitlab module CurrentSettings + extend self + def current_application_settings if RequestStore.active? RequestStore.fetch(:current_application_settings) { ensure_application_settings! } diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index fb6504bdea0..554e40dc8a6 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -47,6 +47,9 @@ module Gitlab # Directory name of repo attr_reader :name + # Relative path of repo + attr_reader :relative_path + # Rugged repo object attr_reader :rugged diff --git a/lib/gitlab/gitaly_client/repository_service.rb b/lib/gitlab/gitaly_client/repository_service.rb index a74a6dc6e78..177a1284f38 100644 --- a/lib/gitlab/gitaly_client/repository_service.rb +++ b/lib/gitlab/gitaly_client/repository_service.rb @@ -37,6 +37,22 @@ module Gitlab request = Gitaly::ApplyGitattributesRequest.new(repository: @gitaly_repo, revision: revision) GitalyClient.call(@storage, :repository_service, :apply_gitattributes, request) end + + def fetch_remote(remote, ssh_auth: nil, forced: false, no_tags: false) + request = Gitaly::FetchRemoteRequest.new(repository: @gitaly_repo, remote: remote, force: forced, no_tags: no_tags) + + if ssh_auth&.ssh_import? + if ssh_auth.ssh_key_auth? && ssh_auth.ssh_private_key.present? + request.ssh_key = ssh_auth.ssh_private_key + end + + if ssh_auth.ssh_known_hosts.present? + request.known_hosts = ssh_auth.ssh_known_hosts + end + end + + GitalyClient.call(@storage, :repository_service, :fetch_remote, request) + end end end end diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb index 2d1ae6a5925..9bcc579278f 100644 --- a/lib/gitlab/gon_helper.rb +++ b/lib/gitlab/gon_helper.rb @@ -3,6 +3,7 @@ module Gitlab module GonHelper include WebpackHelper + include Gitlab::CurrentSettings def add_gon_variables gon.api_version = 'v4' diff --git a/lib/gitlab/metrics/influx_db.rb b/lib/gitlab/metrics/influx_db.rb index d7c56463aac..7b06bb953aa 100644 --- a/lib/gitlab/metrics/influx_db.rb +++ b/lib/gitlab/metrics/influx_db.rb @@ -1,7 +1,7 @@ module Gitlab module Metrics module InfluxDb - extend Gitlab::CurrentSettings + include Gitlab::CurrentSettings extend self MUTEX = Mutex.new diff --git a/lib/gitlab/performance_bar.rb b/lib/gitlab/performance_bar.rb index 56112ec2301..e73245b82c1 100644 --- a/lib/gitlab/performance_bar.rb +++ b/lib/gitlab/performance_bar.rb @@ -1,6 +1,6 @@ module Gitlab module PerformanceBar - include Gitlab::CurrentSettings + extend Gitlab::CurrentSettings ALLOWED_USER_IDS_KEY = 'performance_bar_allowed_user_ids:v2'.freeze EXPIRY_TIME = 5.minutes diff --git a/lib/gitlab/polling_interval.rb b/lib/gitlab/polling_interval.rb index f0c50584f07..4780675a492 100644 --- a/lib/gitlab/polling_interval.rb +++ b/lib/gitlab/polling_interval.rb @@ -1,6 +1,6 @@ module Gitlab class PollingInterval - include Gitlab::CurrentSettings + extend Gitlab::CurrentSettings HEADER_NAME = 'Poll-Interval'.freeze diff --git a/lib/gitlab/protocol_access.rb b/lib/gitlab/protocol_access.rb index 21aefc884be..09fa14764e6 100644 --- a/lib/gitlab/protocol_access.rb +++ b/lib/gitlab/protocol_access.rb @@ -1,5 +1,7 @@ module Gitlab module ProtocolAccess + extend Gitlab::CurrentSettings + def self.allowed?(protocol) if protocol == 'web' true diff --git a/lib/gitlab/recaptcha.rb b/lib/gitlab/recaptcha.rb index 4bc76ea033f..c463dd487a0 100644 --- a/lib/gitlab/recaptcha.rb +++ b/lib/gitlab/recaptcha.rb @@ -1,5 +1,7 @@ module Gitlab module Recaptcha + extend Gitlab::CurrentSettings + def self.load_configurations! if current_application_settings.recaptcha_enabled ::Recaptcha.configure do |config| diff --git a/lib/gitlab/sentry.rb b/lib/gitlab/sentry.rb index 2442c2ded3b..f6bdd6cf0fe 100644 --- a/lib/gitlab/sentry.rb +++ b/lib/gitlab/sentry.rb @@ -1,5 +1,7 @@ module Gitlab module Sentry + extend Gitlab::CurrentSettings + def self.enabled? Rails.env.production? && current_application_settings.sentry_enabled? end diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb index 280a9abf03e..81ecdf43ef9 100644 --- a/lib/gitlab/shell.rb +++ b/lib/gitlab/shell.rb @@ -98,33 +98,24 @@ module Gitlab # Fetch remote for repository # - # name - project path with namespace + # repository - an instance of Git::Repository # remote - remote name # forced - should we use --force flag? # no_tags - should we use --no-tags flag? # # Ex. - # fetch_remote("gitlab/gitlab-ci", "upstream") + # fetch_remote(my_repo, "upstream") # # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387 - def fetch_remote(storage, name, remote, ssh_auth: nil, forced: false, no_tags: false) - args = [gitlab_shell_projects_path, 'fetch-remote', storage, "#{name}.git", remote, "#{Gitlab.config.gitlab_shell.git_timeout}"] - args << '--force' if forced - args << '--no-tags' if no_tags - - vars = {} - - if ssh_auth&.ssh_import? - if ssh_auth.ssh_key_auth? && ssh_auth.ssh_private_key.present? - vars['GITLAB_SHELL_SSH_KEY'] = ssh_auth.ssh_private_key - end - - if ssh_auth.ssh_known_hosts.present? - vars['GITLAB_SHELL_KNOWN_HOSTS'] = ssh_auth.ssh_known_hosts + def fetch_remote(repository, remote, ssh_auth: nil, forced: false, no_tags: false) + gitaly_migrate(:fetch_remote) do |is_enabled| + if is_enabled + repository.gitaly_repository_client.fetch_remote(remote, ssh_auth: ssh_auth, forced: forced, no_tags: no_tags) + else + storage_path = Gitlab.config.repositories.storages[repository.storage]["path"] + local_fetch_remote(storage_path, repository.relative_path, remote, ssh_auth: ssh_auth, forced: forced, no_tags: no_tags) end end - - gitlab_shell_fast_execute_raise_error(args, vars) end # Move repository @@ -302,6 +293,26 @@ module Gitlab private + def local_fetch_remote(storage, name, remote, ssh_auth: nil, forced: false, no_tags: false) + args = [gitlab_shell_projects_path, 'fetch-remote', storage, name, remote, "#{Gitlab.config.gitlab_shell.git_timeout}"] + args << '--force' if forced + args << '--no-tags' if no_tags + + vars = {} + + if ssh_auth&.ssh_import? + if ssh_auth.ssh_key_auth? && ssh_auth.ssh_private_key.present? + vars['GITLAB_SHELL_SSH_KEY'] = ssh_auth.ssh_private_key + end + + if ssh_auth.ssh_known_hosts.present? + vars['GITLAB_SHELL_KNOWN_HOSTS'] = ssh_auth.ssh_known_hosts + end + end + + gitlab_shell_fast_execute_raise_error(args, vars) + end + def gitlab_shell_fast_execute(cmd) output, status = gitlab_shell_fast_execute_helper(cmd) @@ -325,5 +336,13 @@ module Gitlab # from wasting I/O by searching through GEM_PATH Bundler.with_original_env { Popen.popen(cmd, nil, vars) } end + + def gitaly_migrate(method, &block) + Gitlab::GitalyClient.migrate(method, &block) + rescue GRPC::NotFound, GRPC::BadStatus => e + # Old Popen code returns [Error, output] to the caller, so we + # need to do the same here... + raise Error, e + end end end diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb index 748e0a29184..3cf26625108 100644 --- a/lib/gitlab/usage_data.rb +++ b/lib/gitlab/usage_data.rb @@ -1,8 +1,8 @@ module Gitlab class UsageData - include Gitlab::CurrentSettings - class << self + include Gitlab::CurrentSettings + def data(force_refresh: false) Rails.cache.fetch('usage_data', force: force_refresh, expires_in: 2.weeks) { uncached_data } end diff --git a/lib/tasks/import.rake b/lib/tasks/import.rake index 1206302cb76..4d485108cf6 100644 --- a/lib/tasks/import.rake +++ b/lib/tasks/import.rake @@ -80,7 +80,7 @@ class GithubImport end def visibility_level - @repo['private'] ? Gitlab::VisibilityLevel::PRIVATE : current_application_settings.default_project_visibility + @repo['private'] ? Gitlab::VisibilityLevel::PRIVATE : Gitlab::CurrentSettings.current_application_settings.default_project_visibility end end diff --git a/scripts/static-analysis b/scripts/static-analysis index e4f80e8fc6f..52529e64b30 100755 --- a/scripts/static-analysis +++ b/scripts/static-analysis @@ -3,7 +3,7 @@ require ::File.expand_path('../lib/gitlab/popen', __dir__) tasks = [ - %w[bundle exec bundle-audit check --update --ignore CVE-2016-4658 CVE-2017-5029], + %w[bundle exec bundle-audit check --update], %w[bundle exec rake config_lint], %w[bundle exec rake flay], %w[bundle exec rake haml_lint], diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb index 3d21b695af4..aadd3317875 100644 --- a/spec/controllers/admin/users_controller_spec.rb +++ b/spec/controllers/admin/users_controller_spec.rb @@ -150,6 +150,18 @@ describe Admin::UsersController do post :update, params end + context 'when the admin changes his own password' do + it 'updates the password' do + expect { update_password(admin, 'AValidPassword1') } + .to change { admin.reload.encrypted_password } + end + + it 'does not set the new password to expire immediately' do + expect { update_password(admin, 'AValidPassword1') } + .not_to change { admin.reload.password_expires_at } + end + end + context 'when the new password is valid' do it 'redirects to the user' do update_password(user, 'AValidPassword1') @@ -158,15 +170,13 @@ describe Admin::UsersController do end it 'updates the password' do - update_password(user, 'AValidPassword1') - - expect { user.reload }.to change { user.encrypted_password } + expect { update_password(user, 'AValidPassword1') } + .to change { user.reload.encrypted_password } end it 'sets the new password to expire immediately' do - update_password(user, 'AValidPassword1') - - expect { user.reload }.to change { user.password_expires_at }.to(a_value <= Time.now) + expect { update_password(user, 'AValidPassword1') } + .to change { user.reload.password_expires_at }.to be_within(2.seconds).of(Time.now) end end @@ -184,9 +194,8 @@ describe Admin::UsersController do end it 'does not update the password' do - update_password(user, 'invalid') - - expect { user.reload }.not_to change { user.encrypted_password } + expect { update_password(user, 'invalid') } + .not_to change { user.reload.encrypted_password } end end @@ -204,9 +213,8 @@ describe Admin::UsersController do end it 'does not update the password' do - update_password(user, 'AValidPassword1', 'AValidPassword2') - - expect { user.reload }.not_to change { user.encrypted_password } + expect { update_password(user, 'AValidPassword1', 'AValidPassword2') } + .not_to change { user.reload.encrypted_password } end end end diff --git a/spec/controllers/projects/pages_controller_spec.rb b/spec/controllers/projects/pages_controller_spec.rb index 4d0111302f3..83c7744a231 100644 --- a/spec/controllers/projects/pages_controller_spec.rb +++ b/spec/controllers/projects/pages_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Projects::PagesController do let(:user) { create(:user) } - let(:project) { create(:project, :public, :access_requestable) } + let(:project) { create(:project, :public) } let(:request_params) do { @@ -23,6 +23,17 @@ describe Projects::PagesController do expect(response).to have_http_status(200) end + + context 'when the project is in a subgroup' do + let(:group) { create(:group, :nested) } + let(:project) { create(:project, namespace: group) } + + it 'returns a 404 status code' do + get :show, request_params + + expect(response).to have_http_status(404) + end + end end describe 'DELETE destroy' do diff --git a/spec/helpers/version_check_helper_spec.rb b/spec/helpers/version_check_helper_spec.rb index 5eba03ef576..fa8cfda3b86 100644 --- a/spec/helpers/version_check_helper_spec.rb +++ b/spec/helpers/version_check_helper_spec.rb @@ -4,7 +4,7 @@ describe VersionCheckHelper do describe '#version_status_badge' do it 'should return nil if not dev environment and not enabled' do allow(Rails.env).to receive(:production?) { false } - allow(current_application_settings).to receive(:version_check_enabled) { false } + allow(helper.current_application_settings).to receive(:version_check_enabled) { false } expect(helper.version_status_badge).to be(nil) end @@ -12,7 +12,7 @@ describe VersionCheckHelper do context 'when production and enabled' do before do allow(Rails.env).to receive(:production?) { true } - allow(current_application_settings).to receive(:version_check_enabled) { true } + allow(helper.current_application_settings).to receive(:version_check_enabled) { true } allow_any_instance_of(VersionCheck).to receive(:url) { 'https://version.host.com/check.svg?gitlab_info=xxx' } @image_tag = helper.version_status_badge diff --git a/spec/javascripts/fly_out_nav_spec.js b/spec/javascripts/fly_out_nav_spec.js index 2e81a1b056b..0847e463577 100644 --- a/spec/javascripts/fly_out_nav_spec.js +++ b/spec/javascripts/fly_out_nav_spec.js @@ -1,4 +1,3 @@ -import Cookies from 'js-cookie'; import { calculateTop, showSubLevelItems, @@ -11,6 +10,7 @@ import { getHideSubItemsInterval, documentMouseMove, getHeaderHeight, + setSidebar, } from '~/fly_out_nav'; import bp from '~/breakpoints'; @@ -113,7 +113,6 @@ describe('Fly out sidebar navigation', () => { clientX: el.getBoundingClientRect().left + 20, clientY: el.getBoundingClientRect().top + 10, }); - console.log(el); expect( getHideSubItemsInterval(), @@ -283,7 +282,7 @@ describe('Fly out sidebar navigation', () => { describe('canShowActiveSubItems', () => { afterEach(() => { - Cookies.remove('sidebar_collapsed'); + setSidebar(null); }); it('returns true by default', () => { @@ -292,36 +291,23 @@ describe('Fly out sidebar navigation', () => { ).toBeTruthy(); }); - it('returns false when cookie is false & element is active', () => { - Cookies.set('sidebar_collapsed', 'false'); + it('returns false when active & expanded sidebar', () => { + const sidebar = document.createElement('div'); el.classList.add('active'); - expect( - canShowActiveSubItems(el), - ).toBeFalsy(); - }); - - it('returns true when cookie is false & element is active', () => { - Cookies.set('sidebar_collapsed', 'true'); - el.classList.add('active'); + setSidebar(sidebar); expect( canShowActiveSubItems(el), - ).toBeTruthy(); + ).toBeFalsy(); }); - it('returns true when element is active & breakpoint is sm', () => { - breakpointSize = 'sm'; + it('returns true when active & collapsed sidebar', () => { + const sidebar = document.createElement('div'); + sidebar.classList.add('sidebar-icons-only'); el.classList.add('active'); - expect( - canShowActiveSubItems(el), - ).toBeTruthy(); - }); - - it('returns true when element is active & breakpoint is md', () => { - breakpointSize = 'md'; - el.classList.add('active'); + setSidebar(sidebar); expect( canShowActiveSubItems(el), diff --git a/spec/javascripts/issue_show/components/edited_spec.js b/spec/javascripts/issue_show/components/edited_spec.js index a0d0750ae34..2061def699b 100644 --- a/spec/javascripts/issue_show/components/edited_spec.js +++ b/spec/javascripts/issue_show/components/edited_spec.js @@ -46,4 +46,14 @@ describe('edited', () => { expect(editedComponent.$el.querySelector('.author_link')).toBeFalsy(); expect(editedComponent.$el.querySelector('time')).toBeTruthy(); }); + + it('renders time ago tooltip at the bottom', () => { + const editedComponent = new EditedComponent({ + propsData: { + updatedAt: '2017-05-15T12:31:04.428Z', + }, + }).$mount(); + + expect(editedComponent.$el.querySelector('time').dataset.placement).toEqual('bottom'); + }); }); diff --git a/spec/javascripts/monitoring/monitoring_spec.js b/spec/javascripts/monitoring/dashboard_spec.js index 6c7b691baa4..752fdfb4614 100644 --- a/spec/javascripts/monitoring/monitoring_spec.js +++ b/spec/javascripts/monitoring/dashboard_spec.js @@ -1,21 +1,21 @@ import Vue from 'vue'; -import Monitoring from '~/monitoring/components/monitoring.vue'; +import Dashboard from '~/monitoring/components/dashboard.vue'; import { MonitorMockInterceptor } from './mock_data'; -describe('Monitoring', () => { +describe('Dashboard', () => { const fixtureName = 'environments/metrics/metrics.html.raw'; - let MonitoringComponent; + let DashboardComponent; let component; preloadFixtures(fixtureName); beforeEach(() => { loadFixtures(fixtureName); - MonitoringComponent = Vue.extend(Monitoring); + DashboardComponent = Vue.extend(Dashboard); }); describe('no metrics are available yet', () => { it('shows a getting started empty state when no metrics are present', () => { - component = new MonitoringComponent({ + component = new DashboardComponent({ el: document.querySelector('#prometheus-graphs'), }); @@ -36,7 +36,7 @@ describe('Monitoring', () => { }); it('shows up a loading state', (done) => { - component = new MonitoringComponent({ + component = new DashboardComponent({ el: document.querySelector('#prometheus-graphs'), }); component.$mount(); diff --git a/spec/javascripts/monitoring/monitoring_state_spec.js b/spec/javascripts/monitoring/dashboard_state_spec.js index 4c0c558502f..e8f7042e131 100644 --- a/spec/javascripts/monitoring/monitoring_state_spec.js +++ b/spec/javascripts/monitoring/dashboard_state_spec.js @@ -1,9 +1,9 @@ import Vue from 'vue'; -import MonitoringState from '~/monitoring/components/monitoring_state.vue'; +import EmptyState from '~/monitoring/components/empty_state.vue'; import { statePaths } from './mock_data'; const createComponent = (propsData) => { - const Component = Vue.extend(MonitoringState); + const Component = Vue.extend(EmptyState); return new Component({ propsData, @@ -14,7 +14,7 @@ function getTextFromNode(component, selector) { return component.$el.querySelector(selector).firstChild.nodeValue.trim(); } -describe('MonitoringState', () => { +describe('EmptyState', () => { describe('Computed props', () => { it('currentState', () => { const component = createComponent({ diff --git a/spec/javascripts/monitoring/monitoring_deployment_spec.js b/spec/javascripts/monitoring/graph/deployment_spec.js index 5cc5b514824..c2ff38ffab9 100644 --- a/spec/javascripts/monitoring/monitoring_deployment_spec.js +++ b/spec/javascripts/monitoring/graph/deployment_spec.js @@ -1,9 +1,9 @@ import Vue from 'vue'; -import MonitoringState from '~/monitoring/components/monitoring_deployment.vue'; -import { deploymentData } from './mock_data'; +import GraphDeployment from '~/monitoring/components/graph/deployment.vue'; +import { deploymentData } from '../mock_data'; const createComponent = (propsData) => { - const Component = Vue.extend(MonitoringState); + const Component = Vue.extend(GraphDeployment); return new Component({ propsData, diff --git a/spec/javascripts/monitoring/monitoring_flag_spec.js b/spec/javascripts/monitoring/graph/flag_spec.js index 3861a95ff07..731076a7d2a 100644 --- a/spec/javascripts/monitoring/monitoring_flag_spec.js +++ b/spec/javascripts/monitoring/graph/flag_spec.js @@ -1,8 +1,8 @@ import Vue from 'vue'; -import MonitoringFlag from '~/monitoring/components/monitoring_flag.vue'; +import GraphFlag from '~/monitoring/components/graph/flag.vue'; const createComponent = (propsData) => { - const Component = Vue.extend(MonitoringFlag); + const Component = Vue.extend(GraphFlag); return new Component({ propsData, @@ -14,7 +14,7 @@ function getCoordinate(component, selector, coordinate) { return parseInt(coordinateVal, 10); } -describe('MonitoringFlag', () => { +describe('GraphFlag', () => { it('has a line and a circle located at the currentXCoordinate and currentYCoordinate', () => { const component = createComponent({ currentXCoordinate: 200, diff --git a/spec/javascripts/monitoring/monitoring_legends_spec.js b/spec/javascripts/monitoring/graph/legend_spec.js index 4c69b81e650..e877832dffd 100644 --- a/spec/javascripts/monitoring/monitoring_legends_spec.js +++ b/spec/javascripts/monitoring/graph/legend_spec.js @@ -1,9 +1,9 @@ import Vue from 'vue'; -import MonitoringLegends from '~/monitoring/components/monitoring_legends.vue'; +import GraphLegend from '~/monitoring/components/graph/legend.vue'; import measurements from '~/monitoring/utils/measurements'; const createComponent = (propsData) => { - const Component = Vue.extend(MonitoringLegends); + const Component = Vue.extend(GraphLegend); return new Component({ propsData, @@ -14,7 +14,7 @@ function getTextFromNode(component, selector) { return component.$el.querySelector(selector).firstChild.nodeValue.trim(); } -describe('MonitoringLegends', () => { +describe('GraphLegend', () => { describe('Computed props', () => { it('textTransform', () => { const component = createComponent({ diff --git a/spec/javascripts/monitoring/monitoring_row_spec.js b/spec/javascripts/monitoring/graph_row_spec.js index a82480e8342..dd485473ccf 100644 --- a/spec/javascripts/monitoring/monitoring_row_spec.js +++ b/spec/javascripts/monitoring/graph_row_spec.js @@ -1,16 +1,21 @@ import Vue from 'vue'; -import MonitoringRow from '~/monitoring/components/monitoring_row.vue'; +import GraphRow from '~/monitoring/components/graph_row.vue'; +import MonitoringMixins from '~/monitoring/mixins/monitoring_mixins'; import { deploymentData, singleRowMetrics } from './mock_data'; const createComponent = (propsData) => { - const Component = Vue.extend(MonitoringRow); + const Component = Vue.extend(GraphRow); return new Component({ propsData, }).$mount(); }; -describe('MonitoringRow', () => { +describe('GraphRow', () => { + beforeEach(() => { + spyOn(MonitoringMixins.methods, 'formatDeployments').and.returnValue({}); + }); + describe('Computed props', () => { it('bootstrapClass is set to col-md-6 when rowData is higher/equal to 2', () => { const component = createComponent({ diff --git a/spec/javascripts/monitoring/monitoring_column_spec.js b/spec/javascripts/monitoring/graph_spec.js index c423024dce0..6d6fe410113 100644 --- a/spec/javascripts/monitoring/monitoring_column_spec.js +++ b/spec/javascripts/monitoring/graph_spec.js @@ -1,39 +1,37 @@ import Vue from 'vue'; import _ from 'underscore'; -import MonitoringColumn from '~/monitoring/components/monitoring_column.vue'; +import Graph from '~/monitoring/components/graph.vue'; import MonitoringMixins from '~/monitoring/mixins/monitoring_mixins'; import eventHub from '~/monitoring/event_hub'; import { deploymentData, singleRowMetrics } from './mock_data'; const createComponent = (propsData) => { - const Component = Vue.extend(MonitoringColumn); + const Component = Vue.extend(Graph); return new Component({ propsData, }).$mount(); }; -describe('MonitoringColumn', () => { +describe('Graph', () => { beforeEach(() => { - spyOn(MonitoringMixins.methods, 'formatDeployments').and.callFake(function fakeFormat() { - return {}; - }); + spyOn(MonitoringMixins.methods, 'formatDeployments').and.returnValue({}); }); it('has a title', () => { const component = createComponent({ - columnData: singleRowMetrics[0], + graphData: singleRowMetrics[0], classType: 'col-md-6', updateAspectRatio: false, deploymentData, }); - expect(component.$el.querySelector('.text-center').innerText.trim()).toBe(component.columnData.title); + expect(component.$el.querySelector('.text-center').innerText.trim()).toBe(component.graphData.title); }); it('creates a path for the line and area of the graph', (done) => { const component = createComponent({ - columnData: singleRowMetrics[0], + graphData: singleRowMetrics[0], classType: 'col-md-6', updateAspectRatio: false, deploymentData, @@ -53,7 +51,7 @@ describe('MonitoringColumn', () => { describe('Computed props', () => { it('axisTransform translates an element Y position depending of its height', () => { const component = createComponent({ - columnData: singleRowMetrics[0], + graphData: singleRowMetrics[0], classType: 'col-md-6', updateAspectRatio: false, deploymentData, @@ -66,7 +64,7 @@ describe('MonitoringColumn', () => { it('outterViewBox gets a width and height property based on the DOM size of the element', () => { const component = createComponent({ - columnData: singleRowMetrics[0], + graphData: singleRowMetrics[0], classType: 'col-md-6', updateAspectRatio: false, deploymentData, @@ -81,7 +79,7 @@ describe('MonitoringColumn', () => { it('sends an event to the eventhub when it has finished resizing', (done) => { const component = createComponent({ - columnData: singleRowMetrics[0], + graphData: singleRowMetrics[0], classType: 'col-md-6', updateAspectRatio: false, deploymentData, @@ -97,13 +95,13 @@ describe('MonitoringColumn', () => { it('has a title for the y-axis and the chart legend that comes from the backend', () => { const component = createComponent({ - columnData: singleRowMetrics[0], + graphData: singleRowMetrics[0], classType: 'col-md-6', updateAspectRatio: false, deploymentData, }); - expect(component.yAxisLabel).toEqual(component.columnData.y_label); - expect(component.legendTitle).toEqual(component.columnData.queries[0].label); + expect(component.yAxisLabel).toEqual(component.graphData.y_label); + expect(component.legendTitle).toEqual(component.graphData.queries[0].label); }); }); diff --git a/spec/javascripts/project_select_combo_button_spec.js b/spec/javascripts/project_select_combo_button_spec.js index 021804e0769..dda83645c92 100644 --- a/spec/javascripts/project_select_combo_button_spec.js +++ b/spec/javascripts/project_select_combo_button_spec.js @@ -32,11 +32,6 @@ describe('Project Select Combo Button', function () { this.comboButton = new ProjectSelectComboButton(this.projectSelectInput); }); - it('newItemBtn is disabled', function () { - expect(this.newItemBtn.hasAttribute('disabled')).toBe(true); - expect(this.newItemBtn.classList.contains('disabled')).toBe(true); - }); - it('newItemBtn href is null', function () { expect(this.newItemBtn.getAttribute('href')).toBe(''); }); @@ -53,11 +48,6 @@ describe('Project Select Combo Button', function () { this.comboButton = new ProjectSelectComboButton(this.projectSelectInput); }); - it('newItemBtn is not disabled', function () { - expect(this.newItemBtn.hasAttribute('disabled')).toBe(false); - expect(this.newItemBtn.classList.contains('disabled')).toBe(false); - }); - it('newItemBtn href is correctly set', function () { expect(this.newItemBtn.getAttribute('href')).toBe(this.defaults.projectMeta.url); }); @@ -82,11 +72,6 @@ describe('Project Select Combo Button', function () { .trigger('change'); }); - it('newItemBtn is not disabled', function () { - expect(this.newItemBtn.hasAttribute('disabled')).toBe(false); - expect(this.newItemBtn.classList.contains('disabled')).toBe(false); - }); - it('newItemBtn href is correctly set', function () { expect(this.newItemBtn.getAttribute('href')) .toBe('http://myothercoolproject.com/issues/new'); diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index ee28387cd48..c70a4cb55fe 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -344,28 +344,31 @@ module Ci let(:config) { { rspec: { script: "rspec", type: "test", only: only } } } let(:processor) { GitlabCiYamlProcessor.new(YAML.dump(config)) } - shared_examples 'raises an error' do - it do - expect { processor }.to raise_error(GitlabCiYamlProcessor::ValidationError, 'jobs:rspec:only config should be an array of strings or regexps') - end - end - context 'when it is integer' do let(:only) { 1 } - it_behaves_like 'raises an error' + it do + expect { processor }.to raise_error(GitlabCiYamlProcessor::ValidationError, + 'jobs:rspec:only has to be either an array of conditions or a hash') + end end context 'when it is an array of integers' do let(:only) { [1, 1] } - it_behaves_like 'raises an error' + it do + expect { processor }.to raise_error(GitlabCiYamlProcessor::ValidationError, + 'jobs:rspec:only config should be an array of strings or regexps') + end end context 'when it is invalid regex' do let(:only) { ["/*invalid/"] } - it_behaves_like 'raises an error' + it do + expect { processor }.to raise_error(GitlabCiYamlProcessor::ValidationError, + 'jobs:rspec:only config should be an array of strings or regexps') + end end end end @@ -518,28 +521,31 @@ module Ci let(:config) { { rspec: { script: "rspec", except: except } } } let(:processor) { GitlabCiYamlProcessor.new(YAML.dump(config)) } - shared_examples 'raises an error' do - it do - expect { processor }.to raise_error(GitlabCiYamlProcessor::ValidationError, 'jobs:rspec:except config should be an array of strings or regexps') - end - end - context 'when it is integer' do let(:except) { 1 } - it_behaves_like 'raises an error' + it do + expect { processor }.to raise_error(GitlabCiYamlProcessor::ValidationError, + 'jobs:rspec:except has to be either an array of conditions or a hash') + end end context 'when it is an array of integers' do let(:except) { [1, 1] } - it_behaves_like 'raises an error' + it do + expect { processor }.to raise_error(GitlabCiYamlProcessor::ValidationError, + 'jobs:rspec:except config should be an array of strings or regexps') + end end context 'when it is invalid regex' do let(:except) { ["/*invalid/"] } - it_behaves_like 'raises an error' + it do + expect { processor }.to raise_error(GitlabCiYamlProcessor::ValidationError, + 'jobs:rspec:except config should be an array of strings or regexps') + end end end end diff --git a/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb b/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb index f29431b937c..22708687a56 100644 --- a/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb +++ b/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb @@ -41,7 +41,7 @@ describe Gitlab::Auth::UniqueIpsLimiter, :clean_gitlab_redis_shared_state do context 'allow 2 unique ips' do before do - current_application_settings.update!(unique_ips_limit_per_user: 2) + Gitlab::CurrentSettings.current_application_settings.update!(unique_ips_limit_per_user: 2) end it 'blocks user trying to login from third ip' do diff --git a/spec/lib/gitlab/ci/config/entry/attributable_spec.rb b/spec/lib/gitlab/ci/config/entry/attributable_spec.rb index fde03c51e2c..b028b771375 100644 --- a/spec/lib/gitlab/ci/config/entry/attributable_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/attributable_spec.rb @@ -1,18 +1,21 @@ require 'spec_helper' describe Gitlab::Ci::Config::Entry::Attributable do - let(:node) { Class.new } + let(:node) do + Class.new do + include Gitlab::Ci::Config::Entry::Attributable + end + end + let(:instance) { node.new } before do - node.include(described_class) - node.class_eval do attributes :name, :test end end - context 'config is a hash' do + context 'when config is a hash' do before do allow(instance) .to receive(:config) @@ -29,7 +32,7 @@ describe Gitlab::Ci::Config::Entry::Attributable do end end - context 'config is not a hash' do + context 'when config is not a hash' do before do allow(instance) .to receive(:config) @@ -40,4 +43,18 @@ describe Gitlab::Ci::Config::Entry::Attributable do expect(instance.test).to be_nil end end + + context 'when method is already defined in a superclass' do + it 'raises an error' do + expectation = expect do + Class.new(String) do + include Gitlab::Ci::Config::Entry::Attributable + + attributes :length + end + end + + expectation.to raise_error(ArgumentError, 'Method already defined!') + end + end end diff --git a/spec/lib/gitlab/ci/config/entry/configurable_spec.rb b/spec/lib/gitlab/ci/config/entry/configurable_spec.rb index ae7e628b5b5..088d4b472da 100644 --- a/spec/lib/gitlab/ci/config/entry/configurable_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/configurable_spec.rb @@ -1,40 +1,26 @@ require 'spec_helper' describe Gitlab::Ci::Config::Entry::Configurable do - let(:entry) { Class.new } - - before do - entry.include(described_class) + let(:entry) do + Class.new(Gitlab::Ci::Config::Entry::Node) do + include Gitlab::Ci::Config::Entry::Configurable + end end describe 'validations' do - let(:validator) { entry.validator.new(instance) } - - before do - entry.class_eval do - attr_reader :config + context 'when entry is a hash' do + let(:instance) { entry.new(key: 'value') } - def initialize(config) - @config = config - end + it 'correctly validates an instance' do + expect(instance).to be_valid end - - validator.validate end - context 'when entry validator is invalid' do + context 'when entry is not a hash' do let(:instance) { entry.new('ls') } - it 'returns invalid validator' do - expect(validator).to be_invalid - end - end - - context 'when entry instance is valid' do - let(:instance) { entry.new(key: 'value') } - - it 'returns valid validator' do - expect(validator).to be_valid + it 'invalidates the instance' do + expect(instance).not_to be_valid end end end diff --git a/spec/lib/gitlab/ci/config/entry/policy_spec.rb b/spec/lib/gitlab/ci/config/entry/policy_spec.rb new file mode 100644 index 00000000000..36a84da4a52 --- /dev/null +++ b/spec/lib/gitlab/ci/config/entry/policy_spec.rb @@ -0,0 +1,73 @@ +require 'spec_helper' + +describe Gitlab::Ci::Config::Entry::Policy do + let(:entry) { described_class.new(config) } + + context 'when using simplified policy' do + describe 'validations' do + context 'when entry config value is valid' do + context 'when config is a branch or tag name' do + let(:config) { %w[master feature/branch] } + + describe '#valid?' do + it 'is valid' do + expect(entry).to be_valid + end + end + + describe '#value' do + it 'returns key value' do + expect(entry.value).to eq config + end + end + end + + context 'when config is a regexp' do + let(:config) { ['/^issue-.*$/'] } + + describe '#valid?' do + it 'is valid' do + expect(entry).to be_valid + end + end + end + + context 'when config is a special keyword' do + let(:config) { %w[tags triggers branches] } + + describe '#valid?' do + it 'is valid' do + expect(entry).to be_valid + end + end + end + end + + context 'when entry value is not valid' do + let(:config) { [1] } + + describe '#errors' do + it 'saves errors' do + expect(entry.errors) + .to include /policy config should be an array of strings or regexps/ + end + end + end + end + end + + context 'when policy strategy does not match' do + let(:config) { 'string strategy' } + + it 'returns information about errors' do + expect(entry.errors) + .to include /has to be either an array of conditions or a hash/ + end + end + + describe '.default' do + it 'does not have a default value' do + expect(described_class.default).to be_nil + end + end +end diff --git a/spec/lib/gitlab/ci/config/entry/simplifiable_spec.rb b/spec/lib/gitlab/ci/config/entry/simplifiable_spec.rb new file mode 100644 index 00000000000..395062207a3 --- /dev/null +++ b/spec/lib/gitlab/ci/config/entry/simplifiable_spec.rb @@ -0,0 +1,88 @@ +require 'spec_helper' + +describe Gitlab::Ci::Config::Entry::Simplifiable do + describe '.strategy' do + let(:entry) do + Class.new(described_class) do + strategy :Something, if: -> { 'condition' } + strategy :DifferentOne, if: -> { 'condition' } + end + end + + it 'defines entry strategies' do + expect(entry.strategies.size).to eq 2 + expect(entry.strategies.map(&:name)) + .to eq %i[Something DifferentOne] + end + end + + describe 'setting strategy by a condition' do + let(:first) { double('first strategy') } + let(:second) { double('second strategy') } + let(:unknown) { double('unknown strategy') } + + before do + stub_const("#{described_class.name}::Something", first) + stub_const("#{described_class.name}::DifferentOne", second) + stub_const("#{described_class.name}::UnknownStrategy", unknown) + end + + context 'when first strategy should be used' do + let(:entry) do + Class.new(described_class) do + strategy :Something, if: -> (arg) { arg == 'something' } + strategy :DifferentOne, if: -> (*) { false } + end + end + + it 'attemps to load a first strategy' do + expect(first).to receive(:new).with('something', anything) + + entry.new('something') + end + end + + context 'when second strategy should be used' do + let(:entry) do + Class.new(described_class) do + strategy :Something, if: -> (arg) { arg == 'something' } + strategy :DifferentOne, if: -> (arg) { arg == 'test' } + end + end + + it 'attemps to load a second strategy' do + expect(second).to receive(:new).with('test', anything) + + entry.new('test') + end + end + + context 'when neither one is a valid strategy' do + let(:entry) do + Class.new(described_class) do + strategy :Something, if: -> (*) { false } + strategy :DifferentOne, if: -> (*) { false } + end + end + + it 'instantiates an unknown strategy' do + expect(unknown).to receive(:new).with('test', anything) + + entry.new('test') + end + end + end + + context 'when a unknown strategy class is not defined' do + let(:entry) do + Class.new(described_class) do + strategy :String, if: -> (*) { true } + end + end + + it 'raises an error when being initialized' do + expect { entry.new('something') } + .to raise_error ArgumentError, /UndefinedStrategy not available!/ + end + end +end diff --git a/spec/lib/gitlab/ci/config/entry/trigger_spec.rb b/spec/lib/gitlab/ci/config/entry/trigger_spec.rb deleted file mode 100644 index e4ee44f1274..00000000000 --- a/spec/lib/gitlab/ci/config/entry/trigger_spec.rb +++ /dev/null @@ -1,56 +0,0 @@ -require 'spec_helper' - -describe Gitlab::Ci::Config::Entry::Trigger do - let(:entry) { described_class.new(config) } - - describe 'validations' do - context 'when entry config value is valid' do - context 'when config is a branch or tag name' do - let(:config) { %w[master feature/branch] } - - describe '#valid?' do - it 'is valid' do - expect(entry).to be_valid - end - end - - describe '#value' do - it 'returns key value' do - expect(entry.value).to eq config - end - end - end - - context 'when config is a regexp' do - let(:config) { ['/^issue-.*$/'] } - - describe '#valid?' do - it 'is valid' do - expect(entry).to be_valid - end - end - end - - context 'when config is a special keyword' do - let(:config) { %w[tags triggers branches] } - - describe '#valid?' do - it 'is valid' do - expect(entry).to be_valid - end - end - end - end - - context 'when entry value is not valid' do - let(:config) { [1] } - - describe '#errors' do - it 'saves errors' do - expect(entry.errors) - .to include 'trigger config should be an array of strings or regexps' - end - end - end - end -end diff --git a/spec/lib/gitlab/ci/config/entry/validatable_spec.rb b/spec/lib/gitlab/ci/config/entry/validatable_spec.rb index d1856801827..ae2a7a51ba6 100644 --- a/spec/lib/gitlab/ci/config/entry/validatable_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/validatable_spec.rb @@ -1,10 +1,10 @@ require 'spec_helper' describe Gitlab::Ci::Config::Entry::Validatable do - let(:entry) { Class.new } - - before do - entry.include(described_class) + let(:entry) do + Class.new(Gitlab::Ci::Config::Entry::Node) do + include Gitlab::Ci::Config::Entry::Validatable + end end describe '.validator' do @@ -28,7 +28,7 @@ describe Gitlab::Ci::Config::Entry::Validatable do end context 'when validating entry instance' do - let(:entry_instance) { entry.new } + let(:entry_instance) { entry.new('something') } context 'when attribute is valid' do before do diff --git a/spec/lib/gitlab/ci/config/entry/validator_spec.rb b/spec/lib/gitlab/ci/config/entry/validator_spec.rb index ad7e6f07d3c..172b6b47a4f 100644 --- a/spec/lib/gitlab/ci/config/entry/validator_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/validator_spec.rb @@ -48,7 +48,7 @@ describe Gitlab::Ci::Config::Entry::Validator do validator_instance.validate expect(validator_instance.messages) - .to include "node test attribute can't be blank" + .to include /test attribute can't be blank/ end end end diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb index cfadee0bcf5..c7930378240 100644 --- a/spec/lib/gitlab/shell_spec.rb +++ b/spec/lib/gitlab/shell_spec.rb @@ -186,22 +186,48 @@ describe Gitlab::Shell do end end - describe '#fetch_remote' do + shared_examples 'fetch_remote' do |gitaly_on| + let(:project2) { create(:project, :repository) } + let(:repository) { project2.repository } + def fetch_remote(ssh_auth = nil) - gitlab_shell.fetch_remote('current/storage', 'project/path', 'new/storage', ssh_auth: ssh_auth) + gitlab_shell.fetch_remote(repository.raw_repository, 'new/storage', ssh_auth: ssh_auth) end - def expect_popen(vars = {}) + def expect_popen(fail = false, vars = {}) popen_args = [ projects_path, 'fetch-remote', - 'current/storage', - 'project/path.git', + TestEnv.repos_path, + repository.relative_path, 'new/storage', Gitlab.config.gitlab_shell.git_timeout.to_s ] - expect(Gitlab::Popen).to receive(:popen).with(popen_args, nil, popen_vars.merge(vars)) + return_value = fail ? ["error", 1] : [nil, 0] + + expect(Gitlab::Popen).to receive(:popen).with(popen_args, nil, popen_vars.merge(vars)).and_return(return_value) + end + + def expect_gitaly_call(fail, vars = {}) + receive_fetch_remote = + if fail + receive(:fetch_remote).and_raise(GRPC::NotFound) + else + receive(:fetch_remote).and_return(true) + end + + expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive_fetch_remote + end + + if gitaly_on + def expect_call(fail, vars = {}) + expect_gitaly_call(fail, vars) + end + else + def expect_call(fail, vars = {}) + expect_popen(fail, vars) + end end def build_ssh_auth(opts = {}) @@ -216,20 +242,20 @@ describe Gitlab::Shell do end it 'returns true when the command succeeds' do - expect_popen.and_return([nil, 0]) + expect_call(false) expect(fetch_remote).to be_truthy end it 'raises an exception when the command fails' do - expect_popen.and_return(["error", 1]) + expect_call(true) - expect { fetch_remote }.to raise_error(Gitlab::Shell::Error, "error") + expect { fetch_remote }.to raise_error(Gitlab::Shell::Error) end context 'SSH auth' do it 'passes the SSH key if specified' do - expect_popen('GITLAB_SHELL_SSH_KEY' => 'foo').and_return([nil, 0]) + expect_call(false, 'GITLAB_SHELL_SSH_KEY' => 'foo') ssh_auth = build_ssh_auth(ssh_key_auth?: true, ssh_private_key: 'foo') @@ -237,7 +263,7 @@ describe Gitlab::Shell do end it 'does not pass an empty SSH key' do - expect_popen.and_return([nil, 0]) + expect_call(false) ssh_auth = build_ssh_auth(ssh_key_auth: true, ssh_private_key: '') @@ -245,7 +271,7 @@ describe Gitlab::Shell do end it 'does not pass the key unless SSH key auth is to be used' do - expect_popen.and_return([nil, 0]) + expect_call(false) ssh_auth = build_ssh_auth(ssh_key_auth: false, ssh_private_key: 'foo') @@ -253,7 +279,7 @@ describe Gitlab::Shell do end it 'passes the known_hosts data if specified' do - expect_popen('GITLAB_SHELL_KNOWN_HOSTS' => 'foo').and_return([nil, 0]) + expect_call(false, 'GITLAB_SHELL_KNOWN_HOSTS' => 'foo') ssh_auth = build_ssh_auth(ssh_known_hosts: 'foo') @@ -261,7 +287,7 @@ describe Gitlab::Shell do end it 'does not pass empty known_hosts data' do - expect_popen.and_return([nil, 0]) + expect_call(false) ssh_auth = build_ssh_auth(ssh_known_hosts: '') @@ -269,7 +295,7 @@ describe Gitlab::Shell do end it 'does not pass known_hosts data unless SSH is to be used' do - expect_popen(popen_vars).and_return([nil, 0]) + expect_call(false, popen_vars) ssh_auth = build_ssh_auth(ssh_import?: false, ssh_known_hosts: 'foo') @@ -278,6 +304,14 @@ describe Gitlab::Shell do end end + describe '#fetch_remote local', skip_gitaly_mock: true do + it_should_behave_like 'fetch_remote', false + end + + describe '#fetch_remote gitaly' do + it_should_behave_like 'fetch_remote', true + end + describe '#import_repository' do it 'returns true when the command succeeds' do expect(Gitlab::Popen).to receive(:popen) diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 4f77f0d85cd..0c35ad3c9d8 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -1257,8 +1257,12 @@ describe Ci::Build do context 'when build has user' do let(:user_variables) do - [{ key: 'GITLAB_USER_ID', value: user.id.to_s, public: true }, - { key: 'GITLAB_USER_EMAIL', value: user.email, public: true }] + [ + { key: 'GITLAB_USER_ID', value: user.id.to_s, public: true }, + { key: 'GITLAB_USER_EMAIL', value: user.email, public: true }, + { key: 'GITLAB_USER_LOGIN', value: user.username, public: true }, + { key: 'GITLAB_USER_NAME', value: user.name, public: true } + ] end before do diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index de86788d142..e547da0cfbe 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -769,4 +769,22 @@ describe Issue do expect(described_class.public_only).to eq([public_issue]) end end + + describe '#update_project_counter_caches?' do + it 'returns true when the state changes' do + subject.state = 'closed' + + expect(subject.update_project_counter_caches?).to eq(true) + end + + it 'returns true when the confidential flag changes' do + subject.confidential = true + + expect(subject.update_project_counter_caches?).to eq(true) + end + + it 'returns false when the state or confidential flag did not change' do + expect(subject.update_project_counter_caches?).to eq(false) + end + end end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 92cf15a5a51..09f3b97ec58 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -1700,4 +1700,16 @@ describe MergeRequest do .to change { project.open_merge_requests_count }.from(1).to(0) end end + + describe '#update_project_counter_caches?' do + it 'returns true when the state changes' do + subject.state = 'closed' + + expect(subject.update_project_counter_caches?).to eq(true) + end + + it 'returns false when the state did not change' do + expect(subject.update_project_counter_caches?).to eq(false) + end + end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 11717ba39e8..3621023f4ca 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -2234,6 +2234,28 @@ describe Project do end end + describe '#pages_available?' do + let(:project) { create(:project, group: group) } + + subject { project.pages_available? } + + before do + allow(Gitlab.config.pages).to receive(:enabled).and_return(true) + end + + context 'when the project is in a top level namespace' do + let(:group) { create(:group) } + + it { is_expected.to be(true) } + end + + context 'when the project is in a subgroup' do + let(:group) { create(:group, :nested) } + + it { is_expected.to be(false) } + end + end + describe '#remove_private_deploy_keys' do let!(:project) { create(:project) } diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb index ea97c556430..971eaf837cb 100644 --- a/spec/requests/api/files_spec.rb +++ b/spec/requests/api/files_spec.rb @@ -125,6 +125,15 @@ describe API::Files do expect(response).to have_http_status(200) end + it 'returns raw file info for files with dots' do + url = route('.gitignore') + "/raw" + expect(Gitlab::Workhorse).to receive(:send_git_blob) + + get api(url, current_user), params + + expect(response).to have_http_status(200) + end + it 'returns file by commit sha' do # This file is deleted on HEAD file_path = "files%2Fjs%2Fcommit%2Ejs%2Ecoffee" diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index e6a18654651..c2d6d7781b9 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -3,9 +3,9 @@ require 'spec_helper' describe SystemNoteService do include Gitlab::Routing - let(:group) { create(:group) } - let(:project) { create(:project, group: group) } - let(:author) { create(:user) } + set(:group) { create(:group) } + set(:project) { create(:project, :repository, group: group) } + set(:author) { create(:user) } let(:noteable) { create(:issue, project: project) } let(:issue) { noteable } @@ -29,8 +29,7 @@ describe SystemNoteService do describe '.add_commits' do subject { described_class.add_commits(noteable, project, author, new_commits, old_commits, oldrev) } - let(:project) { create(:project, :repository) } - let(:noteable) { create(:merge_request, source_project: project) } + let(:noteable) { create(:merge_request, source_project: project, target_project: project) } let(:new_commits) { noteable.commits } let(:old_commits) { [] } let(:oldrev) { nil } @@ -185,7 +184,7 @@ describe SystemNoteService do describe '.change_label' do subject { described_class.change_label(noteable, project, author, added, removed) } - let(:labels) { create_list(:label, 2) } + let(:labels) { create_list(:label, 2, project: project) } let(:added) { [] } let(:removed) { [] } @@ -294,7 +293,6 @@ describe SystemNoteService do end describe '.merge_when_pipeline_succeeds' do - let(:project) { create(:project, :repository) } let(:pipeline) { build(:ci_pipeline_without_jobs )} let(:noteable) do create(:merge_request, source_project: project, target_project: project) @@ -312,7 +310,6 @@ describe SystemNoteService do end describe '.cancel_merge_when_pipeline_succeeds' do - let(:project) { create(:project, :repository) } let(:noteable) do create(:merge_request, source_project: project, target_project: project) end @@ -390,7 +387,6 @@ describe SystemNoteService do describe '.change_branch' do subject { described_class.change_branch(noteable, project, author, 'target', old_branch, new_branch) } - let(:project) { create(:project, :repository) } let(:old_branch) { 'old_branch'} let(:new_branch) { 'new_branch'} @@ -408,8 +404,6 @@ describe SystemNoteService do describe '.change_branch_presence' do subject { described_class.change_branch_presence(noteable, project, author, :source, 'feature', :delete) } - let(:project) { create(:project, :repository) } - it_behaves_like 'a system note' do let(:action) { 'branch' } end @@ -424,8 +418,6 @@ describe SystemNoteService do describe '.new_issue_branch' do subject { described_class.new_issue_branch(noteable, project, author, "1-mepmep") } - let(:project) { create(:project, :repository) } - it_behaves_like 'a system note' do let(:action) { 'branch' } end @@ -471,7 +463,7 @@ describe SystemNoteService do describe 'note_body' do context 'cross-project' do - let(:project2) { create(:project, :repository) } + let(:project2) { create(:project, :repository) } let(:mentioner) { create(:issue, project: project2) } context 'from Commit' do @@ -491,7 +483,6 @@ describe SystemNoteService do context 'within the same project' do context 'from Commit' do - let(:project) { create(:project, :repository) } let(:mentioner) { project.repository.commit } it 'references the mentioning commit' do @@ -533,7 +524,6 @@ describe SystemNoteService do end context 'when mentioner is a MergeRequest' do - let(:project) { create(:project, :repository) } let(:mentioner) { create(:merge_request, :simple, source_project: project) } let(:noteable) { project.commit } @@ -561,7 +551,6 @@ describe SystemNoteService do end describe '.cross_reference_exists?' do - let(:project) { create(:project, :repository) } let(:commit0) { project.commit } let(:commit1) { project.commit('HEAD~2') } @@ -899,9 +888,8 @@ describe SystemNoteService do end describe '.discussion_continued_in_issue' do - let(:discussion) { create(:diff_note_on_merge_request).to_discussion } + let(:discussion) { create(:diff_note_on_merge_request, project: project).to_discussion } let(:merge_request) { discussion.noteable } - let(:project) { merge_request.source_project } let(:issue) { create(:issue, project: project) } def reloaded_merge_request @@ -1023,7 +1011,6 @@ describe SystemNoteService do end describe '.add_merge_request_wip_from_commit' do - let(:project) { create(:project, :repository) } let(:noteable) do create(:merge_request, source_project: project, target_project: project) end @@ -1078,9 +1065,8 @@ describe SystemNoteService do end describe '.diff_discussion_outdated' do - let(:discussion) { create(:diff_note_on_merge_request).to_discussion } + let(:discussion) { create(:diff_note_on_merge_request, project: project).to_discussion } let(:merge_request) { discussion.noteable } - let(:project) { merge_request.source_project } let(:change_position) { discussion.position } def reloaded_merge_request diff --git a/spec/support/stub_env.rb b/spec/support/stub_env.rb index b8928867174..19fbe572930 100644 --- a/spec/support/stub_env.rb +++ b/spec/support/stub_env.rb @@ -1,5 +1,7 @@ # Inspired by https://github.com/ljkbennett/stub_env/blob/master/lib/stub_env/helpers.rb module StubENV + include Gitlab::CurrentSettings + def stub_env(key_or_hash, value = nil) init_stub unless env_stubbed? if key_or_hash.is_a? Hash diff --git a/spec/views/admin/dashboard/index.html.haml_spec.rb b/spec/views/admin/dashboard/index.html.haml_spec.rb index df742bf6848..b4359d819a0 100644 --- a/spec/views/admin/dashboard/index.html.haml_spec.rb +++ b/spec/views/admin/dashboard/index.html.haml_spec.rb @@ -9,6 +9,7 @@ describe 'admin/dashboard/index.html.haml' do assign(:groups, create_list(:group, 1)) allow(view).to receive(:admin?).and_return(true) + allow(view).to receive(:current_application_settings).and_return(Gitlab::CurrentSettings.current_application_settings) end it "shows version of GitLab Workhorse" do diff --git a/spec/views/devise/shared/_signin_box.html.haml_spec.rb b/spec/views/devise/shared/_signin_box.html.haml_spec.rb index 9adbb0476be..0870b8f09f9 100644 --- a/spec/views/devise/shared/_signin_box.html.haml_spec.rb +++ b/spec/views/devise/shared/_signin_box.html.haml_spec.rb @@ -5,6 +5,7 @@ describe 'devise/shared/_signin_box' do before do stub_devise assign(:ldap_servers, []) + allow(view).to receive(:current_application_settings).and_return(Gitlab::CurrentSettings.current_application_settings) end it 'is shown when Crowd is enabled' do diff --git a/spec/views/help/index.html.haml_spec.rb b/spec/views/help/index.html.haml_spec.rb index 1f8261cc46b..c030129559e 100644 --- a/spec/views/help/index.html.haml_spec.rb +++ b/spec/views/help/index.html.haml_spec.rb @@ -37,5 +37,6 @@ describe 'help/index' do def stub_helpers allow(view).to receive(:markdown).and_return('') allow(view).to receive(:version_status_badge).and_return('') + allow(view).to receive(:current_application_settings).and_return(Gitlab::CurrentSettings.current_application_settings) end end diff --git a/spec/views/layouts/_head.html.haml_spec.rb b/spec/views/layouts/_head.html.haml_spec.rb index 8020faa1f9c..e8e6d2e7a75 100644 --- a/spec/views/layouts/_head.html.haml_spec.rb +++ b/spec/views/layouts/_head.html.haml_spec.rb @@ -1,6 +1,10 @@ require 'spec_helper' describe 'layouts/_head' do + before do + allow(view).to receive(:current_application_settings).and_return(Gitlab::CurrentSettings.current_application_settings) + end + it 'escapes HTML-safe strings in page_title' do stub_helper_with_safe_string(:page_title) diff --git a/spec/views/projects/commits/_commit.html.haml_spec.rb b/spec/views/projects/commits/_commit.html.haml_spec.rb index 4c247361bd7..00547e433c4 100644 --- a/spec/views/projects/commits/_commit.html.haml_spec.rb +++ b/spec/views/projects/commits/_commit.html.haml_spec.rb @@ -1,6 +1,10 @@ require 'spec_helper' describe 'projects/commits/_commit.html.haml' do + before do + allow(view).to receive(:current_application_settings).and_return(Gitlab::CurrentSettings.current_application_settings) + end + context 'with a singed commit' do let(:project) { create(:project, :repository) } let(:repository) { project.repository } diff --git a/spec/views/projects/edit.html.haml_spec.rb b/spec/views/projects/edit.html.haml_spec.rb index 1af422941d7..c1398629749 100644 --- a/spec/views/projects/edit.html.haml_spec.rb +++ b/spec/views/projects/edit.html.haml_spec.rb @@ -10,7 +10,9 @@ describe 'projects/edit' do assign(:project, project) allow(controller).to receive(:current_user).and_return(user) - allow(view).to receive_messages(current_user: user, can?: true) + allow(view).to receive_messages(current_user: user, + can?: true, + current_application_settings: Gitlab::CurrentSettings.current_application_settings) end context 'LFS enabled setting' do diff --git a/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb b/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb index 5770cf92b4e..9ab105c3238 100644 --- a/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb +++ b/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb @@ -14,6 +14,7 @@ describe 'projects/merge_requests/creations/_new_submit.html.haml' do allow(view).to receive(:can?).and_return(true) allow(view).to receive(:url_for).and_return('#') allow(view).to receive(:current_user).and_return(merge_request.author) + allow(view).to receive(:current_application_settings).and_return(Gitlab::CurrentSettings.current_application_settings) end context 'when there are pipelines for merge request but no pipeline for last commit' do diff --git a/spec/views/projects/merge_requests/show.html.haml_spec.rb b/spec/views/projects/merge_requests/show.html.haml_spec.rb index dc2fcc3e715..6f29d12373a 100644 --- a/spec/views/projects/merge_requests/show.html.haml_spec.rb +++ b/spec/views/projects/merge_requests/show.html.haml_spec.rb @@ -25,7 +25,9 @@ describe 'projects/merge_requests/show.html.haml' do assign(:notes, []) assign(:pipelines, Ci::Pipeline.none) - allow(view).to receive_messages(current_user: user, can?: true) + allow(view).to receive_messages(current_user: user, + can?: true, + current_application_settings: Gitlab::CurrentSettings.current_application_settings) end context 'when the merge request is closed' do diff --git a/spec/views/projects/tree/show.html.haml_spec.rb b/spec/views/projects/tree/show.html.haml_spec.rb index 33eba3e6d3d..3c25e341b39 100644 --- a/spec/views/projects/tree/show.html.haml_spec.rb +++ b/spec/views/projects/tree/show.html.haml_spec.rb @@ -12,6 +12,7 @@ describe 'projects/tree/show' do allow(view).to receive(:can?).and_return(true) allow(view).to receive(:can_collaborate_with_project?).and_return(true) + allow(view).to receive(:current_application_settings).and_return(Gitlab::CurrentSettings.current_application_settings) end context 'for branch names ending on .json' do diff --git a/spec/views/shared/projects/_project.html.haml_spec.rb b/spec/views/shared/projects/_project.html.haml_spec.rb index b500016016a..f0a4f153699 100644 --- a/spec/views/shared/projects/_project.html.haml_spec.rb +++ b/spec/views/shared/projects/_project.html.haml_spec.rb @@ -3,6 +3,10 @@ require 'spec_helper' describe 'shared/projects/_project.html.haml' do let(:project) { create(:project) } + before do + allow(view).to receive(:current_application_settings).and_return(Gitlab::CurrentSettings.current_application_settings) + end + it 'should render creator avatar if project has a creator' do render 'shared/projects/project', use_creator_avatar: true, project: project |