Commit a9a15124 authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'master' into fl-eslint-vue-house-keeping

* master: (48 commits)
  Avoid checking the user format in every url validation
  Migrate CycleAnalytics::CommitCount to Gitaly
  Hide project name if searching against a project
  Unify app/views/search/results by using EE
  Resolve "Table on Failed Jobs tab is overflowing in IE11 and sm screens"
  Update MrWidgetAuthorTime and MRWidgetMerged spec
  fixed specs
  Fix IDE pipelines eTagPoll not stopping
  Don't use Gitlab::Utils.nlbr in Gitlab::Git
  Move gitaly_blame,  gitaly_count_commits, gitaly_commit_count to opt-out
  Rename MrWidgetAuthorTime vue component
  Use Tooltip component in MrWidgetAuthorTime vue component
  set max_old_space_size to 3.5 GB for compile-assets job
  Remove SCLAU to mirror https://gitlab.com/gitlab-org/gitlab-ee/commit/cd5cef8f84a2b8c58a741e90afec232243a9f3a9
  Add missing `:comment` attribute
  Prevent ENV from leaking variables in CI output
  Bump grape-path-helpers to 1.0.5
  Add more logging before a project is destroyed
  Bump Google Chrome to V67
  Upgrade gitlab-markup to fix render issue with reStructuredText
  ...
parents 647a4d6a 3bd5e10e
image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.4.4-golang-1.9-git-2.17-chrome-65.0-node-8.x-yarn-1.2-postgresql-9.6-graphicsmagick-1.3.29" image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.4.4-golang-1.9-git-2.17-chrome-67.0-node-8.x-yarn-1.2-postgresql-9.6-graphicsmagick-1.3.29"
.dedicated-runner: &dedicated-runner .dedicated-runner: &dedicated-runner
retry: 1 retry: 1
...@@ -394,7 +394,11 @@ compile-assets: ...@@ -394,7 +394,11 @@ compile-assets:
- date - date
- yarn install --frozen-lockfile --cache-folder .yarn-cache - yarn install --frozen-lockfile --cache-folder .yarn-cache
- date - date
- free -m
- bundle exec rake gitlab:assets:compile - bundle exec rake gitlab:assets:compile
variables:
# we override the max_old_space_size to prevent OOM errors
NODE_OPTIONS: --max_old_space_size=3584
artifacts: artifacts:
expire_in: 7d expire_in: 7d
paths: paths:
...@@ -658,10 +662,13 @@ gitlab:assets:compile: ...@@ -658,10 +662,13 @@ gitlab:assets:compile:
SKIP_STORAGE_VALIDATION: "true" SKIP_STORAGE_VALIDATION: "true"
WEBPACK_REPORT: "true" WEBPACK_REPORT: "true"
NO_COMPRESSION: "true" NO_COMPRESSION: "true"
# we override the max_old_space_size to prevent OOM errors
NODE_OPTIONS: --max_old_space_size=3584
script: script:
- date - date
- yarn install --frozen-lockfile --production --cache-folder .yarn-cache - yarn install --frozen-lockfile --production --cache-folder .yarn-cache
- date - date
- free -m
- bundle exec rake gitlab:assets:compile - bundle exec rake gitlab:assets:compile
artifacts: artifacts:
name: webpack-report name: webpack-report
......
...@@ -134,7 +134,7 @@ gem 'seed-fu', '~> 2.3.7' ...@@ -134,7 +134,7 @@ gem 'seed-fu', '~> 2.3.7'
# Markdown and HTML processing # Markdown and HTML processing
gem 'html-pipeline', '~> 2.7.1' gem 'html-pipeline', '~> 2.7.1'
gem 'deckar01-task_list', '2.0.0' gem 'deckar01-task_list', '2.0.0'
gem 'gitlab-markup', '~> 1.6.2' gem 'gitlab-markup', '~> 1.6.4'
gem 'redcarpet', '~> 3.4' gem 'redcarpet', '~> 3.4'
gem 'commonmarker', '~> 0.17' gem 'commonmarker', '~> 0.17'
gem 'RedCloth', '~> 4.3.2' gem 'RedCloth', '~> 4.3.2'
...@@ -333,7 +333,7 @@ group :development, :test do ...@@ -333,7 +333,7 @@ group :development, :test do
gem 'database_cleaner', '~> 1.5.0' gem 'database_cleaner', '~> 1.5.0'
gem 'factory_bot_rails', '~> 4.8.2' gem 'factory_bot_rails', '~> 4.8.2'
gem 'rspec-rails', '~> 3.6.0' gem 'rspec-rails', '~> 3.7.0'
gem 'rspec-retry', '~> 0.4.5' gem 'rspec-retry', '~> 0.4.5'
gem 'rspec_profiling', '~> 0.0.5' gem 'rspec_profiling', '~> 0.0.5'
gem 'rspec-set', '~> 0.1.3' gem 'rspec-set', '~> 0.1.3'
......
...@@ -312,7 +312,7 @@ GEM ...@@ -312,7 +312,7 @@ GEM
diff-lcs (~> 1.1) diff-lcs (~> 1.1)
mime-types (>= 1.16) mime-types (>= 1.16)
posix-spawn (~> 0.3) posix-spawn (~> 0.3)
gitlab-markup (1.6.3) gitlab-markup (1.6.4)
gitlab-styles (2.3.2) gitlab-styles (2.3.2)
rubocop (~> 0.51) rubocop (~> 0.51)
rubocop-gitlab-security (~> 0.1.0) rubocop-gitlab-security (~> 0.1.0)
...@@ -360,8 +360,8 @@ GEM ...@@ -360,8 +360,8 @@ GEM
grape-entity (0.7.1) grape-entity (0.7.1)
activesupport (>= 4.0) activesupport (>= 4.0)
multi_json (>= 1.3.2) multi_json (>= 1.3.2)
grape-path-helpers (1.0.4) grape-path-helpers (1.0.5)
activesupport (~> 4) activesupport (>= 4, < 5.1)
grape (~> 1.0) grape (~> 1.0)
rake (~> 12) rake (~> 12)
grape_logging (1.7.0) grape_logging (1.7.0)
...@@ -742,36 +742,36 @@ GEM ...@@ -742,36 +742,36 @@ GEM
chunky_png chunky_png
rqrcode-rails3 (0.1.7) rqrcode-rails3 (0.1.7)
rqrcode (>= 0.4.2) rqrcode (>= 0.4.2)
rspec (3.6.0) rspec (3.7.0)
rspec-core (~> 3.6.0) rspec-core (~> 3.7.0)
rspec-expectations (~> 3.6.0) rspec-expectations (~> 3.7.0)
rspec-mocks (~> 3.6.0) rspec-mocks (~> 3.7.0)
rspec-core (3.6.0) rspec-core (3.7.1)
rspec-support (~> 3.6.0) rspec-support (~> 3.7.0)
rspec-expectations (3.6.0) rspec-expectations (3.7.0)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.6.0) rspec-support (~> 3.7.0)
rspec-mocks (3.6.0) rspec-mocks (3.7.0)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.6.0) rspec-support (~> 3.7.0)
rspec-parameterized (0.4.0) rspec-parameterized (0.4.0)
binding_of_caller binding_of_caller
parser parser
proc_to_ast proc_to_ast
rspec (>= 2.13, < 4) rspec (>= 2.13, < 4)
unparser unparser
rspec-rails (3.6.0) rspec-rails (3.7.2)
actionpack (>= 3.0) actionpack (>= 3.0)
activesupport (>= 3.0) activesupport (>= 3.0)
railties (>= 3.0) railties (>= 3.0)
rspec-core (~> 3.6.0) rspec-core (~> 3.7.0)
rspec-expectations (~> 3.6.0) rspec-expectations (~> 3.7.0)
rspec-mocks (~> 3.6.0) rspec-mocks (~> 3.7.0)
rspec-support (~> 3.6.0) rspec-support (~> 3.7.0)
rspec-retry (0.4.5) rspec-retry (0.4.5)
rspec-core rspec-core
rspec-set (0.1.3) rspec-set (0.1.3)
rspec-support (3.6.0) rspec-support (3.7.1)
rspec_profiling (0.0.5) rspec_profiling (0.0.5)
activerecord activerecord
pg pg
...@@ -1044,7 +1044,7 @@ DEPENDENCIES ...@@ -1044,7 +1044,7 @@ DEPENDENCIES
gitlab-flowdock-git-hook (~> 1.0.1) gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-gollum-lib (~> 4.2) gitlab-gollum-lib (~> 4.2)
gitlab-gollum-rugged_adapter (~> 0.4.4) gitlab-gollum-rugged_adapter (~> 0.4.4)
gitlab-markup (~> 1.6.2) gitlab-markup (~> 1.6.4)
gitlab-styles (~> 2.3) gitlab-styles (~> 2.3)
gitlab_omniauth-ldap (~> 2.0.4) gitlab_omniauth-ldap (~> 2.0.4)
gon (~> 6.2) gon (~> 6.2)
...@@ -1141,7 +1141,7 @@ DEPENDENCIES ...@@ -1141,7 +1141,7 @@ DEPENDENCIES
rouge (~> 3.1) rouge (~> 3.1)
rqrcode-rails3 (~> 0.1.7) rqrcode-rails3 (~> 0.1.7)
rspec-parameterized rspec-parameterized
rspec-rails (~> 3.6.0) rspec-rails (~> 3.7.0)
rspec-retry (~> 0.4.5) rspec-retry (~> 0.4.5)
rspec-set (~> 0.1.3) rspec-set (~> 0.1.3)
rspec_profiling (~> 0.0.5) rspec_profiling (~> 0.0.5)
......
...@@ -286,7 +286,7 @@ GEM ...@@ -286,7 +286,7 @@ GEM
gettext_i18n_rails (>= 0.7.1) gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0) po_to_json (>= 1.0.0)
rails (>= 3.2.0) rails (>= 3.2.0)
gitaly-proto (0.100.0) gitaly-proto (0.101.0)
google-protobuf (~> 3.1) google-protobuf (~> 3.1)
grpc (~> 1.10) grpc (~> 1.10)
github-linguist (5.3.3) github-linguist (5.3.3)
...@@ -363,10 +363,10 @@ GEM ...@@ -363,10 +363,10 @@ GEM
grape-entity (0.7.1) grape-entity (0.7.1)
activesupport (>= 4.0) activesupport (>= 4.0)
multi_json (>= 1.3.2) multi_json (>= 1.3.2)
grape-path-helpers (1.0.0) grape-path-helpers (1.0.5)
activesupport activesupport (>= 4, < 5.1)
grape (~> 1.0) grape (~> 1.0)
rake rake (~> 12)
grape_logging (1.7.0) grape_logging (1.7.0)
grape grape
graphiql-rails (1.4.10) graphiql-rails (1.4.10)
...@@ -501,6 +501,7 @@ GEM ...@@ -501,6 +501,7 @@ GEM
mime-types-data (~> 3.2015) mime-types-data (~> 3.2015)
mime-types-data (3.2016.0521) mime-types-data (3.2016.0521)
mimemagic (0.3.0) mimemagic (0.3.0)
mini_magick (4.8.0)
mini_mime (1.0.0) mini_mime (1.0.0)
mini_portile2 (2.3.0) mini_portile2 (2.3.0)
minitest (5.7.0) minitest (5.7.0)
...@@ -1048,7 +1049,7 @@ DEPENDENCIES ...@@ -1048,7 +1049,7 @@ DEPENDENCIES
gettext (~> 3.2.2) gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3) gettext_i18n_rails_js (~> 1.3)
gitaly-proto (~> 0.100.0) gitaly-proto (~> 0.101.0)
github-linguist (~> 5.3.3) github-linguist (~> 5.3.3)
gitlab-flowdock-git-hook (~> 1.0.1) gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-gollum-lib (~> 4.2) gitlab-gollum-lib (~> 4.2)
...@@ -1091,6 +1092,7 @@ DEPENDENCIES ...@@ -1091,6 +1092,7 @@ DEPENDENCIES
loofah (~> 2.2) loofah (~> 2.2)
mail_room (~> 0.9.1) mail_room (~> 0.9.1)
method_source (~> 0.8) method_source (~> 0.8)
mini_magick
minitest (~> 5.7.0) minitest (~> 5.7.0)
mousetrap-rails (~> 1.4.6) mousetrap-rails (~> 1.4.6)
mysql2 (~> 0.4.10) mysql2 (~> 0.4.10)
......
...@@ -95,7 +95,7 @@ export default class ClusterStore { ...@@ -95,7 +95,7 @@ export default class ClusterStore {
this.state.applications.jupyter.hostname = this.state.applications.jupyter.hostname =
serverAppEntry.hostname || serverAppEntry.hostname ||
(this.state.applications.ingress.externalIp (this.state.applications.ingress.externalIp
? `jupyter.${this.state.applications.ingress.externalIp}.xip.io` ? `jupyter.${this.state.applications.ingress.externalIp}.nip.io`
: ''); : '');
} }
}); });
......
...@@ -31,10 +31,15 @@ export const openMergeRequest = ({ commit, dispatch }, { projectPath, id }) => { ...@@ -31,10 +31,15 @@ export const openMergeRequest = ({ commit, dispatch }, { projectPath, id }) => {
commit(rootTypes.CLEAR_PROJECTS, null, { root: true }); commit(rootTypes.CLEAR_PROJECTS, null, { root: true });
commit(rootTypes.SET_CURRENT_MERGE_REQUEST, `${id}`, { root: true }); commit(rootTypes.SET_CURRENT_MERGE_REQUEST, `${id}`, { root: true });
commit(rootTypes.RESET_OPEN_FILES, null, { root: true }); commit(rootTypes.RESET_OPEN_FILES, null, { root: true });
dispatch('pipelines/stopPipelinePolling', null, { root: true });
dispatch('pipelines/clearEtagPoll', null, { root: true });
dispatch('pipelines/resetLatestPipeline', null, { root: true }); dispatch('pipelines/resetLatestPipeline', null, { root: true });
dispatch('setCurrentBranchId', '', { root: true }); dispatch('setCurrentBranchId', '', { root: true });
dispatch('pipelines/stopPipelinePolling', null, { root: true })
.then(() => {
dispatch('pipelines/clearEtagPoll', null, { root: true });
})
.catch(e => {
throw e;
});
router.push(`/project/${projectPath}/merge_requests/${id}`); router.push(`/project/${projectPath}/merge_requests/${id}`);
}; };
......
...@@ -12,8 +12,12 @@ let eTagPoll; ...@@ -12,8 +12,12 @@ let eTagPoll;
export const clearEtagPoll = () => { export const clearEtagPoll = () => {
eTagPoll = null; eTagPoll = null;
}; };
export const stopPipelinePolling = () => eTagPoll && eTagPoll.stop(); export const stopPipelinePolling = () => {
export const restartPipelinePolling = () => eTagPoll && eTagPoll.restart(); if (eTagPoll) eTagPoll.stop();
};
export const restartPipelinePolling = () => {
if (eTagPoll) eTagPoll.restart();
};
export const requestLatestPipeline = ({ commit }) => commit(types.REQUEST_LATEST_PIPELINE); export const requestLatestPipeline = ({ commit }) => commit(types.REQUEST_LATEST_PIPELINE);
export const receiveLatestPipelineError = ({ commit, dispatch }) => { export const receiveLatestPipelineError = ({ commit, dispatch }) => {
...@@ -51,9 +55,9 @@ export const fetchLatestPipeline = ({ dispatch, rootGetters }) => { ...@@ -51,9 +55,9 @@ export const fetchLatestPipeline = ({ dispatch, rootGetters }) => {
Visibility.change(() => { Visibility.change(() => {
if (!Visibility.hidden()) { if (!Visibility.hidden()) {
eTagPoll.restart(); dispatch('restartPipelinePolling');
} else { } else {
eTagPoll.stop(); dispatch('stopPipelinePolling');
} }
}); });
}; };
......
<script> <script>
import { parseSeconds, stringifyTime } from '../../../lib/utils/pretty_time'; import { parseSeconds, stringifyTime } from '../../../lib/utils/pretty_time';
import tooltip from '../../../vue_shared/directives/tooltip';
export default { export default {
name: 'TimeTrackingComparisonPane', name: 'TimeTrackingComparisonPane',
directives: {
tooltip,
},
props: { props: {
timeSpent: { timeSpent: {
type: Number, type: Number,
...@@ -50,9 +54,8 @@ export default { ...@@ -50,9 +54,8 @@ export default {
<template> <template>
<div class="time-tracking-comparison-pane"> <div class="time-tracking-comparison-pane">
<div <div
:aria-valuenow="timeRemainingTooltip" v-tooltip
:title="timeRemainingTooltip" :title="timeRemainingTooltip"
:data-original-title="timeRemainingTooltip"
:class="timeRemainingStatusClass" :class="timeRemainingStatusClass"
class="compare-meter" class="compare-meter"
data-toggle="tooltip" data-toggle="tooltip"
...@@ -62,7 +65,6 @@ export default { ...@@ -62,7 +65,6 @@ export default {
<div <div
:aria-valuenow="timeRemainingPercent" :aria-valuenow="timeRemainingPercent"
class="meter-container" class="meter-container"
role="timeSpentPercent"
> >
<div <div
:style="{ width: timeRemainingPercent }" :style="{ width: timeRemainingPercent }"
......
<script> <script>
import tooltip from '~/vue_shared/directives/tooltip';
import MrWidgetAuthor from './mr_widget_author.vue'; import MrWidgetAuthor from './mr_widget_author.vue';
export default { export default {
name: 'MRWidgetAuthorTime', name: 'MrWidgetAuthorTime',
components: { components: {
MrWidgetAuthor, MrWidgetAuthor,
}, },
directives: {
tooltip,
},
props: { props: {
actionText: { actionText: {
type: String, type: String,
...@@ -31,9 +35,8 @@ ...@@ -31,9 +35,8 @@
{{ actionText }} {{ actionText }}
<mr-widget-author :author="author" /> <mr-widget-author :author="author" />
<time <time
v-tooltip
:title="dateTitle" :title="dateTitle"
data-toggle="tooltip"
data-placement="top"
data-container="body" data-container="body"
> >
{{ dateReadable }} {{ dateReadable }}
......
<script> <script>
import mrWidgetAuthorTime from '../../components/mr_widget_author_time.vue'; import MrWidgetAuthorTime from '../../components/mr_widget_author_time.vue';
import statusIcon from '../mr_widget_status_icon.vue'; import statusIcon from '../mr_widget_status_icon.vue';
export default { export default {
name: 'MRWidgetClosed', name: 'MRWidgetClosed',
components: { components: {
mrWidgetAuthorTime, MrWidgetAuthorTime,
statusIcon, statusIcon,
}, },
props: { props: {
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
import loadingIcon from '~/vue_shared/components/loading_icon.vue'; import loadingIcon from '~/vue_shared/components/loading_icon.vue';
import { s__, __ } from '~/locale'; import { s__, __ } from '~/locale';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import mrWidgetAuthorTime from '../../components/mr_widget_author_time.vue'; import MrWidgetAuthorTime from '../../components/mr_widget_author_time.vue';
import statusIcon from '../mr_widget_status_icon.vue'; import statusIcon from '../mr_widget_status_icon.vue';
import eventHub from '../../event_hub'; import eventHub from '../../event_hub';
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
tooltip, tooltip,
}, },
components: { components: {
mrWidgetAuthorTime, MrWidgetAuthorTime,
loadingIcon, loadingIcon,
statusIcon, statusIcon,
ClipboardButton, ClipboardButton,
......
...@@ -58,8 +58,13 @@ table { ...@@ -58,8 +58,13 @@ table {
display: none; display: none;
} }
table,
tbody,
td { td {
display: block; display: block;
}
td {
color: $gl-text-color-secondary; color: $gl-text-color-secondary;
} }
......
...@@ -3,6 +3,9 @@ class RegistrationsController < Devise::RegistrationsController ...@@ -3,6 +3,9 @@ class RegistrationsController < Devise::RegistrationsController
include AcceptsPendingInvitations include AcceptsPendingInvitations
before_action :whitelist_query_limiting, only: [:destroy] before_action :whitelist_query_limiting, only: [:destroy]
before_action :ensure_terms_accepted,
if: -> { Gitlab::CurrentSettings.current_application_settings.enforce_terms? },
only: [:create]
def new def new
redirect_to(new_user_session_path) redirect_to(new_user_session_path)
...@@ -18,7 +21,9 @@ class RegistrationsController < Devise::RegistrationsController ...@@ -18,7 +21,9 @@ class RegistrationsController < Devise::RegistrationsController
if !Gitlab::Recaptcha.load_configurations! || verify_recaptcha if !Gitlab::Recaptcha.load_configurations! || verify_recaptcha
accept_pending_invitations accept_pending_invitations
super super do |new_user|
persist_accepted_terms_if_required(new_user)
end
else else
flash[:alert] = 'There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.' flash[:alert] = 'There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.'
flash.delete :recaptcha_error flash.delete :recaptcha_error
...@@ -40,6 +45,16 @@ class RegistrationsController < Devise::RegistrationsController ...@@ -40,6 +45,16 @@ class RegistrationsController < Devise::RegistrationsController
protected protected
def persist_accepted_terms_if_required(new_user)
return unless new_user.persisted?
return unless Gitlab::CurrentSettings.current_application_settings.enforce_terms?
if terms_accepted?
terms = ApplicationSetting::Term.latest
Users::RespondToTermsService.new(new_user, terms).execute(accepted: true)
end
end
def destroy_confirmation_valid? def destroy_confirmation_valid?
if current_user.confirm_deletion_with_password? if current_user.confirm_deletion_with_password?
current_user.valid_password?(params[:password]) current_user.valid_password?(params[:password])
...@@ -91,4 +106,14 @@ class RegistrationsController < Devise::RegistrationsController ...@@ -91,4 +106,14 @@ class RegistrationsController < Devise::RegistrationsController
def whitelist_query_limiting def whitelist_query_limiting
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-ce/issues/42380') Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-ce/issues/42380')
end end
def ensure_terms_accepted
return if terms_accepted?
redirect_to new_user_session_path, alert: _('You must accept our Terms of Service and privacy policy in order to register an account')
end
def terms_accepted?
Gitlab::Utils.to_boolean(params[:terms_opt_in])
end
end end
...@@ -2,6 +2,7 @@ module Users ...@@ -2,6 +2,7 @@ module Users
class TermsController < ApplicationController class TermsController < ApplicationController
include InternalRedirect include InternalRedirect
skip_before_action :authenticate_user!
skip_before_action :enforce_terms! skip_before_action :enforce_terms!
skip_before_action :check_password_expiration skip_before_action :check_password_expiration
skip_before_action :check_two_factor_requirement skip_before_action :check_two_factor_requirement
...@@ -14,7 +15,7 @@ module Users ...@@ -14,7 +15,7 @@ module Users
def index def index
@redirect = redirect_path @redirect = redirect_path
if @term.accepted_by_user?(current_user) if current_user && @term.accepted_by_user?(current_user)
flash.now[:notice] = "You have already accepted the Terms of Service as #{current_user.to_reference}" flash.now[:notice] = "You have already accepted the Terms of Service as #{current_user.to_reference}"
end end
end end
......
...@@ -8,6 +8,7 @@ module Ci ...@@ -8,6 +8,7 @@ module Ci
include Gitlab::OptimisticLocking include Gitlab::OptimisticLocking
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
include AtomicInternalId include AtomicInternalId
include EnumWithNil
belongs_to :project, inverse_of: :pipelines belongs_to :project, inverse_of: :pipelines
belongs_to :user belongs_to :user
...@@ -54,7 +55,7 @@ module Ci ...@@ -54,7 +55,7 @@ module Ci
after_create :keep_around_commits, unless: :importing? after_create :keep_around_commits, unless: :importing?
enum source: { enum_with_nil source: {
unknown: nil, unknown: nil,
push: 1, push: 1,
web: 2, web: 2,
...@@ -64,7 +65,7 @@ module Ci ...@@ -64,7 +65,7 @@ module Ci
external: 6 external: 6
} }
enum config_source: { enum_with_nil config_source: {
unknown_source: nil, unknown_source: nil,
repository_source: 1, repository_source: 1,
auto_devops_source: 2 auto_devops_source: 2
...@@ -599,17 +600,6 @@ module Ci ...@@ -599,17 +600,6 @@ module Ci
@latest_builds_with_artifacts ||= builds.latest.with_artifacts_archive.to_a @latest_builds_with_artifacts ||= builds.latest.with_artifacts_archive.to_a
end end
# Rails 5.0 autogenerated question mark enum methods return wrong result if enum value is nil.
# They always return `false`.
# These methods overwrite autogenerated ones to return correct results.
def unknown?
Gitlab.rails5? ? source.nil? : super
end
def unknown_source?
Gitlab.rails5? ? config_source.nil? : super
end
private private
def ci_yaml_from_repo def ci_yaml_from_repo
......
...@@ -3,6 +3,7 @@ class CommitStatus < ActiveRecord::Base ...@@ -3,6 +3,7 @@ class CommitStatus < ActiveRecord::Base
include Importable include Importable
include AfterCommitQueue include AfterCommitQueue
include Presentable include Presentable
include EnumWithNil
self.table_name = 'ci_builds' self.table_name = 'ci_builds'
...@@ -39,7 +40,7 @@ class CommitStatus < ActiveRecord::Base ...@@ -39,7 +40,7 @@ class CommitStatus < ActiveRecord::Base
scope :retried_ordered, -> { retried.ordered.includes(project: :namespace) } scope :retried_ordered, -> { retried.ordered.includes(project: :namespace) }
scope :after_stage, -> (index) { where('stage_idx > ?', index) } scope :after_stage, -> (index) { where('stage_idx > ?', index) }
enum failure_reason: { enum_with_nil failure_reason: {
unknown_failure: nil, unknown_failure: nil,
script_failure: 1, script_failure: 1,
api_failure: 2, api_failure: 2,
...@@ -190,11 +191,4 @@ class CommitStatus < ActiveRecord::Base ...@@ -190,11 +191,4 @@ class CommitStatus < ActiveRecord::Base
v =~ /\d+/ ? v.to_i : v v =~ /\d+/ ? v.to_i : v
end end
end end
# Rails 5.0 autogenerated question mark enum methods return wrong result if enum value is nil.
# They always return `false`.
# This method overwrites the autogenerated one to return correct result.
def unknown_failure?
Gitlab.rails5? ? failure_reason.nil? : super
end
end end
module EnumWithNil
extend ActiveSupport::Concern
included do
def self.enum_with_nil(definitions)
# use original `enum` to auto-define all methods
enum(definitions)
# override auto-defined methods only for the
# key which uses nil value
definitions.each do |name, values|
next unless key_with_nil = values.key(nil)
# E.g. for enum_with_nil failure_reason: { unknown_failure: nil }
# this overrides auto-generated method `unknown_failure?`
define_method("#{key_with_nil}?") do
Gitlab.rails5? ? self[name].nil? : super()
end
# E.g. for enum_with_nil failure_reason: { unknown_failure: nil }
# this overrides auto-generated method `failure_reason`
define_method(name) do
orig = super()
return orig unless Gitlab.rails5?
return orig unless orig.nil?
self.class.public_send(name.to_s.pluralize).key(nil) # rubocop:disable GitlabSecurity/PublicSend
end
end
end
end
end
...@@ -292,6 +292,7 @@ class Project < ActiveRecord::Base ...@@ -292,6 +292,7 @@ class Project < ActiveRecord::Base
validates :name, uniqueness: { scope: :namespace_id } validates :name, uniqueness: { scope: :namespace_id }
validates :import_url, url: { protocols: %w(http https ssh git), validates :import_url, url: { protocols: %w(http https ssh git),
allow_localhost: false, allow_localhost: false,
enforce_user: true,
ports: VALID_IMPORT_PORTS }, if: [:external_import?, :import_url_changed?] ports: VALID_IMPORT_PORTS }, if: [:external_import?, :import_url_changed?]
validates :star_count, numericality: { greater_than_or_equal_to: 0 } validates :star_count, numericality: { greater_than_or_equal_to: 0 }
validate :check_limit, on: :create validate :check_limit, on: :create
......
...@@ -16,7 +16,7 @@ class RemoteMirror < ActiveRecord::Base ...@@ -16,7 +16,7 @@ class RemoteMirror < ActiveRecord::Base
belongs_to :project, inverse_of: :remote_mirrors belongs_to :project, inverse_of: :remote_mirrors
validates :url, presence: true, url: { protocols: %w(ssh git http https), allow_blank: true } validates :url, presence: true, url: { protocols: %w(ssh git http https), allow_blank: true, enforce_user: true }
before_save :set_new_remote_name, if: :mirror_url_changed? before_save :set_new_remote_name, if: :mirror_url_changed?
......
...@@ -17,7 +17,7 @@ module Commits ...@@ -17,7 +17,7 @@ module Commits
new_commit = create_commit! new_commit = create_commit!
success(result: new_commit) success(result: new_commit)
rescue ValidationError, ChangeError, Gitlab::Git::Index::IndexError, Gitlab::Git::CommitError, Gitlab::Git::HooksService::PreReceiveError => ex rescue ValidationError, ChangeError, Gitlab::Git::Index::IndexError, Gitlab::Git::CommitError, Gitlab::Git::PreReceiveError => ex
error(ex.message) error(ex.message)
end end
......
...@@ -14,7 +14,7 @@ class CreateBranchService < BaseService ...@@ -14,7 +14,7 @@ class CreateBranchService < BaseService
else else
error('Invalid reference name') error('Invalid reference name')
end end
rescue Gitlab::Git::HooksService::PreReceiveError => ex rescue Gitlab::Git::PreReceiveError => ex
error(ex.message) error(ex.message)
end end
......
...@@ -16,7 +16,7 @@ class DeleteBranchService < BaseService ...@@ -16,7 +16,7 @@ class DeleteBranchService < BaseService
else else
error('Failed to remove branch') error('Failed to remove branch')
end end
rescue Gitlab::Git::HooksService::PreReceiveError => ex rescue Gitlab::Git::PreReceiveError => ex
error(ex.message) error(ex.message)
end end
......
...@@ -13,7 +13,7 @@ module MergeRequests ...@@ -13,7 +13,7 @@ module MergeRequests
source, source,
merge_request.target_branch, merge_request.target_branch,
merge_request: merge_request) merge_request: merge_request)
rescue Gitlab::Git::HooksService::PreReceiveError => e rescue Gitlab::Git::PreReceiveError => e
raise MergeError, e.message raise MergeError, e.message
rescue StandardError => e rescue StandardError => e
raise MergeError, "Something went wrong during merge: #{e.message}" raise MergeError, "Something went wrong during merge: #{e.message}"
......
...@@ -79,7 +79,7 @@ module MergeRequests ...@@ -79,7 +79,7 @@ module MergeRequests
message = params[:commit_message] || merge_request.merge_commit_message message = params[:commit_message] || merge_request.merge_commit_message
repository.merge(current_user, source, merge_request, message) repository.merge(current_user, source, merge_request, message)
rescue Gitlab::Git::HooksService::PreReceiveError => e rescue Gitlab::Git::PreReceiveError => e
handle_merge_error(log_message: e.message) handle_merge_error(log_message: e.message)
raise MergeError, 'Something went wrong during merge pre-receive hook' raise MergeError, 'Something went wrong during merge pre-receive hook'
rescue => e rescue => e
......
...@@ -135,6 +135,7 @@ module Projects ...@@ -135,6 +135,7 @@ module Projects
raise_error('Failed to remove some tags in project container registry. Please try again or contact administrator.') raise_error('Failed to remove some tags in project container registry. Please try again or contact administrator.')
end end
log_destroy_event
trash_repositories! trash_repositories!
# Rails attempts to load all related records into memory before # Rails attempts to load all related records into memory before
...@@ -148,6 +149,10 @@ module Projects ...@@ -148,6 +149,10 @@ module Projects
end end
end end
def log_destroy_event
log_info("Attempting to destroy #{project.full_path} (#{project.id})")
end
## ##
# This method makes sure that we correctly remove registry tags # This method makes sure that we correctly remove registry tags
# for legacy image repository (when repository path equals project path). # for legacy image repository (when repository path equals project path).
......
...@@ -13,7 +13,7 @@ module Tags ...@@ -13,7 +13,7 @@ module Tags
new_tag = repository.add_tag(current_user, tag_name, target, message) new_tag = repository.add_tag(current_user, tag_name, target, message)
rescue Gitlab::Git::Repository::TagExistsError rescue Gitlab::Git::Repository::TagExistsError
return error("Tag #{tag_name} already exists") return error("Tag #{tag_name} already exists")
rescue Gitlab::Git::HooksService::PreReceiveError => ex rescue Gitlab::Git::PreReceiveError => ex
return error(ex.message) return error(ex.message)
end end
......
...@@ -21,7 +21,7 @@ module Tags ...@@ -21,7 +21,7 @@ module Tags
else else
error('Failed to remove tag') error('Failed to remove tag')
end end
rescue Gitlab::Git::HooksService::PreReceiveError => ex rescue Gitlab::Git::PreReceiveError => ex
error(ex.message) error(ex.message)
end end
......
...@@ -13,7 +13,7 @@ class ValidateNewBranchService < BaseService ...@@ -13,7 +13,7 @@ class ValidateNewBranchService < BaseService
end end
success success
rescue Gitlab::Git::HooksService::PreReceiveError => ex rescue Gitlab::Git::PreReceiveError => ex
error(ex.message) error(ex.message)
end end
end end
...@@ -18,6 +18,13 @@ ...@@ -18,6 +18,13 @@
# This validator can also block urls pointing to localhost or the local network to # This validator can also block urls pointing to localhost or the local network to
# protect against Server-side Request Forgery (SSRF), or check for the right port. # protect against Server-side Request Forgery (SSRF), or check for the right port.
# #
# The available options are:
# - protocols: Allowed protocols. Default: http and https
# - allow_localhost: Allow urls pointing to localhost. Default: true
# - allow_local_network: Allow urls pointing to private network addresses. Default: true
# - ports: Allowed ports. Default: all.
# - enforce_user: Validate user format. Default: false
#
# Example: # Example:
# class User < ActiveRecord::Base # class User < ActiveRecord::Base
# validates :personal_url, url: { allow_localhost: false, allow_local_network: false} # validates :personal_url, url: { allow_localhost: false, allow_local_network: false}
...@@ -35,7 +42,7 @@ class UrlValidator < ActiveModel::EachValidator ...@@ -35,7 +42,7 @@ class UrlValidator < ActiveModel::EachValidator
if value.present? if value.present?
value.strip! value.strip!
else else
record.errors.add(attribute, "must be a valid URL") record.errors.add(attribute, 'must be a valid URL')
end end
Gitlab::UrlBlocker.validate!(value, blocker_args) Gitlab::UrlBlocker.validate!(value, blocker_args)
...@@ -51,7 +58,8 @@ class UrlValidator < ActiveModel::EachValidator ...@@ -51,7 +58,8 @@ class UrlValidator < ActiveModel::EachValidator
protocols: DEFAULT_PROTOCOLS, protocols: DEFAULT_PROTOCOLS,
ports: [], ports: [],
allow_localhost: true, allow_localhost: true,
allow_local_network: true allow_local_network: true,
enforce_user: false
} }
end end
...@@ -64,7 +72,7 @@ class UrlValidator < ActiveModel::EachValidator ...@@ -64,7 +72,7 @@ class UrlValidator < ActiveModel::EachValidator
end end
def blocker_args def blocker_args
current_options.slice(:allow_localhost, :allow_local_network, :protocols, :ports).tap do |args| current_options.slice(*default_options.keys).tap do |args|
if allow_setting_local_requests? if allow_setting_local_requests?
args[:allow_localhost] = args[:allow_local_network] = true args[:allow_localhost] = args[:allow_local_network] = true
end end
......
= form_for @application_setting, url: admin_application_settings_path do |f| = form_for @application_setting, url: admin_application_settings_path, html: { class: 'fieldset-form' } do |f|
= form_errors(@application_setting) = form_errors(@application_setting)
%fieldset %fieldset
...@@ -7,13 +7,13 @@ ...@@ -7,13 +7,13 @@
.form-check .form-check
= f.check_box :enforce_terms, class: 'form-check-input' = f.check_box :enforce_terms, class: 'form-check-input'
= f.label :enforce_terms, class: 'form-check-label' do = f.label :enforce_terms, class: 'form-check-label' do
= _("Require all users to accept Terms of Service when they access GitLab.") = _("Require all users to accept Terms of Service and Privacy Policy when they access GitLab.")
.form-text.text-muted .form-text.text-muted
= _("When enabled, users cannot use GitLab until the terms have been accepted.") = _("When enabled, users cannot use GitLab until the terms have been accepted.")
.form-group.row .form-group.row
.col-sm-12 .col-sm-12
= f.label :terms do = f.label :terms do
= _("Terms of Service Agreement") = _("Terms of Service Agreement and Privacy Policy")
.col-sm-12 .col-sm-12
= f.text_area :terms, class: 'form-control', rows: 8 = f.text_area :terms, class: 'form-control', rows: 8
.form-text.text-muted .form-text.text-muted
......
...@@ -50,11 +50,11 @@ ...@@ -50,11 +50,11 @@
%section.settings.as-terms.no-animate#js-terms-settings{ class: ('expanded' if expanded) } %section.settings.as-terms.no-animate#js-terms-settings{ class: ('expanded' if expanded) }
.settings-header .settings-header
%h4 %h4
= _('Terms of Service') = _('Terms of Service and Privacy Policy')
%button.btn.btn-default.js-settings-toggle{ type: 'button' } %button.btn.btn-default.js-settings-toggle{ type: 'button' }
= expanded ? _('Collapse') : _('Expand') = expanded ? _('Collapse') : _('Expand')
%p %p
= _('Include a Terms of Service agreement that all users must accept.') = _('Include a Terms of Service agreement and Privacy Policy that all users must accept.')
.settings-content .settings-content
= render 'terms' = render 'terms'
......
...@@ -22,6 +22,13 @@ ...@@ -22,6 +22,13 @@
= f.label :password = f.label :password
= f.password_field :password, class: "form-control bottom", required: true, pattern: ".{#{@minimum_password_length},}", title: "Minimum length is #{@minimum_password_length} characters." = f.password_field :password, class: "form-control bottom", required: true, pattern: ".{#{@minimum_password_length},}", title: "Minimum length is #{@minimum_password_length} characters."
%p.gl-field-hint Minimum length is #{@minimum_password_length} characters %p.gl-field-hint Minimum length is #{@minimum_password_length} characters
- if Gitlab::CurrentSettings.current_application_settings.enforce_terms?
.form-group
= check_box_tag :terms_opt_in, '1', false, required: true
= label_tag :terms_opt_in do
- terms_link = link_to s_("I accept the|Terms of Service and Privacy Policy"), terms_path, target: "_blank"
- accept_terms_label = _("I accept the %{terms_link}") % { terms_link: terms_link }
= accept_terms_label.html_safe
%div %div
- if Gitlab::Recaptcha.enabled? - if Gitlab::Recaptcha.enabled?
= recaptcha_tags = recaptcha_tags
......
...@@ -9,10 +9,10 @@ ...@@ -9,10 +9,10 @@
.tree-holder .tree-holder
.nav-block .nav-block
%ul.breadcrumb.repo-breadcrumb %ul.breadcrumb.repo-breadcrumb
%li %li.breadcrumb-item
= link_to 'Artifacts', browse_project_job_artifacts_path(@project, @build) = link_to 'Artifacts', browse_project_job_artifacts_path(@project, @build)
- path_breadcrumbs do |title, path| - path_breadcrumbs do |title, path|
%li %li.breadcrumb-item
= link_to truncate(title, length: 40), browse_project_job_artifacts_path(@project, @build, path) = link_to truncate(title, length: 40), browse_project_job_artifacts_path(@project, @build, path)
.tree-controls .tree-controls
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
.js-file-title.file-title .js-file-title.file-title
= link_to blob_link do = link_to blob_link do
%i.fa.fa-file %i.fa.fa-file
= search_blob_title(project, file_name) %strong
= search_blob_title(project, file_name)
- if blob.data - if blob.data
.file-content.code.term .file-content.code.term
= render 'shared/file_highlight', blob: blob, first_line_number: blob.startline = render 'shared/file_highlight', blob: blob, first_line_number: blob.startline
= render 'projects/commits/commit', project: @project, commit: commit, ref: nil = render 'projects/commits/commit', project: commit.project, commit: commit, ref: nil, show_project_name: @project.nil?
...@@ -2,16 +2,17 @@ ...@@ -2,16 +2,17 @@
.card-body.rendered-terms .card-body.rendered-terms
= markdown_field(@term, :terms) = markdown_field(@term, :terms)
.card-footer.footer-block.clearfix - if current_user
- if can?(current_user, :accept_terms, @term) .card-footer.footer-block.clearfix
.float-right - if can?(current_user, :accept_terms, @term)
= button_to accept_term_path(@term, redirect_params), class: 'btn btn-success prepend-left-8' do .float-right
= _('Accept terms') = button_to accept_term_path(@term, redirect_params), class: 'btn btn-success prepend-left-8' do
- else = _('Accept terms')
.pull-right - else
= link_to root_path, class: 'btn btn-success prepend-left-8' do .pull-right
= _('Continue') = link_to root_path, class: 'btn btn-success prepend-left-8' do
- if can?(current_user, :decline_terms, @term) = _('Continue')
.float-right - if can?(current_user, :decline_terms, @term)
= button_to decline_term_path(@term, redirect_params), class: 'btn btn-default prepend-left-8' do .float-right
= _('Decline and sign out') = button_to decline_term_path(@term, redirect_params), class: 'btn btn-default prepend-left-8' do
= _('Decline and sign out')
---
title: Fix overflowing Failed Jobs table in sm viewports on IE11
merge_request:
author:
type: fixed
---
title: Bump grape-path-helpers to 1.0.5
merge_request: 19604
author: "@blackst0ne"
type: other
---
title: Users can accept terms during registration
merge_request: 19583
author:
type: other
---
title: Avoid checking the user format in every url validation
merge_request: 19575
author:
type: changed
---
title: Move some Gitaly RPC's to opt-out
merge_request: 19591
author:
type: other
---
title: Hide project name if searching against a project
merge_request: 19595
author:
type: changed
---
title: Fix extra blank line at start of rendered reStructuredText code block
merge_request: 19596
author:
type: fixed
---
title: Use Tooltip component in MrWidgetAuthorTime vue comonent
merge_request: 19635
author: George Tsiolis
type: performance
...@@ -41,7 +41,12 @@ module ActiveRecord ...@@ -41,7 +41,12 @@ module ActiveRecord
# Abstract representation of an index definition on a table. Instances of # Abstract representation of an index definition on a table. Instances of
# this type are typically created and returned by methods in database # this type are typically created and returned by methods in database
# adapters. e.g. ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter#indexes # adapters. e.g. ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter#indexes
class IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths, :orders, :where, :type, :using, :opclasses) #:nodoc: attrs = [:table, :name, :unique, :columns, :lengths, :orders, :where, :type, :using, :opclasses]
# In Rails 5 the second last attribute is newly `:comment`
attrs.insert(-2, :comment) if Gitlab.rails5?
class IndexDefinition < Struct.new(*attrs) #:nodoc:
end end
end end
end end
......
const fs = require('fs');
const path = require('path'); const path = require('path');
const glob = require('glob'); const glob = require('glob');
const webpack = require('webpack'); const webpack = require('webpack');
......
...@@ -301,9 +301,9 @@ sudo usermod -aG redis git ...@@ -301,9 +301,9 @@ sudo usermod -aG redis git
### Clone the Source ### Clone the Source
# Clone GitLab repository # Clone GitLab repository
sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 10-8-stable gitlab sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 11-0-stable gitlab
**Note:** You can change `10-8-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server! **Note:** You can change `11-0-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
### Configure It ### Configure It
......
...@@ -557,10 +557,6 @@ Software that is hosted centrally and accessed on-demand (i.e. whenever you want ...@@ -557,10 +557,6 @@ Software that is hosted centrally and accessed on-demand (i.e. whenever you want
This term is often used by people when they mean "Version Control." This term is often used by people when they mean "Version Control."
#### SCLAU
Abbreviation for SQO Count [Large And Up](https://about.gitlab.com/handbook/sales/#market-segmentation). This is the number of opportunities in large and strategic organizations passed from marketing to sales.
### Scrum ### Scrum
An Agile [framework](https://www.scrum.org/Resources/What-is-Scrum) designed to typically help complete complex software projects. It's made up of several parts: product requirements backlog, sprint planning, sprint (development), sprint review, and retrospec (analyzing the sprint). The goal is to end up with potentially shippable products. An Agile [framework](https://www.scrum.org/Resources/What-is-Scrum) designed to typically help complete complex software projects. It's made up of several parts: product requirements backlog, sprint planning, sprint (development), sprint review, and retrospec (analyzing the sprint). The goal is to end up with potentially shippable products.
......
This diff is collapsed.
...@@ -20,6 +20,19 @@ When an admin enables this feature, they will automattically be ...@@ -20,6 +20,19 @@ When an admin enables this feature, they will automattically be
directed to the page to accept the terms themselves. After they directed to the page to accept the terms themselves. After they
accept, they will be directed back to the settings page. accept, they will be directed back to the settings page.
## New registrations
When this feature is enabled, a checkbox will be available in the
sign-up form.
![Sign up form](img/sign_up_terms.png)
This checkbox will be required during sign up.
Users can review the terms entered in the admin panel before
accepting. The page will be opened in a new window so they can
continue their registration afterwards.
## Accepting terms ## Accepting terms
When this feature was enabled, the users that have not accepted the When this feature was enabled, the users that have not accepted the
......
...@@ -7,9 +7,7 @@ module Gitlab ...@@ -7,9 +7,7 @@ module Gitlab
end end
def value def value
Gitlab::GitalyClient::StorageSettings.allow_disk_access do @value ||= count_commits
@value ||= count_commits
end
end end
private private
...@@ -21,19 +19,11 @@ module Gitlab ...@@ -21,19 +19,11 @@ module Gitlab
def count_commits def count_commits
return unless ref return unless ref
repository = @project.repository.raw_repository gitaly_commit_client.commit_count(ref, after: @from)
sha = @project.repository.commit(ref).sha end
cmd = %W(git --git-dir=#{repository.path} log)
cmd << '--format=%H'
cmd << "--after=#{@from.iso8601}"
cmd << sha
output, status = Gitlab::Popen.popen(cmd)
raise IOError, output unless status.zero?
output.lines.count def gitaly_commit_client
Gitlab::GitalyClient::CommitService.new(@project.repository.raw_repository)
end end
def ref def ref
......
...@@ -22,7 +22,7 @@ module Gitlab ...@@ -22,7 +22,7 @@ module Gitlab
private private
def load_blame def load_blame
raw_output = @repo.gitaly_migrate(:blame) do |is_enabled| raw_output = @repo.gitaly_migrate(:blame, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled if is_enabled
load_blame_by_gitaly load_blame_by_gitaly
else else
......
...@@ -20,7 +20,7 @@ module Gitlab ...@@ -20,7 +20,7 @@ module Gitlab
end end
result[:newrev] result[:newrev]
rescue Gitlab::Git::HooksService::PreReceiveError => e rescue Gitlab::Git::PreReceiveError => e
message = "Custom Hook failed: #{e.message}" message = "Custom Hook failed: #{e.message}"
raise Gitlab::Git::Wiki::OperationError, message raise Gitlab::Git::Wiki::OperationError, message
end end
......
...@@ -11,7 +11,7 @@ module Gitlab ...@@ -11,7 +11,7 @@ module Gitlab
def initialize(name, repository) def initialize(name, repository)
@name = name @name = name
@repository = repository @repository = repository
@path = File.join(repo_path.strip, 'hooks', name) @path = File.join(repo_path, 'hooks', name)
end end
def repo_path def repo_path
...@@ -95,13 +95,13 @@ module Gitlab ...@@ -95,13 +95,13 @@ module Gitlab
args = [ref, oldrev, newrev] args = [ref, oldrev, newrev]
stdout, stderr, status = Open3.capture3(env, path, *args, options) stdout, stderr, status = Open3.capture3(env, path, *args, options)
[status.success?, Gitlab::Utils.nlbr(stderr.presence || stdout)] [status.success?, stderr.presence || stdout]
end end
def retrieve_error_message(stderr, stdout) def retrieve_error_message(stderr, stdout)
err_message = stderr.read err_message = stderr.read
err_message = err_message.blank? ? stdout.read : err_message err_message = err_message.blank? ? stdout.read : err_message
Gitlab::Utils.nlbr(err_message) err_message
end end
end end
end end
......
module Gitlab module Gitlab
module Git module Git
class HooksService class HooksService
PreReceiveError = Class.new(StandardError)
attr_accessor :oldrev, :newrev, :ref attr_accessor :oldrev, :newrev, :ref
def execute(pusher, repository, oldrev, newrev, ref) def execute(pusher, repository, oldrev, newrev, ref)
......
module Gitlab
module Git
#
# PreReceiveError is special because its message gets displayed to users
# in the web UI. To prevent XSS we sanitize the message on
# initialization.
class PreReceiveError < StandardError
def initialize(msg = '')
super(nlbr(msg))
end
private
# In gitaly-ruby we override this method to do nothing, so that
# sanitization happens in gitlab-rails only.
def nlbr(str)
Gitlab::Utils.nlbr(str)
end
end
end
end
...@@ -533,7 +533,7 @@ module Gitlab ...@@ -533,7 +533,7 @@ module Gitlab
def count_commits(options) def count_commits(options)
count_commits_options = process_count_commits_options(options) count_commits_options = process_count_commits_options(options)
gitaly_migrate(:count_commits) do |is_enabled| gitaly_migrate(:count_commits, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled if is_enabled
count_commits_by_gitaly(count_commits_options) count_commits_by_gitaly(count_commits_options)
else else
...@@ -738,7 +738,7 @@ module Gitlab ...@@ -738,7 +738,7 @@ module Gitlab
# #
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/330 # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/330
def commit_count(ref) def commit_count(ref)
gitaly_migrate(:commit_count) do |is_enabled| gitaly_migrate(:commit_count, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled if is_enabled
gitaly_commit_client.commit_count(ref) gitaly_commit_client.commit_count(ref)
else else
......
...@@ -20,7 +20,7 @@ module Gitlab ...@@ -20,7 +20,7 @@ module Gitlab
response = GitalyClient.call(@repository.storage, :operation_service, :user_delete_tag, request) response = GitalyClient.call(@repository.storage, :operation_service, :user_delete_tag, request)
if pre_receive_error = response.pre_receive_error.presence if pre_receive_error = response.pre_receive_error.presence
raise Gitlab::Git::HooksService::PreReceiveError, pre_receive_error raise Gitlab::Git::PreReceiveError, pre_receive_error
end end
end end
...@@ -35,7 +35,7 @@ module Gitlab ...@@ -35,7 +35,7 @@ module Gitlab
response = GitalyClient.call(@repository.storage, :operation_service, :user_create_tag, request) response = GitalyClient.call(@repository.storage, :operation_service, :user_create_tag, request)
if pre_receive_error = response.pre_receive_error.presence if pre_receive_error = response.pre_receive_error.presence
raise Gitlab::Git::HooksService::PreReceiveError, pre_receive_error raise Gitlab::Git::PreReceiveError, pre_receive_error
elsif response.exists elsif response.exists
raise Gitlab::Git::Repository::TagExistsError raise Gitlab::Git::Repository::TagExistsError
end end
...@@ -56,7 +56,7 @@ module Gitlab ...@@ -56,7 +56,7 @@ module Gitlab
:user_create_branch, request) :user_create_branch, request)
if response.pre_receive_error.present? if response.pre_receive_error.present?
raise Gitlab::Git::HooksService::PreReceiveError.new(response.pre_receive_error) raise Gitlab::Git::PreReceiveError.new(response.pre_receive_error)
end end
branch = response.branch branch = response.branch
...@@ -76,7 +76,7 @@ module Gitlab ...@@ -76,7 +76,7 @@ module Gitlab
response = GitalyClient.call(@repository.storage, :operation_service, :user_delete_branch, request) response = GitalyClient.call(@repository.storage, :operation_service, :user_delete_branch, request)
if pre_receive_error = response.pre_receive_error.presence if pre_receive_error = response.pre_receive_error.presence
raise Gitlab::Git::HooksService::PreReceiveError, pre_receive_error raise Gitlab::Git::PreReceiveError, pre_receive_error
end end
end end
...@@ -106,7 +106,7 @@ module Gitlab ...@@ -106,7 +106,7 @@ module Gitlab
second_response = response_enum.next second_response = response_enum.next
if second_response.pre_receive_error.present? if second_response.pre_receive_error.present?
raise Gitlab::Git::HooksService::PreReceiveError, second_response.pre_receive_error raise Gitlab::Git::PreReceiveError, second_response.pre_receive_error
end end
branch_update = second_response.branch_update branch_update = second_response.branch_update
...@@ -175,7 +175,7 @@ module Gitlab ...@@ -175,7 +175,7 @@ module Gitlab
) )
if response.pre_receive_error.presence if response.pre_receive_error.presence
raise Gitlab::Git::HooksService::PreReceiveError, response.pre_receive_error raise Gitlab::Git::PreReceiveError, response.pre_receive_error
elsif response.git_error.presence elsif response.git_error.presence
raise Gitlab::Git::Repository::GitError, response.git_error raise Gitlab::Git::Repository::GitError, response.git_error
else else
...@@ -242,7 +242,7 @@ module Gitlab ...@@ -242,7 +242,7 @@ module Gitlab
:user_commit_files, req_enum, remote_storage: start_repository.storage) :user_commit_files, req_enum, remote_storage: start_repository.storage)
if (pre_receive_error = response.pre_receive_error.presence) if (pre_receive_error = response.pre_receive_error.presence)
raise Gitlab::Git::HooksService::PreReceiveError, pre_receive_error raise Gitlab::Git::PreReceiveError, pre_receive_error
end end
if (index_error = response.index_error.presence) if (index_error = response.index_error.presence)
...@@ -280,7 +280,7 @@ module Gitlab ...@@ -280,7 +280,7 @@ module Gitlab
def handle_cherry_pick_or_revert_response(response) def handle_cherry_pick_or_revert_response(response)
if response.pre_receive_error.presence if response.pre_receive_error.presence
raise Gitlab::Git::HooksService::PreReceiveError, response.pre_receive_error raise Gitlab::Git::PreReceiveError, response.pre_receive_error
elsif response.commit_error.presence elsif response.commit_error.presence
raise Gitlab::Git::CommitError, response.commit_error raise Gitlab::Git::CommitError, response.commit_error
elsif response.create_tree_error.presence elsif response.create_tree_error.presence
......
...@@ -5,7 +5,7 @@ module Gitlab ...@@ -5,7 +5,7 @@ module Gitlab
BlockedUrlError = Class.new(StandardError) BlockedUrlError = Class.new(StandardError)
class << self class << self
def validate!(url, allow_localhost: false, allow_local_network: true, ports: [], protocols: []) def validate!(url, allow_localhost: false, allow_local_network: true, enforce_user: false, ports: [], protocols: [])
return true if url.nil? return true if url.nil?
begin begin
...@@ -20,7 +20,7 @@ module Gitlab ...@@ -20,7 +20,7 @@ module Gitlab
port = uri.port || uri.default_port port = uri.port || uri.default_port
validate_protocol!(uri.scheme, protocols) validate_protocol!(uri.scheme, protocols)
validate_port!(port, ports) if ports.any? validate_port!(port, ports) if ports.any?
validate_user!(uri.user) validate_user!(uri.user) if enforce_user
validate_hostname!(uri.hostname) validate_hostname!(uri.hostname)
begin begin
......
...@@ -8,8 +8,8 @@ msgid "" ...@@ -8,8 +8,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: gitlab 1.0.0\n" "Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-06-07 19:35+0200\n" "POT-Creation-Date: 2018-06-08 18:19+0200\n"
"PO-Revision-Date: 2018-06-07 19:35+0200\n" "PO-Revision-Date: 2018-06-08 18:19+0200\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n" "Language: \n"
...@@ -232,7 +232,7 @@ msgstr "" ...@@ -232,7 +232,7 @@ msgstr ""
msgid "Account" msgid "Account"
msgstr "" msgstr ""
msgid "Account and limit settings" msgid "Account and limit"
msgstr "" msgstr ""
msgid "Active" msgid "Active"
...@@ -780,9 +780,6 @@ msgstr "" ...@@ -780,9 +780,6 @@ msgstr ""
msgid "CI/CD settings" msgid "CI/CD settings"
msgstr "" msgstr ""
msgid "CICD|A domain is required to use Auto Review Apps and Auto Deploy Stages."
msgstr ""
msgid "CICD|An explicit %{ci_file} needs to be specified before you can begin using Continuous Integration and Delivery." msgid "CICD|An explicit %{ci_file} needs to be specified before you can begin using Continuous Integration and Delivery."
msgstr "" msgstr ""
...@@ -792,6 +789,18 @@ msgstr "" ...@@ -792,6 +789,18 @@ msgstr ""
msgid "CICD|Auto DevOps will automatically build, test, and deploy your application based on a predefined Continuous Integration and Delivery configuration." msgid "CICD|Auto DevOps will automatically build, test, and deploy your application based on a predefined Continuous Integration and Delivery configuration."
msgstr "" msgstr ""
msgid "CICD|Automatic deployment to staging, manual deployment to production"
msgstr ""
msgid "CICD|Continuous deployment to production"
msgstr ""
msgid "CICD|Deployment strategy"
msgstr ""
msgid "CICD|Deployment strategy needs a domain name to work correctly."
msgstr ""
msgid "CICD|Disable Auto DevOps" msgid "CICD|Disable Auto DevOps"
msgstr "" msgstr ""
...@@ -813,6 +822,9 @@ msgstr "" ...@@ -813,6 +822,9 @@ msgstr ""
msgid "CICD|The Auto DevOps pipeline configuration will be used when there is no %{ci_file} in the project." msgid "CICD|The Auto DevOps pipeline configuration will be used when there is no %{ci_file} in the project."
msgstr "" msgstr ""
msgid "CICD|You need to specify a domain if you want to use Auto Review Apps and Auto Deploy stages."
msgstr ""
msgid "Can run untagged jobs" msgid "Can run untagged jobs"
msgstr "" msgstr ""
...@@ -2133,6 +2145,9 @@ msgstr "" ...@@ -2133,6 +2145,9 @@ msgstr ""
msgid "Failed to update issues, please try again." msgid "Failed to update issues, please try again."
msgstr "" msgstr ""
msgid "Failure"
msgstr ""
msgid "Feb" msgid "Feb"
msgstr "" msgstr ""
...@@ -2371,6 +2386,12 @@ msgstr "" ...@@ -2371,6 +2386,12 @@ msgstr ""
msgid "Housekeeping successfully started" msgid "Housekeeping successfully started"
msgstr "" msgstr ""
msgid "I accept the %{terms_link}"
msgstr ""
msgid "I accept the|Terms of Service and Privacy Policy"
msgstr ""
msgid "IDE|Commit" msgid "IDE|Commit"
msgstr "" msgstr ""
...@@ -2407,7 +2428,7 @@ msgstr "" ...@@ -2407,7 +2428,7 @@ msgstr ""
msgid "Import repository" msgid "Import repository"
msgstr "" msgstr ""
msgid "Include a Terms of Service agreement that all users must accept." msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr "" msgstr ""
msgid "Install Runner on Kubernetes" msgid "Install Runner on Kubernetes"
...@@ -3548,7 +3569,7 @@ msgstr "" ...@@ -3548,7 +3569,7 @@ msgstr ""
msgid "Repository maintenance" msgid "Repository maintenance"
msgstr "" msgstr ""
msgid "Repository mirror settings" msgid "Repository mirror"
msgstr "" msgstr ""
msgid "Repository storage" msgid "Repository storage"
...@@ -3557,7 +3578,7 @@ msgstr "" ...@@ -3557,7 +3578,7 @@ msgstr ""
msgid "Request Access" msgid "Request Access"
msgstr "" msgstr ""
msgid "Require all users to accept Terms of Service when they access GitLab." msgid "Require all users to accept Terms of Service and Privacy Policy when they access GitLab."
msgstr "" msgstr ""
msgid "Reset git storage health information" msgid "Reset git storage health information"
...@@ -3616,9 +3637,6 @@ msgstr "" ...@@ -3616,9 +3637,6 @@ msgstr ""
msgid "Runners can be placed on separate users, servers, and even on your local machine." msgid "Runners can be placed on separate users, servers, and even on your local machine."
msgstr "" msgstr ""
msgid "Runners settings"
msgstr ""
msgid "Running" msgid "Running"
msgstr "" msgstr ""
...@@ -3942,6 +3960,9 @@ msgstr "" ...@@ -3942,6 +3960,9 @@ msgstr ""
msgid "Squash commits" msgid "Squash commits"
msgstr "" msgstr ""
msgid "Stage"
msgstr ""
msgid "Stage all" msgid "Stage all"
msgstr "" msgstr ""
...@@ -4100,10 +4121,10 @@ msgstr "" ...@@ -4100,10 +4121,10 @@ msgstr ""
msgid "Team" msgid "Team"
msgstr "" msgstr ""
msgid "Terms of Service" msgid "Terms of Service Agreement and Privacy Policy"
msgstr "" msgstr ""
msgid "Terms of Service Agreement" msgid "Terms of Service and Privacy Policy"
msgstr "" msgstr ""
msgid "The Issue Tracker is the place to add things that need to be improved or solved in a project" msgid "The Issue Tracker is the place to add things that need to be improved or solved in a project"
...@@ -4331,6 +4352,9 @@ msgstr "" ...@@ -4331,6 +4352,9 @@ msgstr ""
msgid "Timeago|%s days remaining" msgid "Timeago|%s days remaining"
msgstr "" msgstr ""
msgid "Timeago|%s hours ago"
msgstr ""
msgid "Timeago|%s hours remaining" msgid "Timeago|%s hours remaining"
msgstr "" msgstr ""
...@@ -4346,6 +4370,9 @@ msgstr "" ...@@ -4346,6 +4370,9 @@ msgstr ""
msgid "Timeago|%s months remaining" msgid "Timeago|%s months remaining"
msgstr "" msgstr ""
msgid "Timeago|%s seconds ago"
msgstr ""
msgid "Timeago|%s seconds remaining" msgid "Timeago|%s seconds remaining"
msgstr "" msgstr ""
...@@ -4361,46 +4388,43 @@ msgstr "" ...@@ -4361,46 +4388,43 @@ msgstr ""
msgid "Timeago|%s years remaining" msgid "Timeago|%s years remaining"
msgstr "" msgstr ""
msgid "Timeago|1 day remaining" msgid "Timeago|1 day ago"
msgstr "" msgstr ""
msgid "Timeago|1 hour remaining" msgid "Timeago|1 day remaining"
msgstr ""
msgid "Timeago|1 minute remaining"
msgstr "" msgstr ""
msgid "Timeago|1 month remaining" msgid "Timeago|1 hour ago"
msgstr "" msgstr ""
msgid "Timeago|1 week remaining" msgid "Timeago|1 hour remaining"
msgstr "" msgstr ""
msgid "Timeago|1 year remaining" msgid "Timeago|1 minute ago"
msgstr "" msgstr ""
msgid "Timeago|Past due" msgid "Timeago|1 minute remaining"
msgstr "" msgstr ""
msgid "Timeago|a day ago" msgid "Timeago|1 month ago"
msgstr "" msgstr ""
msgid "Timeago|a month ago" msgid "Timeago|1 month remaining"
msgstr "" msgstr ""
msgid "Timeago|a week ago" msgid "Timeago|1 week ago"
msgstr "" msgstr ""
msgid "Timeago|a year ago" msgid "Timeago|1 week remaining"
msgstr "" msgstr ""
msgid "Timeago|about %s hours ago" msgid "Timeago|1 year ago"
msgstr "" msgstr ""
msgid "Timeago|about a minute ago" msgid "Timeago|1 year remaining"
msgstr "" msgstr ""
msgid "Timeago|about an hour ago" msgid "Timeago|Past due"
msgstr "" msgstr ""
msgid "Timeago|in %s days" msgid "Timeago|in %s days"
...@@ -4442,7 +4466,7 @@ msgstr "" ...@@ -4442,7 +4466,7 @@ msgstr ""
msgid "Timeago|in 1 year" msgid "Timeago|in 1 year"
msgstr "" msgstr ""
msgid "Timeago|less than a minute ago" msgid "Timeago|just now"
msgstr "" msgstr ""
msgid "Timeago|right now" msgid "Timeago|right now"
...@@ -4872,6 +4896,9 @@ msgstr "" ...@@ -4872,6 +4896,9 @@ msgstr ""
msgid "You have reached your project limit" msgid "You have reached your project limit"
msgstr "" msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
msgid "You must have maintainer access to force delete a lock" msgid "You must have maintainer access to force delete a lock"
msgstr "" msgstr ""
......
...@@ -3,7 +3,7 @@ module QA ...@@ -3,7 +3,7 @@ module QA
module Repository module Repository
class Push < Factory::Base class Push < Factory::Base
attr_accessor :file_name, :file_content, :commit_message, attr_accessor :file_name, :file_content, :commit_message,
:branch_name, :new_branch :branch_name, :new_branch, :output
attr_writer :remote_branch attr_writer :remote_branch
...@@ -12,6 +12,10 @@ module QA ...@@ -12,6 +12,10 @@ module QA
project.description = 'Project with repository' project.description = 'Project with repository'
end end
product :output do |factory|
factory.output
end
def initialize def initialize
@file_name = 'file.txt' @file_name = 'file.txt'
@file_content = '# This is test project' @file_content = '# This is test project'
...@@ -58,7 +62,7 @@ module QA ...@@ -58,7 +62,7 @@ module QA
end end
repository.commit(commit_message) repository.commit(commit_message)
repository.push_changes("#{branch_name}:#{remote_branch}") @output = repository.push_changes("#{branch_name}:#{remote_branch}")
end end
end end
end end
......
...@@ -46,7 +46,9 @@ module QA ...@@ -46,7 +46,9 @@ module QA
resource.remote_branch = @branch_name resource.remote_branch = @branch_name
end end
Page::Project::Show.act { wait_for_push } Page::Project::Show.perform do |page|
page.wait { page.has_content?(branch_name) }
end
# The upcoming process will make it access the Protected Branches page, # The upcoming process will make it access the Protected Branches page,
# select the already created branch and protect it according # select the already created branch and protect it according
...@@ -62,13 +64,13 @@ module QA ...@@ -62,13 +64,13 @@ module QA
page.select_branch(branch_name) page.select_branch(branch_name)
if allow_to_push if allow_to_push
page.allow_devs_and_masters_to_push page.allow_devs_and_maintainers_to_push
else else
page.allow_no_one_to_push page.allow_no_one_to_push
end end
if allow_to_merge if allow_to_merge
page.allow_devs_and_masters_to_merge page.allow_devs_and_maintainers_to_merge
else else
page.allow_no_one_to_merge page.allow_no_one_to_merge
end end
...@@ -79,9 +81,13 @@ module QA ...@@ -79,9 +81,13 @@ module QA
page.protect_branch page.protect_branch
# Wait for page load, which resets the expanded sections # Avoid Selenium::WebDriver::Error::StaleElementReferenceError
page.wait(reload: false) do # without sleeping. I.e. this completes fast on fast machines.
!page.has_content?('Collapse') page.refresh
# It is possible for the protected branch row to "disappear" at first
page.wait do
page.has_content?(branch_name)
end end
end end
end end
......
...@@ -7,8 +7,6 @@ module QA ...@@ -7,8 +7,6 @@ module QA
class Repository class Repository
include Scenario::Actable include Scenario::Actable
attr_reader :push_output
def self.perform(*args) def self.perform(*args)
Dir.mktmpdir do |dir| Dir.mktmpdir do |dir|
Dir.chdir(dir) { super } Dir.chdir(dir) { super }
...@@ -71,7 +69,9 @@ module QA ...@@ -71,7 +69,9 @@ module QA
end end
def push_changes(branch = 'master') def push_changes(branch = 'master')
@push_output, _ = run_and_redact_credentials("git push #{@uri} #{branch}") output, _ = run_and_redact_credentials("git push #{@uri} #{branch}")
output
end end
def commits def commits
......
...@@ -13,7 +13,7 @@ module QA ...@@ -13,7 +13,7 @@ module QA
visit current_url visit current_url
end end
def wait(max: 60, time: 1, reload: true) def wait(max: 60, time: 0.1, reload: true)
start = Time.now start = Time.now
while Time.now - start < max while Time.now - start < max
......
...@@ -28,11 +28,9 @@ module QA ...@@ -28,11 +28,9 @@ module QA
def has_subgroup?(name) def has_subgroup?(name)
filter_by_name(name) filter_by_name(name)
wait(reload: false) do page.has_text?(/#{name}|Sorry, no groups or projects matched your search/, wait: 60)
break false if page.has_content?('Sorry, no groups or projects matched your search')
page.has_link?(name) page.has_text?(name, wait: 0)
end
end end
def go_to_new_subgroup def go_to_new_subgroup
......
...@@ -6,6 +6,7 @@ module QA::Page ...@@ -6,6 +6,7 @@ module QA::Page
view 'app/views/shared/builds/_build_output.html.haml' do view 'app/views/shared/builds/_build_output.html.haml' do
element :build_output, '.js-build-output' element :build_output, '.js-build-output'
element :loading_animation, '.js-build-refresh'
end end
view 'app/assets/javascripts/vue_shared/components/ci_badge_link.vue' do view 'app/assets/javascripts/vue_shared/components/ci_badge_link.vue' do
...@@ -20,6 +21,10 @@ module QA::Page ...@@ -20,6 +21,10 @@ module QA::Page
find('.ci-status').text == PASSED_STATUS find('.ci-status').text == PASSED_STATUS
end end
def trace_loading?
has_css?('.js-build-refresh')
end
# Reminder: You may wish to wait for a particular job status before checking output # Reminder: You may wish to wait for a particular job status before checking output
def output def output
find('.js-build-output').text find('.js-build-output').text
......
...@@ -40,7 +40,7 @@ module QA ...@@ -40,7 +40,7 @@ module QA
click_allow(:push, 'No one') click_allow(:push, 'No one')
end end
def allow_devs_and_masters_to_push def allow_devs_and_maintainers_to_push
click_allow(:push, 'Developers + Maintainers') click_allow(:push, 'Developers + Maintainers')
end end
...@@ -48,7 +48,7 @@ module QA ...@@ -48,7 +48,7 @@ module QA
click_allow(:merge, 'No one') click_allow(:merge, 'No one')
end end
def allow_devs_and_masters_to_merge def allow_devs_and_maintainers_to_merge
click_allow(:merge, 'Developers + Maintainers') click_allow(:merge, 'Developers + Maintainers')
end end
...@@ -75,10 +75,6 @@ module QA ...@@ -75,10 +75,6 @@ module QA
within_element(:"allowed_to_#{action}_dropdown") do within_element(:"allowed_to_#{action}_dropdown") do
click_on text click_on text
wait(reload: false) do
has_css?('.is-active')
end
end end
end end
end end
......
...@@ -92,7 +92,9 @@ module QA ...@@ -92,7 +92,9 @@ module QA
Page::Project::Pipeline::Show.act { go_to_first_job } Page::Project::Pipeline::Show.act { go_to_first_job }
Page::Project::Job::Show.perform do |job| Page::Project::Job::Show.perform do |job|
job.wait(reload: false) { job.completed? } job.wait(reload: false) do
job.completed? && !job.trace_loading?
end
expect(job.passed?).to be_truthy, "Job status did not become \"passed\"." expect(job.passed?).to be_truthy, "Job status did not become \"passed\"."
expect(job.output).to include(sha1sum) expect(job.output).to include(sha1sum)
......
...@@ -7,12 +7,6 @@ module QA ...@@ -7,12 +7,6 @@ module QA
resource.name = 'protected-branch-project' resource.name = 'protected-branch-project'
end end
end end
given(:location) do
Page::Project::Show.act do
choose_repository_clone_http
repository_location
end
end
before do before do
Runtime::Browser.visit(:gitlab, Page::Main::Login) Runtime::Browser.visit(:gitlab, Page::Main::Login)
...@@ -26,44 +20,49 @@ module QA ...@@ -26,44 +20,49 @@ module QA
Capybara.execute_script 'localStorage.clear()' Capybara.execute_script 'localStorage.clear()'
end end
scenario 'user is able to protect a branch' do context 'when developers and maintainers are allowed to push to a protected branch' do
protected_branch = Factory::Resource::Branch.fabricate! do |resource| let!(:protected_branch) { create_protected_branch(allow_to_push: true) }
resource.branch_name = branch_name
resource.project = project scenario 'user with push rights successfully pushes to the protected branch' do
resource.allow_to_push = true expect(protected_branch.name).to have_content(branch_name)
resource.protected = true expect(protected_branch.push_allowance).to have_content('Developers + Maintainers')
push = push_new_file(branch_name)
expect(push.output).to match(/remote: To create a merge request for protected-branch, visit/)
end end
end
context 'when developers and maintainers are not allowed to push to a protected branch' do
scenario 'user without push rights fails to push to the protected branch' do
create_protected_branch(allow_to_push: false)
push = push_new_file(branch_name)
expect(protected_branch.name).to have_content(branch_name) expect(push.output)
expect(protected_branch.push_allowance).to have_content('Developers + Maintainers') .to match(/remote\: GitLab\: You are not allowed to push code to protected branches on this project/)
expect(push.output)
.to match(/\[remote rejected\] #{branch_name} -> #{branch_name} \(pre-receive hook declined\)/)
end
end end
scenario 'users without authorization cannot push to protected branch' do def create_protected_branch(allow_to_push:)
Factory::Resource::Branch.fabricate! do |resource| Factory::Resource::Branch.fabricate! do |resource|
resource.branch_name = branch_name resource.branch_name = branch_name
resource.project = project resource.project = project
resource.allow_to_push = false resource.allow_to_push = allow_to_push
resource.protected = true resource.protected = true
end end
end
project.visit! def push_new_file(branch)
Factory::Repository::Push.fabricate! do |resource|
Git::Repository.perform do |repository| resource.project = project
repository.uri = location.uri resource.file_name = 'new_file.md'
repository.use_default_credentials resource.file_content = '# This is a new file'
resource.commit_message = 'Add new_file.md'
repository.act do resource.branch_name = branch_name
clone resource.new_branch = false
configure_identity('GitLab QA', 'root@gitlab.com')
checkout('protected-branch')
commit_file('README.md', 'readme content', 'Add a readme')
push_changes('protected-branch')
end
expect(repository.push_output)
.to match(/remote\: GitLab\: You are not allowed to push code to protected branches on this project/)
expect(repository.push_output)
.to match(/\[remote rejected\] #{branch_name} -> #{branch_name} \(pre-receive hook declined\)/)
end end
end end
end end
......
...@@ -32,6 +32,8 @@ module Support ...@@ -32,6 +32,8 @@ module Support
allow(ENV).to receive(:[]).and_call_original allow(ENV).to receive(:[]).and_call_original
allow(ENV).to receive(:key?).and_call_original allow(ENV).to receive(:key?).and_call_original
allow(ENV).to receive(:fetch).and_call_original allow(ENV).to receive(:fetch).and_call_original
# Prevent secrets from leaking in CI
allow(ENV).to receive(:inspect).and_return([])
add_stubbed_value(STUBBED_KEY, true) add_stubbed_value(STUBBED_KEY, true)
end end
end end
......
...@@ -18,7 +18,7 @@ describe Boards::IssuesController do ...@@ -18,7 +18,7 @@ describe Boards::IssuesController do
end end
describe 'GET index', :request_store do describe 'GET index', :request_store do
let(:johndoe) { create(:user, avatar: fixture_file_upload(File.join(Rails.root, 'spec/fixtures/dk.png'))) } let(:johndoe) { create(:user, avatar: fixture_file_upload(File.join('spec/fixtures/dk.png'))) }
context 'with invalid board id' do context 'with invalid board id' do
it 'returns a not found 404 response' do it 'returns a not found 404 response' do
......
...@@ -2,7 +2,7 @@ require 'spec_helper' ...@@ -2,7 +2,7 @@ require 'spec_helper'
describe Groups::AvatarsController do describe Groups::AvatarsController do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:group) { create(:group, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) } let(:group) { create(:group, avatar: fixture_file_upload("spec/fixtures/dk.png", "image/png")) }
before do before do
group.add_owner(user) group.add_owner(user)
......
...@@ -3,7 +3,7 @@ require 'spec_helper' ...@@ -3,7 +3,7 @@ require 'spec_helper'
describe Import::GitlabProjectsController do describe Import::GitlabProjectsController do
set(:namespace) { create(:namespace) } set(:namespace) { create(:namespace) }
set(:user) { namespace.owner } set(:user) { namespace.owner }
let(:file) { fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') } let(:file) { fixture_file_upload('spec/fixtures/doc_sample.txt', 'text/plain') }
before do before do
sign_in(user) sign_in(user)
......
...@@ -4,7 +4,7 @@ describe Import::GoogleCodeController do ...@@ -4,7 +4,7 @@ describe Import::GoogleCodeController do
include ImportSpecHelper include ImportSpecHelper
let(:user) { create(:user) } let(:user) { create(:user) }
let(:dump_file) { fixture_file_upload(Rails.root + 'spec/fixtures/GoogleCodeProjectHosting.json', 'application/json') } let(:dump_file) { fixture_file_upload('spec/fixtures/GoogleCodeProjectHosting.json', 'application/json') }
before do before do
sign_in(user) sign_in(user)
......
require 'spec_helper' require 'spec_helper'
describe Profiles::AvatarsController do describe Profiles::AvatarsController do
let(:user) { create(:user, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png")) } let(:user) { create(:user, avatar: fixture_file_upload("spec/fixtures/dk.png")) }
before do before do
sign_in(user) sign_in(user)
......
require 'spec_helper' require 'spec_helper'
describe Projects::AvatarsController do describe Projects::AvatarsController do
let(:project) { create(:project, :repository, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) } let(:project) { create(:project, :repository, avatar: fixture_file_upload("spec/fixtures/dk.png", "image/png")) }
let(:user) { create(:user) } let(:user) { create(:user) }
before do before do
......
...@@ -6,8 +6,8 @@ describe ProjectsController do ...@@ -6,8 +6,8 @@ describe ProjectsController do
let(:project) { create(:project) } let(:project) { create(:project) }
let(:public_project) { create(:project, :public) } let(:public_project) { create(:project, :public) }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:jpg) { fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg') } let(:jpg) { fixture_file_upload('spec/fixtures/rails_sample.jpg', 'image/jpg') }
let(:txt) { fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') } let(:txt) { fixture_file_upload('spec/fixtures/doc_sample.txt', 'text/plain') }
describe 'GET new' do describe 'GET new' do
context 'with an authenticated user' do context 'with an authenticated user' do
......
require 'spec_helper' require 'spec_helper'
describe RegistrationsController do describe RegistrationsController do
include TermsHelper
describe '#create' do describe '#create' do
let(:user_params) { { user: { name: 'new_user', username: 'new_username', email: 'new@user.com', password: 'Any_password' } } } let(:user_params) { { user: { name: 'new_user', username: 'new_username', email: 'new@user.com', password: 'Any_password' } } }
...@@ -67,6 +69,25 @@ describe RegistrationsController do ...@@ -67,6 +69,25 @@ describe RegistrationsController do
expect(flash[:notice]).to include 'Welcome! You have signed up successfully.' expect(flash[:notice]).to include 'Welcome! You have signed up successfully.'
end end
end end
context 'when terms are enforced' do
before do
enforce_terms
end
it 'redirects back with a notice when the checkbox was not checked' do
post :create, user_params
expect(flash[:alert]).to match /you must accept our terms/i
end
it 'creates the user with agreement when terms are accepted' do
post :create, user_params.merge(terms_opt_in: '1')
expect(subject.current_user).to be_present
expect(subject.current_user.terms_accepted?).to be(true)
end
end
end end
describe '#destroy' do describe '#destroy' do
......
...@@ -6,13 +6,13 @@ shared_examples 'content not cached without revalidation' do ...@@ -6,13 +6,13 @@ shared_examples 'content not cached without revalidation' do
end end
describe UploadsController do describe UploadsController do
let!(:user) { create(:user, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) } let!(:user) { create(:user, avatar: fixture_file_upload("spec/fixtures/dk.png", "image/png")) }
describe 'POST create' do describe 'POST create' do
let(:model) { 'personal_snippet' } let(:model) { 'personal_snippet' }
let(:snippet) { create(:personal_snippet, :public) } let(:snippet) { create(:personal_snippet, :public) }
let(:jpg) { fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg') } let(:jpg) { fixture_file_upload('spec/fixtures/rails_sample.jpg', 'image/jpg') }
let(:txt) { fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') } let(:txt) { fixture_file_upload('spec/fixtures/doc_sample.txt', 'text/plain') }
context 'when a user does not have permissions to upload a file' do context 'when a user does not have permissions to upload a file' do
it "returns 401 when the user is not logged in" do it "returns 401 when the user is not logged in" do
...@@ -205,7 +205,7 @@ describe UploadsController do ...@@ -205,7 +205,7 @@ describe UploadsController do
end end
context "when viewing a project avatar" do context "when viewing a project avatar" do
let!(:project) { create(:project, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) } let!(:project) { create(:project, avatar: fixture_file_upload("spec/fixtures/dk.png", "image/png")) }
context "when the project is public" do context "when the project is public" do
before do before do
...@@ -314,7 +314,7 @@ describe UploadsController do ...@@ -314,7 +314,7 @@ describe UploadsController do
end end
context "when viewing a group avatar" do context "when viewing a group avatar" do
let!(:group) { create(:group, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) } let!(:group) { create(:group, avatar: fixture_file_upload("spec/fixtures/dk.png", "image/png")) }
context "when the group is public" do context "when the group is public" do
context "when not signed in" do context "when not signed in" do
...@@ -521,7 +521,7 @@ describe UploadsController do ...@@ -521,7 +521,7 @@ describe UploadsController do
context 'Appearance' do context 'Appearance' do
context 'when viewing a custom header logo' do context 'when viewing a custom header logo' do
let!(:appearance) { create :appearance, header_logo: fixture_file_upload(Rails.root.join('spec/fixtures/dk.png'), 'image/png') } let!(:appearance) { create :appearance, header_logo: fixture_file_upload('spec/fixtures/dk.png', 'image/png') }
context 'when not signed in' do context 'when not signed in' do
it 'responds with status 200' do it 'responds with status 200' do
...@@ -541,7 +541,7 @@ describe UploadsController do ...@@ -541,7 +541,7 @@ describe UploadsController do
end end
context 'when viewing a custom logo' do context 'when viewing a custom logo' do
let!(:appearance) { create :appearance, logo: fixture_file_upload(Rails.root.join('spec/fixtures/dk.png'), 'image/png') } let!(:appearance) { create :appearance, logo: fixture_file_upload('spec/fixtures/dk.png', 'image/png') }
context 'when not signed in' do context 'when not signed in' do
it 'responds with status 200' do it 'responds with status 200' do
......
...@@ -7,7 +7,7 @@ FactoryBot.define do ...@@ -7,7 +7,7 @@ FactoryBot.define do
end end
trait :with_file do trait :with_file do
file { fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "`/png") } file { fixture_file_upload("spec/fixtures/dk.png", "`/png") }
end end
# The uniqueness constraint means we can't use the correct OID for all LFS # The uniqueness constraint means we can't use the correct OID for all LFS
......
...@@ -130,11 +130,11 @@ FactoryBot.define do ...@@ -130,11 +130,11 @@ FactoryBot.define do
end end
trait :with_attachment do trait :with_attachment do
attachment { fixture_file_upload(Rails.root.join( "spec/fixtures/dk.png"), "image/png") } attachment { fixture_file_upload("spec/fixtures/dk.png", "image/png") }
end end
trait :with_svg_attachment do trait :with_svg_attachment do
attachment { fixture_file_upload(Rails.root.join("spec/fixtures/unsanitized.svg"), "image/svg+xml") } attachment { fixture_file_upload("spec/fixtures/unsanitized.svg", "image/svg+xml") }
end end
transient do transient do
......
...@@ -94,7 +94,7 @@ feature 'Admin updates settings' do ...@@ -94,7 +94,7 @@ feature 'Admin updates settings' do
accept_terms(admin) accept_terms(admin)
page.within('.as-terms') do page.within('.as-terms') do
check 'Require all users to accept Terms of Service when they access GitLab.' check 'Require all users to accept Terms of Service and Privacy Policy when they access GitLab.'
fill_in 'Terms of Service Agreement', with: 'Be nice!' fill_in 'Terms of Service Agreement', with: 'Be nice!'
click_button 'Save changes' click_button 'Save changes'
end end
......
...@@ -47,7 +47,7 @@ describe 'Commits' do ...@@ -47,7 +47,7 @@ describe 'Commits' do
context 'commit status is Ci Build' do context 'commit status is Ci Build' do
let!(:build) { create(:ci_build, pipeline: pipeline) } let!(:build) { create(:ci_build, pipeline: pipeline) }
let(:artifacts_file) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') } let(:artifacts_file) { fixture_file_upload('spec/fixtures/banana_sample.gif', 'image/gif') }
context 'when logged as developer' do context 'when logged as developer' do
before do before do
......
...@@ -23,8 +23,8 @@ describe 'Merge request < User sees mini pipeline graph', :js do ...@@ -23,8 +23,8 @@ describe 'Merge request < User sees mini pipeline graph', :js do
end end
context 'as json' do context 'as json' do
let(:artifacts_file1) { fixture_file_upload(Rails.root.join('spec/fixtures/banana_sample.gif'), 'image/gif') } let(:artifacts_file1) { fixture_file_upload(File.join('spec/fixtures/banana_sample.gif'), 'image/gif') }
let(:artifacts_file2) { fixture_file_upload(Rails.root.join('spec/fixtures/dk.png'), 'image/png') } let(:artifacts_file2) { fixture_file_upload(File.join('spec/fixtures/dk.png'), 'image/png') }
before do before do
create(:ci_build, :success, :trace_artifact, pipeline: pipeline, legacy_artifacts_file: artifacts_file1) create(:ci_build, :success, :trace_artifact, pipeline: pipeline, legacy_artifacts_file: artifacts_file1)
......
...@@ -88,8 +88,7 @@ describe 'Project Jobs Permissions' do ...@@ -88,8 +88,7 @@ describe 'Project Jobs Permissions' do
describe 'artifacts page' do describe 'artifacts page' do
context 'when recent job has artifacts available' do context 'when recent job has artifacts available' do
before do before do
artifacts = Rails.root.join('spec/fixtures/ci_build_artifacts.zip') archive = fixture_file_upload('spec/fixtures/ci_build_artifacts.zip')
archive = fixture_file_upload(artifacts, 'application/zip')
job.update_attributes(legacy_artifacts_file: archive) job.update_attributes(legacy_artifacts_file: archive)
end end
......
...@@ -11,7 +11,7 @@ feature 'Jobs', :clean_gitlab_redis_shared_state do ...@@ -11,7 +11,7 @@ feature 'Jobs', :clean_gitlab_redis_shared_state do
let(:job2) { create(:ci_build) } let(:job2) { create(:ci_build) }
let(:artifacts_file) do let(:artifacts_file) do
fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') fixture_file_upload('spec/fixtures/banana_sample.gif', 'image/gif')
end end
before do before do
......
...@@ -314,8 +314,8 @@ feature 'Pages' do ...@@ -314,8 +314,8 @@ feature 'Pages' do
project: project, project: project,
pipeline: pipeline, pipeline: pipeline,
ref: 'HEAD', ref: 'HEAD',
legacy_artifacts_file: fixture_file_upload(Rails.root.join('spec/fixtures/pages.zip')), legacy_artifacts_file: fixture_file_upload(File.join('spec/fixtures/pages.zip')),
legacy_artifacts_metadata: fixture_file_upload(Rails.root.join('spec/fixtures/pages.zip.meta')) legacy_artifacts_metadata: fixture_file_upload(File.join('spec/fixtures/pages.zip.meta'))
) )
end end
......
...@@ -38,7 +38,7 @@ feature 'Master deletes tag' do ...@@ -38,7 +38,7 @@ feature 'Master deletes tag' do
context 'when Gitaly operation_user_delete_tag feature is enabled' do context 'when Gitaly operation_user_delete_tag feature is enabled' do
before do before do
allow_any_instance_of(Gitlab::GitalyClient::OperationService).to receive(:rm_tag) allow_any_instance_of(Gitlab::GitalyClient::OperationService).to receive(:rm_tag)
.and_raise(Gitlab::Git::HooksService::PreReceiveError, 'Do not delete tags') .and_raise(Gitlab::Git::PreReceiveError, 'Do not delete tags')
end end
scenario 'shows the error message' do scenario 'shows the error message' do
...@@ -51,7 +51,7 @@ feature 'Master deletes tag' do ...@@ -51,7 +51,7 @@ feature 'Master deletes tag' do
context 'when Gitaly operation_user_delete_tag feature is disabled', :skip_gitaly_mock do context 'when Gitaly operation_user_delete_tag feature is disabled', :skip_gitaly_mock do
before do before do
allow_any_instance_of(Gitlab::Git::HooksService).to receive(:execute) allow_any_instance_of(Gitlab::Git::HooksService).to receive(:execute)
.and_raise(Gitlab::Git::HooksService::PreReceiveError, 'Do not delete tags') .and_raise(Gitlab::Git::PreReceiveError, 'Do not delete tags')
end end
scenario 'shows the error message' do scenario 'shows the error message' do
......
...@@ -140,7 +140,7 @@ describe 'Signup' do ...@@ -140,7 +140,7 @@ describe 'Signup' do
enforce_terms enforce_terms
end end
it 'asks the user to accept terms before going to the dashboard' do it 'requires the user to check the checkbox' do
visit root_path visit root_path
fill_in 'new_user_name', with: new_user.name fill_in 'new_user_name', with: new_user.name
...@@ -148,11 +148,24 @@ describe 'Signup' do ...@@ -148,11 +148,24 @@ describe 'Signup' do
fill_in 'new_user_email', with: new_user.email fill_in 'new_user_email', with: new_user.email
fill_in 'new_user_email_confirmation', with: new_user.email fill_in 'new_user_email_confirmation', with: new_user.email
fill_in 'new_user_password', with: new_user.password fill_in 'new_user_password', with: new_user.password
click_button "Register"
expect_to_be_on_terms_page click_button 'Register'
expect(current_path).to eq new_user_session_path
expect(page).to have_content(/you must accept our terms of service/i)
end
it 'asks the user to accept terms before going to the dashboard' do
visit root_path
fill_in 'new_user_name', with: new_user.name
fill_in 'new_user_username', with: new_user.username
fill_in 'new_user_email', with: new_user.email
fill_in 'new_user_email_confirmation', with: new_user.email
fill_in 'new_user_password', with: new_user.password
check :terms_opt_in
click_button 'Accept terms' click_button "Register"
expect(current_path).to eq dashboard_projects_path expect(current_path).to eq dashboard_projects_path
end end
......
...@@ -3,12 +3,10 @@ require 'spec_helper' ...@@ -3,12 +3,10 @@ require 'spec_helper'
describe 'Users > Terms' do describe 'Users > Terms' do
include TermsHelper include TermsHelper
let(:user) { create(:user) }
let!(:term) { create(:term, terms: 'By accepting, you promise to be nice!') } let!(:term) { create(:term, terms: 'By accepting, you promise to be nice!') }
before do before do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
sign_in(user)
end end
it 'shows the terms' do it 'shows the terms' do
...@@ -17,102 +15,119 @@ describe 'Users > Terms' do ...@@ -17,102 +15,119 @@ describe 'Users > Terms' do
expect(page).to have_content('By accepting, you promise to be nice!') expect(page).to have_content('By accepting, you promise to be nice!')
end end
context 'declining the terms' do it 'does not show buttons to accept, decline or sign out', :aggregate_failures do
it 'returns the user to the app' do visit terms_path
visit terms_path
expect(page).not_to have_css('.footer-block')
expect(page).not_to have_content('Accept terms')
expect(page).not_to have_content('Decline and sign out')
expect(page).not_to have_content('Continue')
end
click_button 'Decline and sign out' context 'when signed in' do
let(:user) { create(:user) }
expect(page).not_to have_content(term.terms) before do
expect(user.reload.terms_accepted?).to be(false) sign_in(user)
end end
end
context 'accepting the terms' do context 'declining the terms' do
it 'returns the user to the app' do it 'returns the user to the app' do
visit terms_path visit terms_path
click_button 'Accept terms' click_button 'Decline and sign out'
expect(page).not_to have_content(term.terms) expect(page).not_to have_content(term.terms)
expect(user.reload.terms_accepted?).to be(true) expect(user.reload.terms_accepted?).to be(false)
end
end end
end
context 'when the user has already accepted the terms' do context 'accepting the terms' do
before do it 'returns the user to the app' do
accept_terms(user) visit terms_path
click_button 'Accept terms'
expect(page).not_to have_content(term.terms)
expect(user.reload.terms_accepted?).to be(true)
end
end end
it 'allows the user to continue to the app' do context 'when the user has already accepted the terms' do
visit terms_path before do
accept_terms(user)
end
it 'allows the user to continue to the app' do
visit terms_path
expect(page).to have_content "You have already accepted the Terms of Service as #{user.to_reference}" expect(page).to have_content "You have already accepted the Terms of Service as #{user.to_reference}"
click_link 'Continue' click_link 'Continue'
expect(current_path).to eq(root_path) expect(current_path).to eq(root_path)
end
end end
end
context 'terms were enforced while session is active', :js do context 'terms were enforced while session is active', :js do
let(:project) { create(:project) } let(:project) { create(:project) }
before do before do
project.add_developer(user) project.add_developer(user)
end end
it 'redirects to terms and back to where the user was going' do it 'redirects to terms and back to where the user was going' do
visit project_path(project) visit project_path(project)
enforce_terms enforce_terms
within('.nav-sidebar') do within('.nav-sidebar') do
click_link 'Issues' click_link 'Issues'
end end
expect_to_be_on_terms_page expect_to_be_on_terms_page
click_button('Accept terms') click_button('Accept terms')
expect(current_path).to eq(project_issues_path(project)) expect(current_path).to eq(project_issues_path(project))
end end
# Disabled until https://gitlab.com/gitlab-org/gitlab-ce/issues/37162 is solved properly # Disabled until https://gitlab.com/gitlab-org/gitlab-ce/issues/37162 is solved properly
xit 'redirects back to the page the user was trying to save' do xit 'redirects back to the page the user was trying to save' do
visit new_project_issue_path(project) visit new_project_issue_path(project)
fill_in :issue_title, with: 'Hello world, a new issue' fill_in :issue_title, with: 'Hello world, a new issue'
fill_in :issue_description, with: "We don't want to lose what the user typed" fill_in :issue_description, with: "We don't want to lose what the user typed"
enforce_terms enforce_terms
click_button 'Submit issue' click_button 'Submit issue'
expect(current_path).to eq(terms_path) expect(current_path).to eq(terms_path)
click_button('Accept terms') click_button('Accept terms')
expect(current_path).to eq(new_project_issue_path(project)) expect(current_path).to eq(new_project_issue_path(project))
expect(find_field('issue_title').value).to eq('Hello world, a new issue') expect(find_field('issue_title').value).to eq('Hello world, a new issue')
expect(find_field('issue_description').value).to eq("We don't want to lose what the user typed") expect(find_field('issue_description').value).to eq("We don't want to lose what the user typed")
end
end end
end
context 'when the terms are enforced' do context 'when the terms are enforced' do
before do before do
enforce_terms enforce_terms
end end
context 'signing out', :js do context 'signing out', :js do
it 'allows the user to sign out without a response' do it 'allows the user to sign out without a response' do
visit terms_path visit terms_path
find('.header-user-dropdown-toggle').click find('.header-user-dropdown-toggle').click
click_link('Sign out') click_link('Sign out')
expect(page).to have_content('Sign in') expect(page).to have_content('Sign in')
expect(page).to have_content('Register') expect(page).to have_content('Register')
end
end end
end end
end end
......
...@@ -47,9 +47,7 @@ describe EmailsHelper do ...@@ -47,9 +47,7 @@ describe EmailsHelper do
describe '#header_logo' do describe '#header_logo' do
context 'there is a brand item with a logo' do context 'there is a brand item with a logo' do
it 'returns the brand header logo' do it 'returns the brand header logo' do
appearance = create :appearance, header_logo: fixture_file_upload( appearance = create :appearance, header_logo: fixture_file_upload('spec/fixtures/dk.png')
Rails.root.join('spec/fixtures/dk.png')
)
expect(header_logo).to eq( expect(header_logo).to eq(
%{<img style="height: 50px" src="/uploads/-/system/appearance/header_logo/#{appearance.id}/dk.png" alt="Dk" />} %{<img style="height: 50px" src="/uploads/-/system/appearance/header_logo/#{appearance.id}/dk.png" alt="Dk" />}
......
...@@ -4,9 +4,9 @@ describe GroupsHelper do ...@@ -4,9 +4,9 @@ describe GroupsHelper do
include ApplicationHelper include ApplicationHelper
describe 'group_icon' do describe 'group_icon' do
avatar_file_path = File.join(Rails.root, 'spec', 'fixtures', 'banana_sample.gif')
it 'returns an url for the avatar' do it 'returns an url for the avatar' do
avatar_file_path = File.join('spec', 'fixtures', 'banana_sample.gif')
group = create(:group) group = create(:group)
group.avatar = fixture_file_upload(avatar_file_path) group.avatar = fixture_file_upload(avatar_file_path)
group.save! group.save!
...@@ -17,9 +17,9 @@ describe GroupsHelper do ...@@ -17,9 +17,9 @@ describe GroupsHelper do
end end
describe 'group_icon_url' do describe 'group_icon_url' do
avatar_file_path = File.join(Rails.root, 'spec', 'fixtures', 'banana_sample.gif')
it 'returns an url for the avatar' do it 'returns an url for the avatar' do
avatar_file_path = File.join('spec', 'fixtures', 'banana_sample.gif')
group = create(:group) group = create(:group)
group.avatar = fixture_file_upload(avatar_file_path) group.avatar = fixture_file_upload(avatar_file_path)
group.save! group.save!
......
...@@ -110,7 +110,7 @@ describe('Clusters Store', () => { ...@@ -110,7 +110,7 @@ describe('Clusters Store', () => {
expect( expect(
store.state.applications.jupyter.hostname, store.state.applications.jupyter.hostname,
).toEqual(`jupyter.${store.state.applications.ingress.externalIp}.xip.io`); ).toEqual(`jupyter.${store.state.applications.ingress.externalIp}.nip.io`);
}); });
}); });
}); });
...@@ -45,12 +45,15 @@ describe('IDE pipelines list', () => { ...@@ -45,12 +45,15 @@ describe('IDE pipelines list', () => {
setTimeout(done); setTimeout(done);
}); });
afterEach(() => { afterEach(done => {
vm.$store.dispatch('pipelines/stopPipelinePolling');
vm.$store.dispatch('pipelines/clearEtagPoll');
vm.$destroy(); vm.$destroy();
mock.restore(); mock.restore();
vm.$store
.dispatch('pipelines/stopPipelinePolling')
.then(() => vm.$store.dispatch('pipelines/clearEtagPoll'))
.then(done)
.catch(done.fail);
}); });
it('renders pipeline data', () => { it('renders pipeline data', () => {
......
...@@ -199,28 +199,39 @@ describe('IDE merge requests actions', () => { ...@@ -199,28 +199,39 @@ describe('IDE merge requests actions', () => {
}); });
it('commits reset mutations and actions', done => { it('commits reset mutations and actions', done => {
testAction( const commit = jasmine.createSpy();
openMergeRequest, const dispatch = jasmine.createSpy().and.returnValue(Promise.resolve());
{ projectPath: 'gitlab-org/gitlab-ce', id: '1' }, openMergeRequest({ commit, dispatch }, { projectPath: 'gitlab-org/gitlab-ce', id: '1' });
mockedState,
[ setTimeout(() => {
{ type: 'CLEAR_PROJECTS' }, expect(commit.calls.argsFor(0)).toEqual(['CLEAR_PROJECTS', null, { root: true }]);
{ type: 'SET_CURRENT_MERGE_REQUEST', payload: '1' }, expect(commit.calls.argsFor(1)).toEqual(['SET_CURRENT_MERGE_REQUEST', '1', { root: true }]);
{ type: 'RESET_OPEN_FILES' }, expect(commit.calls.argsFor(2)).toEqual(['RESET_OPEN_FILES', null, { root: true }]);
],
[ expect(dispatch.calls.argsFor(0)).toEqual([
{ type: 'pipelines/stopPipelinePolling' }, 'pipelines/resetLatestPipeline',
{ type: 'pipelines/clearEtagPoll' }, null,
{ type: 'pipelines/resetLatestPipeline' }, { root: true },
{ type: 'setCurrentBranchId', payload: '' }, ]);
], expect(dispatch.calls.argsFor(1)).toEqual(['setCurrentBranchId', '', { root: true }]);
done, expect(dispatch.calls.argsFor(2)).toEqual([
); 'pipelines/stopPipelinePolling',
null,
{ root: true },
]);
expect(dispatch.calls.argsFor(3)).toEqual([
'pipelines/clearEtagPoll',
null,
{ root: true },
]);
done();
});
}); });
it('pushes new route', () => { it('pushes new route', () => {
openMergeRequest( openMergeRequest(
{ commit() {}, dispatch() {} }, { commit() {}, dispatch: () => Promise.resolve() },
{ projectPath: 'gitlab-org/gitlab-ce', id: '1' }, { projectPath: 'gitlab-org/gitlab-ce', id: '1' },
); );
......
import Vue from 'vue'; import Vue from 'vue';
import authorTimeComponent from '~/vue_merge_request_widget/components/mr_widget_author_time.vue'; import MrWidgetAuthorTime from '~/vue_merge_request_widget/components/mr_widget_author_time.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('MRWidgetAuthorTime', () => { describe('MrWidgetAuthorTime', () => {
let vm; let vm;
beforeEach(() => { beforeEach(() => {
const Component = Vue.extend(authorTimeComponent); const Component = Vue.extend(MrWidgetAuthorTime);
vm = mountComponent(Component, { vm = mountComponent(Component, {
actionText: 'Merged by', actionText: 'Merged by',
...@@ -34,7 +34,7 @@ describe('MRWidgetAuthorTime', () => { ...@@ -34,7 +34,7 @@ describe('MRWidgetAuthorTime', () => {
}); });
it('renders provided time', () => { it('renders provided time', () => {
expect(vm.$el.querySelector('time').getAttribute('title')).toEqual('2017-03-23T23:02:00.807Z'); expect(vm.$el.querySelector('time').getAttribute('data-original-title')).toEqual('2017-03-23T23:02:00.807Z');
expect(vm.$el.querySelector('time').textContent.trim()).toEqual('12 hours ago'); expect(vm.$el.querySelector('time').textContent.trim()).toEqual('12 hours ago');
}); });
}); });
...@@ -186,7 +186,7 @@ describe('MRWidgetMerged', () => { ...@@ -186,7 +186,7 @@ describe('MRWidgetMerged', () => {
it('should use mergedEvent mergedAt as tooltip title', () => { it('should use mergedEvent mergedAt as tooltip title', () => {
expect( expect(
vm.$el.querySelector('time').getAttribute('title'), vm.$el.querySelector('time').getAttribute('data-original-title'),
).toBe('Jan 24, 2018 1:02pm GMT+0000'); ).toBe('Jan 24, 2018 1:02pm GMT+0000');
}); });
}); });
...@@ -9,24 +9,31 @@ describe Gitlab::Git::Hook do ...@@ -9,24 +9,31 @@ describe Gitlab::Git::Hook do
end end
describe "#trigger" do describe "#trigger" do
let(:project) { create(:project, :repository) } set(:project) { create(:project, :repository) }
let(:repository) { project.repository.raw_repository } let(:repository) { project.repository.raw_repository }
let(:repo_path) { repository.path } let(:repo_path) { repository.path }
let(:hooks_dir) { File.join(repo_path, 'hooks') }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:gl_id) { Gitlab::GlId.gl_id(user) } let(:gl_id) { Gitlab::GlId.gl_id(user) }
let(:gl_username) { user.username } let(:gl_username) { user.username }
def create_hook(name) def create_hook(name)
FileUtils.mkdir_p(File.join(repo_path, 'hooks')) FileUtils.mkdir_p(hooks_dir)
File.open(File.join(repo_path, 'hooks', name), 'w', 0755) do |f| hook_path = File.join(hooks_dir, name)
f.write('exit 0') File.open(hook_path, 'w', 0755) do |f|
f.write(<<~HOOK)
#!/bin/sh
exit 0
HOOK
end end
end end
def create_failing_hook(name) def create_failing_hook(name)
FileUtils.mkdir_p(File.join(repo_path, 'hooks')) FileUtils.mkdir_p(hooks_dir)
File.open(File.join(repo_path, 'hooks', name), 'w', 0755) do |f| hook_path = File.join(hooks_dir, name)
f.write(<<-HOOK) File.open(hook_path, 'w', 0755) do |f|
f.write(<<~HOOK)
#!/bin/sh
echo 'regular message from the hook' echo 'regular message from the hook'
echo 'error message from the hook' 1>&2 echo 'error message from the hook' 1>&2
echo 'error message from the hook line 2' 1>&2 echo 'error message from the hook line 2' 1>&2
...@@ -38,7 +45,7 @@ describe Gitlab::Git::Hook do ...@@ -38,7 +45,7 @@ describe Gitlab::Git::Hook do
['pre-receive', 'post-receive', 'update'].each do |hook_name| ['pre-receive', 'post-receive', 'update'].each do |hook_name|
context "when triggering a #{hook_name} hook" do context "when triggering a #{hook_name} hook" do
context "when the hook is successful" do context "when the hook is successful" do
let(:hook_path) { File.join(repo_path, 'hooks', hook_name) } let(:hook_path) { File.join(hooks_dir, hook_name) }
let(:gl_repository) { Gitlab::GlRepository.gl_repository(project, false) } let(:gl_repository) { Gitlab::GlRepository.gl_repository(project, false) }
let(:env) do let(:env) do
{ {
...@@ -76,7 +83,7 @@ describe Gitlab::Git::Hook do ...@@ -76,7 +83,7 @@ describe Gitlab::Git::Hook do
status, errors = hook.trigger(gl_id, gl_username, blank, blank, ref) status, errors = hook.trigger(gl_id, gl_username, blank, blank, ref)
expect(status).to be false expect(status).to be false
expect(errors).to eq("error message from the hook<br>error message from the hook line 2<br>") expect(errors).to eq("error message from the hook\nerror message from the hook line 2\n")
end end
end end
end end
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment