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
retry: 1
......@@ -394,7 +394,11 @@ compile-assets:
- date
- yarn install --frozen-lockfile --cache-folder .yarn-cache
- date
- free -m
- 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:
expire_in: 7d
paths:
......@@ -658,10 +662,13 @@ gitlab:assets:compile:
SKIP_STORAGE_VALIDATION: "true"
WEBPACK_REPORT: "true"
NO_COMPRESSION: "true"
# we override the max_old_space_size to prevent OOM errors
NODE_OPTIONS: --max_old_space_size=3584
script:
- date
- yarn install --frozen-lockfile --production --cache-folder .yarn-cache
- date
- free -m
- bundle exec rake gitlab:assets:compile
artifacts:
name: webpack-report
......
......@@ -134,7 +134,7 @@ gem 'seed-fu', '~> 2.3.7'
# Markdown and HTML processing
gem 'html-pipeline', '~> 2.7.1'
gem 'deckar01-task_list', '2.0.0'
gem 'gitlab-markup', '~> 1.6.2'
gem 'gitlab-markup', '~> 1.6.4'
gem 'redcarpet', '~> 3.4'
gem 'commonmarker', '~> 0.17'
gem 'RedCloth', '~> 4.3.2'
......@@ -333,7 +333,7 @@ group :development, :test do
gem 'database_cleaner', '~> 1.5.0'
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_profiling', '~> 0.0.5'
gem 'rspec-set', '~> 0.1.3'
......
......@@ -312,7 +312,7 @@ GEM
diff-lcs (~> 1.1)
mime-types (>= 1.16)
posix-spawn (~> 0.3)
gitlab-markup (1.6.3)
gitlab-markup (1.6.4)
gitlab-styles (2.3.2)
rubocop (~> 0.51)
rubocop-gitlab-security (~> 0.1.0)
......@@ -360,8 +360,8 @@ GEM
grape-entity (0.7.1)
activesupport (>= 4.0)
multi_json (>= 1.3.2)
grape-path-helpers (1.0.4)
activesupport (~> 4)
grape-path-helpers (1.0.5)
activesupport (>= 4, < 5.1)
grape (~> 1.0)
rake (~> 12)
grape_logging (1.7.0)
......@@ -742,36 +742,36 @@ GEM
chunky_png
rqrcode-rails3 (0.1.7)
rqrcode (>= 0.4.2)
rspec (3.6.0)
rspec-core (~> 3.6.0)
rspec-expectations (~> 3.6.0)
rspec-mocks (~> 3.6.0)
rspec-core (3.6.0)
rspec-support (~> 3.6.0)
rspec-expectations (3.6.0)
rspec (3.7.0)
rspec-core (~> 3.7.0)
rspec-expectations (~> 3.7.0)
rspec-mocks (~> 3.7.0)
rspec-core (3.7.1)
rspec-support (~> 3.7.0)
rspec-expectations (3.7.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.6.0)
rspec-mocks (3.6.0)
rspec-support (~> 3.7.0)
rspec-mocks (3.7.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.6.0)
rspec-support (~> 3.7.0)
rspec-parameterized (0.4.0)
binding_of_caller
parser
proc_to_ast
rspec (>= 2.13, < 4)
unparser
rspec-rails (3.6.0)
rspec-rails (3.7.2)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec-core (~> 3.6.0)
rspec-expectations (~> 3.6.0)
rspec-mocks (~> 3.6.0)
rspec-support (~> 3.6.0)
rspec-core (~> 3.7.0)
rspec-expectations (~> 3.7.0)
rspec-mocks (~> 3.7.0)
rspec-support (~> 3.7.0)
rspec-retry (0.4.5)
rspec-core
rspec-set (0.1.3)
rspec-support (3.6.0)
rspec-support (3.7.1)
rspec_profiling (0.0.5)
activerecord
pg
......@@ -1044,7 +1044,7 @@ DEPENDENCIES
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-gollum-lib (~> 4.2)
gitlab-gollum-rugged_adapter (~> 0.4.4)
gitlab-markup (~> 1.6.2)
gitlab-markup (~> 1.6.4)
gitlab-styles (~> 2.3)
gitlab_omniauth-ldap (~> 2.0.4)
gon (~> 6.2)
......@@ -1141,7 +1141,7 @@ DEPENDENCIES
rouge (~> 3.1)
rqrcode-rails3 (~> 0.1.7)
rspec-parameterized
rspec-rails (~> 3.6.0)
rspec-rails (~> 3.7.0)
rspec-retry (~> 0.4.5)
rspec-set (~> 0.1.3)
rspec_profiling (~> 0.0.5)
......
......@@ -286,7 +286,7 @@ GEM
gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
gitaly-proto (0.100.0)
gitaly-proto (0.101.0)
google-protobuf (~> 3.1)
grpc (~> 1.10)
github-linguist (5.3.3)
......@@ -363,10 +363,10 @@ GEM
grape-entity (0.7.1)
activesupport (>= 4.0)
multi_json (>= 1.3.2)
grape-path-helpers (1.0.0)
activesupport
grape-path-helpers (1.0.5)
activesupport (>= 4, < 5.1)
grape (~> 1.0)
rake
rake (~> 12)
grape_logging (1.7.0)
grape
graphiql-rails (1.4.10)
......@@ -501,6 +501,7 @@ GEM
mime-types-data (~> 3.2015)
mime-types-data (3.2016.0521)
mimemagic (0.3.0)
mini_magick (4.8.0)
mini_mime (1.0.0)
mini_portile2 (2.3.0)
minitest (5.7.0)
......@@ -1048,7 +1049,7 @@ DEPENDENCIES
gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3)
gitaly-proto (~> 0.100.0)
gitaly-proto (~> 0.101.0)
github-linguist (~> 5.3.3)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-gollum-lib (~> 4.2)
......@@ -1091,6 +1092,7 @@ DEPENDENCIES
loofah (~> 2.2)
mail_room (~> 0.9.1)
method_source (~> 0.8)
mini_magick
minitest (~> 5.7.0)
mousetrap-rails (~> 1.4.6)
mysql2 (~> 0.4.10)
......
......@@ -95,7 +95,7 @@ export default class ClusterStore {
this.state.applications.jupyter.hostname =
serverAppEntry.hostname ||
(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 }) => {
commit(rootTypes.CLEAR_PROJECTS, null, { root: true });
commit(rootTypes.SET_CURRENT_MERGE_REQUEST, `${id}`, { 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('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}`);
};
......
......@@ -12,8 +12,12 @@ let eTagPoll;
export const clearEtagPoll = () => {
eTagPoll = null;
};
export const stopPipelinePolling = () => eTagPoll && eTagPoll.stop();
export const restartPipelinePolling = () => eTagPoll && eTagPoll.restart();
export const stopPipelinePolling = () => {
if (eTagPoll) eTagPoll.stop();
};
export const restartPipelinePolling = () => {
if (eTagPoll) eTagPoll.restart();
};
export const requestLatestPipeline = ({ commit }) => commit(types.REQUEST_LATEST_PIPELINE);
export const receiveLatestPipelineError = ({ commit, dispatch }) => {
......@@ -51,9 +55,9 @@ export const fetchLatestPipeline = ({ dispatch, rootGetters }) => {
Visibility.change(() => {
if (!Visibility.hidden()) {
eTagPoll.restart();
dispatch('restartPipelinePolling');
} else {
eTagPoll.stop();
dispatch('stopPipelinePolling');
}
});
};
......
<script>
import { parseSeconds, stringifyTime } from '../../../lib/utils/pretty_time';
import tooltip from '../../../vue_shared/directives/tooltip';
export default {
name: 'TimeTrackingComparisonPane',
directives: {
tooltip,
},
props: {
timeSpent: {
type: Number,
......@@ -50,9 +54,8 @@ export default {
<template>
<div class="time-tracking-comparison-pane">
<div
:aria-valuenow="timeRemainingTooltip"
v-tooltip
:title="timeRemainingTooltip"
:data-original-title="timeRemainingTooltip"
:class="timeRemainingStatusClass"
class="compare-meter"
data-toggle="tooltip"
......@@ -62,7 +65,6 @@ export default {
<div
:aria-valuenow="timeRemainingPercent"
class="meter-container"
role="timeSpentPercent"
>
<div
:style="{ width: timeRemainingPercent }"
......
<script>
import tooltip from '~/vue_shared/directives/tooltip';
import MrWidgetAuthor from './mr_widget_author.vue';
export default {
name: 'MRWidgetAuthorTime',
name: 'MrWidgetAuthorTime',
components: {
MrWidgetAuthor,
},
directives: {
tooltip,
},
props: {
actionText: {
type: String,
......@@ -31,9 +35,8 @@
{{ actionText }}
<mr-widget-author :author="author" />
<time
v-tooltip
:title="dateTitle"
data-toggle="tooltip"
data-placement="top"
data-container="body"
>
{{ dateReadable }}
......
<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';
export default {
name: 'MRWidgetClosed',
components: {
mrWidgetAuthorTime,
MrWidgetAuthorTime,
statusIcon,
},
props: {
......
......@@ -4,7 +4,7 @@
import loadingIcon from '~/vue_shared/components/loading_icon.vue';
import { s__, __ } from '~/locale';
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 eventHub from '../../event_hub';
......@@ -14,7 +14,7 @@
tooltip,
},
components: {
mrWidgetAuthorTime,
MrWidgetAuthorTime,
loadingIcon,
statusIcon,
ClipboardButton,
......
......@@ -58,8 +58,13 @@ table {
display: none;
}
table,
tbody,
td {
display: block;
}
td {
color: $gl-text-color-secondary;
}
......
......@@ -3,6 +3,9 @@ class RegistrationsController < Devise::RegistrationsController
include AcceptsPendingInvitations
before_action :whitelist_query_limiting, only: [:destroy]
before_action :ensure_terms_accepted,
if: -> { Gitlab::CurrentSettings.current_application_settings.enforce_terms? },
only: [:create]
def new
redirect_to(new_user_session_path)
......@@ -18,7 +21,9 @@ class RegistrationsController < Devise::RegistrationsController
if !Gitlab::Recaptcha.load_configurations! || verify_recaptcha
accept_pending_invitations
super
super do |new_user|
persist_accepted_terms_if_required(new_user)
end
else
flash[:alert] = 'There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.'
flash.delete :recaptcha_error
......@@ -40,6 +45,16 @@ class RegistrationsController < Devise::RegistrationsController
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?
if current_user.confirm_deletion_with_password?
current_user.valid_password?(params[:password])
......@@ -91,4 +106,14 @@ class RegistrationsController < Devise::RegistrationsController
def whitelist_query_limiting
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-ce/issues/42380')
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
......@@ -2,6 +2,7 @@ module Users
class TermsController < ApplicationController
include InternalRedirect
skip_before_action :authenticate_user!
skip_before_action :enforce_terms!
skip_before_action :check_password_expiration
skip_before_action :check_two_factor_requirement
......@@ -14,7 +15,7 @@ module Users
def index
@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}"
end
end
......
......@@ -8,6 +8,7 @@ module Ci
include Gitlab::OptimisticLocking
include Gitlab::Utils::StrongMemoize
include AtomicInternalId
include EnumWithNil
belongs_to :project, inverse_of: :pipelines
belongs_to :user
......@@ -54,7 +55,7 @@ module Ci
after_create :keep_around_commits, unless: :importing?
enum source: {
enum_with_nil source: {
unknown: nil,
push: 1,
web: 2,
......@@ -64,7 +65,7 @@ module Ci
external: 6
}
enum config_source: {
enum_with_nil config_source: {
unknown_source: nil,
repository_source: 1,
auto_devops_source: 2
......@@ -599,17 +600,6 @@ module Ci
@latest_builds_with_artifacts ||= builds.latest.with_artifacts_archive.to_a
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
def ci_yaml_from_repo
......
......@@ -3,6 +3,7 @@ class CommitStatus < ActiveRecord::Base
include Importable
include AfterCommitQueue
include Presentable
include EnumWithNil
self.table_name = 'ci_builds'
......@@ -39,7 +40,7 @@ class CommitStatus < ActiveRecord::Base
scope :retried_ordered, -> { retried.ordered.includes(project: :namespace) }
scope :after_stage, -> (index) { where('stage_idx > ?', index) }
enum failure_reason: {
enum_with_nil failure_reason: {
unknown_failure: nil,
script_failure: 1,
api_failure: 2,
......@@ -190,11 +191,4 @@ class CommitStatus < ActiveRecord::Base
v =~ /\d+/ ? v.to_i : v
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
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
validates :name, uniqueness: { scope: :namespace_id }
validates :import_url, url: { protocols: %w(http https ssh git),
allow_localhost: false,
enforce_user: true,
ports: VALID_IMPORT_PORTS }, if: [:external_import?, :import_url_changed?]
validates :star_count, numericality: { greater_than_or_equal_to: 0 }
validate :check_limit, on: :create
......
......@@ -16,7 +16,7 @@ class RemoteMirror < ActiveRecord::Base
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?
......
......@@ -17,7 +17,7 @@ module Commits
new_commit = create_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)
end
......
......@@ -14,7 +14,7 @@ class CreateBranchService < BaseService
else
error('Invalid reference name')
end
rescue Gitlab::Git::HooksService::PreReceiveError => ex
rescue Gitlab::Git::PreReceiveError => ex
error(ex.message)
end
......
......@@ -16,7 +16,7 @@ class DeleteBranchService < BaseService
else
error('Failed to remove branch')
end
rescue Gitlab::Git::HooksService::PreReceiveError => ex
rescue Gitlab::Git::PreReceiveError => ex
error(ex.message)
end
......
......@@ -13,7 +13,7 @@ module MergeRequests
source,
merge_request.target_branch,
merge_request: merge_request)
rescue Gitlab::Git::HooksService::PreReceiveError => e
rescue Gitlab::Git::PreReceiveError => e
raise MergeError, e.message
rescue StandardError => e
raise MergeError, "Something went wrong during merge: #{e.message}"
......
......@@ -79,7 +79,7 @@ module MergeRequests
message = params[:commit_message] || merge_request.merge_commit_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)
raise MergeError, 'Something went wrong during merge pre-receive hook'
rescue => e
......
......@@ -135,6 +135,7 @@ module Projects
raise_error('Failed to remove some tags in project container registry. Please try again or contact administrator.')
end
log_destroy_event
trash_repositories!
# Rails attempts to load all related records into memory before
......@@ -148,6 +149,10 @@ module Projects
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
# for legacy image repository (when repository path equals project path).
......
......@@ -13,7 +13,7 @@ module Tags
new_tag = repository.add_tag(current_user, tag_name, target, message)
rescue Gitlab::Git::Repository::TagExistsError
return error("Tag #{tag_name} already exists")
rescue Gitlab::Git::HooksService::PreReceiveError => ex
rescue Gitlab::Git::PreReceiveError => ex
return error(ex.message)
end
......
......@@ -21,7 +21,7 @@ module Tags
else
error('Failed to remove tag')
end
rescue Gitlab::Git::HooksService::PreReceiveError => ex
rescue Gitlab::Git::PreReceiveError => ex
error(ex.message)
end
......
......@@ -13,7 +13,7 @@ class ValidateNewBranchService < BaseService
end
success
rescue Gitlab::Git::HooksService::PreReceiveError => ex
rescue Gitlab::Git::PreReceiveError => ex
error(ex.message)
end
end
......@@ -18,6 +18,13 @@
# 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.
#
# 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:
# class User < ActiveRecord::Base
# validates :personal_url, url: { allow_localhost: false, allow_local_network: false}
......@@ -35,7 +42,7 @@ class UrlValidator < ActiveModel::EachValidator
if value.present?
value.strip!
else
record.errors.add(attribute, "must be a valid URL")
record.errors.add(attribute, 'must be a valid URL')
end
Gitlab::UrlBlocker.validate!(value, blocker_args)
......@@ -51,7 +58,8 @@ class UrlValidator < ActiveModel::EachValidator
protocols: DEFAULT_PROTOCOLS,
ports: [],
allow_localhost: true,
allow_local_network: true
allow_local_network: true,
enforce_user: false
}
end
......@@ -64,7 +72,7 @@ class UrlValidator < ActiveModel::EachValidator
end
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?
args[:allow_localhost] = args[:allow_local_network] = true
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)
%fieldset
......@@ -7,13 +7,13 @@
.form-check
= f.check_box :enforce_terms, class: 'form-check-input'
= 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
= _("When enabled, users cannot use GitLab until the terms have been accepted.")
.form-group.row
.col-sm-12
= f.label :terms do
= _("Terms of Service Agreement")
= _("Terms of Service Agreement and Privacy Policy")
.col-sm-12
= f.text_area :terms, class: 'form-control', rows: 8
.form-text.text-muted
......
......@@ -50,11 +50,11 @@
%section.settings.as-terms.no-animate#js-terms-settings{ class: ('expanded' if expanded) }
.settings-header
%h4
= _('Terms of Service')
= _('Terms of Service and Privacy Policy')
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
= expanded ? _('Collapse') : _('Expand')
%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
= render 'terms'
......
......@@ -22,6 +22,13 @@
= 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."
%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
- if Gitlab::Recaptcha.enabled?
= recaptcha_tags
......
......@@ -9,10 +9,10 @@
.tree-holder
.nav-block
%ul.breadcrumb.repo-breadcrumb
%li
%li.breadcrumb-item
= link_to 'Artifacts', browse_project_job_artifacts_path(@project, @build)
- path_breadcrumbs do |title, path|
%li
%li.breadcrumb-item
= link_to truncate(title, length: 40), browse_project_job_artifacts_path(@project, @build, path)
.tree-controls
......
......@@ -3,7 +3,8 @@
.js-file-title.file-title
= link_to blob_link do
%i.fa.fa-file
= search_blob_title(project, file_name)
%strong
= search_blob_title(project, file_name)
- if blob.data
.file-content.code.term
= 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 @@
.card-body.rendered-terms
= markdown_field(@term, :terms)
.card-footer.footer-block.clearfix
- if can?(current_user, :accept_terms, @term)
.float-right
= button_to accept_term_path(@term, redirect_params), class: 'btn btn-success prepend-left-8' do
= _('Accept terms')
- else
.pull-right
= link_to root_path, class: 'btn btn-success prepend-left-8' do
= _('Continue')
- if can?(current_user, :decline_terms, @term)
.float-right
= button_to decline_term_path(@term, redirect_params), class: 'btn btn-default prepend-left-8' do
= _('Decline and sign out')
- if current_user
.card-footer.footer-block.clearfix
- if can?(current_user, :accept_terms, @term)
.float-right
= button_to accept_term_path(@term, redirect_params), class: 'btn btn-success prepend-left-8' do
= _('Accept terms')
- else
.pull-right
= link_to root_path, class: 'btn btn-success prepend-left-8' do
= _('Continue')
- if can?(current_user, :decline_terms, @term)
.float-right
= 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
# Abstract representation of an index definition on a table. Instances of
# this type are typically created and returned by methods in database
# 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
......
const fs = require('fs');
const path = require('path');
const glob = require('glob');
const webpack = require('webpack');
......
......@@ -301,9 +301,9 @@ sudo usermod -aG redis git
### Clone the Source
# 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
......
......@@ -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."
#### 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
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
directed to the page to accept the terms themselves. After they
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
When this feature was enabled, the users that have not accepted the
......
......@@ -7,9 +7,7 @@ module Gitlab
end
def value
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
@value ||= count_commits
end
@value ||= count_commits
end
private
......@@ -21,19 +19,11 @@ module Gitlab
def count_commits
return unless ref
repository = @project.repository.raw_repository
sha = @project.repository.commit(ref).sha
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?
gitaly_commit_client.commit_count(ref, after: @from)
end
output.lines.count
def gitaly_commit_client
Gitlab::GitalyClient::CommitService.new(@project.repository.raw_repository)
end
def ref
......
......@@ -22,7 +22,7 @@ module Gitlab
private
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
load_blame_by_gitaly
else
......
......@@ -20,7 +20,7 @@ module Gitlab
end
result[:newrev]
rescue Gitlab::Git::HooksService::PreReceiveError => e
rescue Gitlab::Git::PreReceiveError => e
message = "Custom Hook failed: #{e.message}"
raise Gitlab::Git::Wiki::OperationError, message
end
......
......@@ -11,7 +11,7 @@ module Gitlab
def initialize(name, repository)
@name = name
@repository = repository
@path = File.join(repo_path.strip, 'hooks', name)
@path = File.join(repo_path, 'hooks', name)
end
def repo_path
......@@ -95,13 +95,13 @@ module Gitlab
args = [ref, oldrev, newrev]
stdout, stderr, status = Open3.capture3(env, path, *args, options)
[status.success?, Gitlab::Utils.nlbr(stderr.presence || stdout)]
[status.success?, stderr.presence || stdout]
end
def retrieve_error_message(stderr, stdout)
err_message = stderr.read
err_message = err_message.blank? ? stdout.read : err_message
Gitlab::Utils.nlbr(err_message)
err_message
end
end
end
......
module Gitlab
module Git
class HooksService
PreReceiveError = Class.new(StandardError)
attr_accessor :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
def count_commits(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
count_commits_by_gitaly(count_commits_options)
else
......@@ -738,7 +738,7 @@ module Gitlab
#
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/330
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
gitaly_commit_client.commit_count(ref)
else
......
......@@ -20,7 +20,7 @@ module Gitlab
response = GitalyClient.call(@repository.storage, :operation_service, :user_delete_tag, request)
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
......@@ -35,7 +35,7 @@ module Gitlab
response = GitalyClient.call(@repository.storage, :operation_service, :user_create_tag, request)
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
raise Gitlab::Git::Repository::TagExistsError
end
......@@ -56,7 +56,7 @@ module Gitlab
:user_create_branch, request)
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
branch = response.branch
......@@ -76,7 +76,7 @@ module Gitlab
response = GitalyClient.call(@repository.storage, :operation_service, :user_delete_branch, request)
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
......@@ -106,7 +106,7 @@ module Gitlab
second_response = response_enum.next
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
branch_update = second_response.branch_update
......@@ -175,7 +175,7 @@ module Gitlab
)
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
raise Gitlab::Git::Repository::GitError, response.git_error
else
......@@ -242,7 +242,7 @@ module Gitlab
:user_commit_files, req_enum, remote_storage: start_repository.storage)
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
if (index_error = response.index_error.presence)
......@@ -280,7 +280,7 @@ module Gitlab
def handle_cherry_pick_or_revert_response(response)
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
raise Gitlab::Git::CommitError, response.commit_error
elsif response.create_tree_error.presence
......
......@@ -5,7 +5,7 @@ module Gitlab
BlockedUrlError = Class.new(StandardError)
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?
begin
......@@ -20,7 +20,7 @@ module Gitlab
port = uri.port || uri.default_port
validate_protocol!(uri.scheme, protocols)
validate_port!(port, ports) if ports.any?
validate_user!(uri.user)
validate_user!(uri.user) if enforce_user
validate_hostname!(uri.hostname)
begin
......
......@@ -8,8 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-06-07 19:35+0200\n"
"PO-Revision-Date: 2018-06-07 19:35+0200\n"
"POT-Creation-Date: 2018-06-08 18:19+0200\n"
"PO-Revision-Date: 2018-06-08 18:19+0200\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
......@@ -232,7 +232,7 @@ msgstr ""
msgid "Account"
msgstr ""
msgid "Account and limit settings"
msgid "Account and limit"
msgstr ""
msgid "Active"
......@@ -780,9 +780,6 @@ msgstr ""
msgid "CI/CD settings"
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."
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."
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"
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."
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"
msgstr ""
......@@ -2133,6 +2145,9 @@ msgstr ""
msgid "Failed to update issues, please try again."
msgstr ""
msgid "Failure"
msgstr ""
msgid "Feb"
msgstr ""
......@@ -2371,6 +2386,12 @@ msgstr ""
msgid "Housekeeping successfully started"
msgstr ""
msgid "I accept the %{terms_link}"
msgstr ""
msgid "I accept the|Terms of Service and Privacy Policy"
msgstr ""
msgid "IDE|Commit"
msgstr ""
......@@ -2407,7 +2428,7 @@ msgstr ""
msgid "Import repository"
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 ""
msgid "Install Runner on Kubernetes"
......@@ -3548,7 +3569,7 @@ msgstr ""
msgid "Repository maintenance"
msgstr ""
msgid "Repository mirror settings"
msgid "Repository mirror"
msgstr ""
msgid "Repository storage"
......@@ -3557,7 +3578,7 @@ msgstr ""
msgid "Request Access"
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 ""
msgid "Reset git storage health information"
......@@ -3616,9 +3637,6 @@ msgstr ""
msgid "Runners can be placed on separate users, servers, and even on your local machine."
msgstr ""
msgid "Runners settings"
msgstr ""
msgid "Running"
msgstr ""
......@@ -3942,6 +3960,9 @@ msgstr ""
msgid "Squash commits"
msgstr ""
msgid "Stage"
msgstr ""
msgid "Stage all"
msgstr ""
......@@ -4100,10 +4121,10 @@ msgstr ""
msgid "Team"
msgstr ""
msgid "Terms of Service"
msgid "Terms of Service Agreement and Privacy Policy"
msgstr ""
msgid "Terms of Service Agreement"
msgid "Terms of Service and Privacy Policy"
msgstr ""
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 ""
msgid "Timeago|%s days remaining"
msgstr ""
msgid "Timeago|%s hours ago"
msgstr ""
msgid "Timeago|%s hours remaining"
msgstr ""
......@@ -4346,6 +4370,9 @@ msgstr ""
msgid "Timeago|%s months remaining"
msgstr ""
msgid "Timeago|%s seconds ago"
msgstr ""
msgid "Timeago|%s seconds remaining"
msgstr ""
......@@ -4361,46 +4388,43 @@ msgstr ""
msgid "Timeago|%s years remaining"
msgstr ""
msgid "Timeago|1 day remaining"
msgid "Timeago|1 day ago"
msgstr ""
msgid "Timeago|1 hour remaining"
msgstr ""
msgid "Timeago|1 minute remaining"
msgid "Timeago|1 day remaining"
msgstr ""
msgid "Timeago|1 month remaining"
msgid "Timeago|1 hour ago"
msgstr ""
msgid "Timeago|1 week remaining"
msgid "Timeago|1 hour remaining"
msgstr ""
msgid "Timeago|1 year remaining"
msgid "Timeago|1 minute ago"
msgstr ""
msgid "Timeago|Past due"
msgid "Timeago|1 minute remaining"
msgstr ""
msgid "Timeago|a day ago"
msgid "Timeago|1 month ago"
msgstr ""
msgid "Timeago|a month ago"
msgid "Timeago|1 month remaining"
msgstr ""
msgid "Timeago|a week ago"
msgid "Timeago|1 week ago"
msgstr ""
msgid "Timeago|a year ago"
msgid "Timeago|1 week remaining"
msgstr ""
msgid "Timeago|about %s hours ago"
msgid "Timeago|1 year ago"
msgstr ""
msgid "Timeago|about a minute ago"
msgid "Timeago|1 year remaining"
msgstr ""
msgid "Timeago|about an hour ago"
msgid "Timeago|Past due"
msgstr ""
msgid "Timeago|in %s days"
......@@ -4442,7 +4466,7 @@ msgstr ""
msgid "Timeago|in 1 year"
msgstr ""
msgid "Timeago|less than a minute ago"
msgid "Timeago|just now"
msgstr ""
msgid "Timeago|right now"
......@@ -4872,6 +4896,9 @@ msgstr ""
msgid "You have reached your project limit"
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"
msgstr ""
......
......@@ -3,7 +3,7 @@ module QA
module Repository
class Push < Factory::Base
attr_accessor :file_name, :file_content, :commit_message,
:branch_name, :new_branch
:branch_name, :new_branch, :output
attr_writer :remote_branch
......@@ -12,6 +12,10 @@ module QA
project.description = 'Project with repository'
end
product :output do |factory|
factory.output
end
def initialize
@file_name = 'file.txt'
@file_content = '# This is test project'
......@@ -58,7 +62,7 @@ module QA
end
repository.commit(commit_message)
repository.push_changes("#{branch_name}:#{remote_branch}")
@output = repository.push_changes("#{branch_name}:#{remote_branch}")
end
end
end
......
......@@ -46,7 +46,9 @@ module QA
resource.remote_branch = @branch_name
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,
# select the already created branch and protect it according
......@@ -62,13 +64,13 @@ module QA
page.select_branch(branch_name)
if allow_to_push
page.allow_devs_and_masters_to_push
page.allow_devs_and_maintainers_to_push
else
page.allow_no_one_to_push
end
if allow_to_merge
page.allow_devs_and_masters_to_merge
page.allow_devs_and_maintainers_to_merge
else
page.allow_no_one_to_merge
end
......@@ -79,9 +81,13 @@ module QA
page.protect_branch
# Wait for page load, which resets the expanded sections
page.wait(reload: false) do
!page.has_content?('Collapse')
# Avoid Selenium::WebDriver::Error::StaleElementReferenceError
# without sleeping. I.e. this completes fast on fast machines.
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
......
......@@ -7,8 +7,6 @@ module QA
class Repository
include Scenario::Actable
attr_reader :push_output
def self.perform(*args)
Dir.mktmpdir do |dir|
Dir.chdir(dir) { super }
......@@ -71,7 +69,9 @@ module QA
end
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
def commits
......
......@@ -13,7 +13,7 @@ module QA
visit current_url
end
def wait(max: 60, time: 1, reload: true)
def wait(max: 60, time: 0.1, reload: true)
start = Time.now
while Time.now - start < max
......
......@@ -28,11 +28,9 @@ module QA
def has_subgroup?(name)
filter_by_name(name)
wait(reload: false) do
break false if page.has_content?('Sorry, no groups or projects matched your search')
page.has_text?(/#{name}|Sorry, no groups or projects matched your search/, wait: 60)
page.has_link?(name)
end
page.has_text?(name, wait: 0)
end
def go_to_new_subgroup
......
......@@ -6,6 +6,7 @@ module QA::Page
view 'app/views/shared/builds/_build_output.html.haml' do
element :build_output, '.js-build-output'
element :loading_animation, '.js-build-refresh'
end
view 'app/assets/javascripts/vue_shared/components/ci_badge_link.vue' do
......@@ -20,6 +21,10 @@ module QA::Page
find('.ci-status').text == PASSED_STATUS
end
def trace_loading?
has_css?('.js-build-refresh')
end
# Reminder: You may wish to wait for a particular job status before checking output
def output
find('.js-build-output').text
......
......@@ -40,7 +40,7 @@ module QA
click_allow(:push, 'No one')
end
def allow_devs_and_masters_to_push
def allow_devs_and_maintainers_to_push
click_allow(:push, 'Developers + Maintainers')
end
......@@ -48,7 +48,7 @@ module QA
click_allow(:merge, 'No one')
end
def allow_devs_and_masters_to_merge
def allow_devs_and_maintainers_to_merge
click_allow(:merge, 'Developers + Maintainers')
end
......@@ -75,10 +75,6 @@ module QA
within_element(:"allowed_to_#{action}_dropdown") do
click_on text
wait(reload: false) do
has_css?('.is-active')
end
end
end
end
......
......@@ -92,7 +92,9 @@ module QA
Page::Project::Pipeline::Show.act { go_to_first_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.output).to include(sha1sum)
......
......@@ -7,12 +7,6 @@ module QA
resource.name = 'protected-branch-project'
end
end
given(:location) do
Page::Project::Show.act do
choose_repository_clone_http
repository_location
end
end
before do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
......@@ -26,44 +20,49 @@ module QA
Capybara.execute_script 'localStorage.clear()'
end
scenario 'user is able to protect a branch' do
protected_branch = Factory::Resource::Branch.fabricate! do |resource|
resource.branch_name = branch_name
resource.project = project
resource.allow_to_push = true
resource.protected = true
context 'when developers and maintainers are allowed to push to a protected branch' do
let!(:protected_branch) { create_protected_branch(allow_to_push: true) }
scenario 'user with push rights successfully pushes to the protected branch' do
expect(protected_branch.name).to have_content(branch_name)
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
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(protected_branch.push_allowance).to have_content('Developers + Maintainers')
expect(push.output)
.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
scenario 'users without authorization cannot push to protected branch' do
def create_protected_branch(allow_to_push:)
Factory::Resource::Branch.fabricate! do |resource|
resource.branch_name = branch_name
resource.project = project
resource.allow_to_push = false
resource.allow_to_push = allow_to_push
resource.protected = true
end
end
project.visit!
Git::Repository.perform do |repository|
repository.uri = location.uri
repository.use_default_credentials
repository.act do
clone
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\)/)
def push_new_file(branch)
Factory::Repository::Push.fabricate! do |resource|
resource.project = project
resource.file_name = 'new_file.md'
resource.file_content = '# This is a new file'
resource.commit_message = 'Add new_file.md'
resource.branch_name = branch_name
resource.new_branch = false
end
end
end
......
......@@ -32,6 +32,8 @@ module Support
allow(ENV).to receive(:[]).and_call_original
allow(ENV).to receive(:key?).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)
end
end
......
......@@ -18,7 +18,7 @@ describe Boards::IssuesController do
end
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
it 'returns a not found 404 response' do
......
......@@ -2,7 +2,7 @@ require 'spec_helper'
describe Groups::AvatarsController do
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
group.add_owner(user)
......
......@@ -3,7 +3,7 @@ require 'spec_helper'
describe Import::GitlabProjectsController do
set(:namespace) { create(:namespace) }
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
sign_in(user)
......
......@@ -4,7 +4,7 @@ describe Import::GoogleCodeController do
include ImportSpecHelper
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
sign_in(user)
......
require 'spec_helper'
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
sign_in(user)
......
require 'spec_helper'
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) }
before do
......
......@@ -6,8 +6,8 @@ describe ProjectsController do
let(:project) { create(:project) }
let(:public_project) { create(:project, :public) }
let(:user) { create(:user) }
let(:jpg) { fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg') }
let(:txt) { fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') }
let(:jpg) { fixture_file_upload('spec/fixtures/rails_sample.jpg', 'image/jpg') }
let(:txt) { fixture_file_upload('spec/fixtures/doc_sample.txt', 'text/plain') }
describe 'GET new' do
context 'with an authenticated user' do
......
require 'spec_helper'
describe RegistrationsController do
include TermsHelper
describe '#create' do
let(:user_params) { { user: { name: 'new_user', username: 'new_username', email: 'new@user.com', password: 'Any_password' } } }
......@@ -67,6 +69,25 @@ describe RegistrationsController do
expect(flash[:notice]).to include 'Welcome! You have signed up successfully.'
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
describe '#destroy' do
......
......@@ -6,13 +6,13 @@ shared_examples 'content not cached without revalidation' do
end
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
let(:model) { 'personal_snippet' }
let(:snippet) { create(:personal_snippet, :public) }
let(:jpg) { fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg') }
let(:txt) { fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') }
let(:jpg) { fixture_file_upload('spec/fixtures/rails_sample.jpg', 'image/jpg') }
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
it "returns 401 when the user is not logged in" do
......@@ -205,7 +205,7 @@ describe UploadsController do
end
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
before do
......@@ -314,7 +314,7 @@ describe UploadsController do
end
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 not signed in" do
......@@ -521,7 +521,7 @@ describe UploadsController do
context 'Appearance' 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
it 'responds with status 200' do
......@@ -541,7 +541,7 @@ describe UploadsController do
end
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
it 'responds with status 200' do
......
......@@ -7,7 +7,7 @@ FactoryBot.define do
end
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
# The uniqueness constraint means we can't use the correct OID for all LFS
......
......@@ -130,11 +130,11 @@ FactoryBot.define do
end
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
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
transient do
......
......@@ -94,7 +94,7 @@ feature 'Admin updates settings' do
accept_terms(admin)
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!'
click_button 'Save changes'
end
......
......@@ -47,7 +47,7 @@ describe 'Commits' do
context 'commit status is Ci Build' do
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
before do
......
......@@ -23,8 +23,8 @@ describe 'Merge request < User sees mini pipeline graph', :js do
end
context 'as json' do
let(:artifacts_file1) { fixture_file_upload(Rails.root.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_file1) { fixture_file_upload(File.join('spec/fixtures/banana_sample.gif'), 'image/gif') }
let(:artifacts_file2) { fixture_file_upload(File.join('spec/fixtures/dk.png'), 'image/png') }
before do
create(:ci_build, :success, :trace_artifact, pipeline: pipeline, legacy_artifacts_file: artifacts_file1)
......
......@@ -88,8 +88,7 @@ describe 'Project Jobs Permissions' do
describe 'artifacts page' do
context 'when recent job has artifacts available' do
before do
artifacts = Rails.root.join('spec/fixtures/ci_build_artifacts.zip')
archive = fixture_file_upload(artifacts, 'application/zip')
archive = fixture_file_upload('spec/fixtures/ci_build_artifacts.zip')
job.update_attributes(legacy_artifacts_file: archive)
end
......
......@@ -11,7 +11,7 @@ feature 'Jobs', :clean_gitlab_redis_shared_state do
let(:job2) { create(:ci_build) }
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
before do
......
......@@ -314,8 +314,8 @@ feature 'Pages' do
project: project,
pipeline: pipeline,
ref: 'HEAD',
legacy_artifacts_file: fixture_file_upload(Rails.root.join('spec/fixtures/pages.zip')),
legacy_artifacts_metadata: fixture_file_upload(Rails.root.join('spec/fixtures/pages.zip.meta'))
legacy_artifacts_file: fixture_file_upload(File.join('spec/fixtures/pages.zip')),
legacy_artifacts_metadata: fixture_file_upload(File.join('spec/fixtures/pages.zip.meta'))
)
end
......
......@@ -38,7 +38,7 @@ feature 'Master deletes tag' do
context 'when Gitaly operation_user_delete_tag feature is enabled' do
before do
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
scenario 'shows the error message' do
......@@ -51,7 +51,7 @@ feature 'Master deletes tag' do
context 'when Gitaly operation_user_delete_tag feature is disabled', :skip_gitaly_mock do
before do
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
scenario 'shows the error message' do
......
......@@ -140,7 +140,7 @@ describe 'Signup' do
enforce_terms
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
fill_in 'new_user_name', with: new_user.name
......@@ -148,11 +148,24 @@ describe 'Signup' do
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
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
end
......
......@@ -3,12 +3,10 @@ require 'spec_helper'
describe 'Users > Terms' do
include TermsHelper
let(:user) { create(:user) }
let!(:term) { create(:term, terms: 'By accepting, you promise to be nice!') }
before do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
sign_in(user)
end
it 'shows the terms' do
......@@ -17,102 +15,119 @@ describe 'Users > Terms' do
expect(page).to have_content('By accepting, you promise to be nice!')
end
context 'declining the terms' do
it 'returns the user to the app' do
visit terms_path
it 'does not show buttons to accept, decline or sign out', :aggregate_failures do
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)
expect(user.reload.terms_accepted?).to be(false)
before do
sign_in(user)
end
end
context 'accepting the terms' do
it 'returns the user to the app' do
visit terms_path
context 'declining the terms' do
it 'returns the user to the app' do
visit terms_path
click_button 'Accept terms'
click_button 'Decline and sign out'
expect(page).not_to have_content(term.terms)
expect(user.reload.terms_accepted?).to be(true)
expect(page).not_to have_content(term.terms)
expect(user.reload.terms_accepted?).to be(false)
end
end
end
context 'when the user has already accepted the terms' do
before do
accept_terms(user)
context 'accepting the terms' do
it 'returns the user to the app' do
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
it 'allows the user to continue to the app' do
visit terms_path
context 'when the user has already accepted the terms' do
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
context 'terms were enforced while session is active', :js do
let(:project) { create(:project) }
context 'terms were enforced while session is active', :js do
let(:project) { create(:project) }
before do
project.add_developer(user)
end
before do
project.add_developer(user)
end
it 'redirects to terms and back to where the user was going' do
visit project_path(project)
it 'redirects to terms and back to where the user was going' do
visit project_path(project)
enforce_terms
enforce_terms
within('.nav-sidebar') do
click_link 'Issues'
end
within('.nav-sidebar') do
click_link 'Issues'
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))
end
expect(current_path).to eq(project_issues_path(project))
end
# 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
visit new_project_issue_path(project)
# 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
visit new_project_issue_path(project)
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_title, with: 'Hello world, a new issue'
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(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(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_description').value).to eq("We don't want to lose what the user typed")
end
end
end
context 'when the terms are enforced' do
before do
enforce_terms
end
context 'when the terms are enforced' do
before do
enforce_terms
end
context 'signing out', :js do
it 'allows the user to sign out without a response' do
visit terms_path
context 'signing out', :js do
it 'allows the user to sign out without a response' do
visit terms_path
find('.header-user-dropdown-toggle').click
click_link('Sign out')
find('.header-user-dropdown-toggle').click
click_link('Sign out')
expect(page).to have_content('Sign in')
expect(page).to have_content('Register')
expect(page).to have_content('Sign in')
expect(page).to have_content('Register')
end
end
end
end
......
......@@ -47,9 +47,7 @@ describe EmailsHelper do
describe '#header_logo' do
context 'there is a brand item with a logo' do
it 'returns the brand header logo' do
appearance = create :appearance, header_logo: fixture_file_upload(
Rails.root.join('spec/fixtures/dk.png')
)
appearance = create :appearance, header_logo: fixture_file_upload('spec/fixtures/dk.png')
expect(header_logo).to eq(
%{<img style="height: 50px" src="/uploads/-/system/appearance/header_logo/#{appearance.id}/dk.png" alt="Dk" />}
......
......@@ -4,9 +4,9 @@ describe GroupsHelper do
include ApplicationHelper
describe 'group_icon' do
avatar_file_path = File.join(Rails.root, 'spec', 'fixtures', 'banana_sample.gif')
it 'returns an url for the avatar' do
avatar_file_path = File.join('spec', 'fixtures', 'banana_sample.gif')
group = create(:group)
group.avatar = fixture_file_upload(avatar_file_path)
group.save!
......@@ -17,9 +17,9 @@ describe GroupsHelper do
end
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
avatar_file_path = File.join('spec', 'fixtures', 'banana_sample.gif')
group = create(:group)
group.avatar = fixture_file_upload(avatar_file_path)
group.save!
......
......@@ -110,7 +110,7 @@ describe('Clusters Store', () => {
expect(
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', () => {
setTimeout(done);
});
afterEach(() => {
vm.$store.dispatch('pipelines/stopPipelinePolling');
vm.$store.dispatch('pipelines/clearEtagPoll');
afterEach(done => {
vm.$destroy();
mock.restore();
vm.$store
.dispatch('pipelines/stopPipelinePolling')
.then(() => vm.$store.dispatch('pipelines/clearEtagPoll'))
.then(done)
.catch(done.fail);
});
it('renders pipeline data', () => {
......
......@@ -199,28 +199,39 @@ describe('IDE merge requests actions', () => {
});
it('commits reset mutations and actions', done => {
testAction(
openMergeRequest,
{ projectPath: 'gitlab-org/gitlab-ce', id: '1' },
mockedState,
[
{ type: 'CLEAR_PROJECTS' },
{ type: 'SET_CURRENT_MERGE_REQUEST', payload: '1' },
{ type: 'RESET_OPEN_FILES' },
],
[
{ type: 'pipelines/stopPipelinePolling' },
{ type: 'pipelines/clearEtagPoll' },
{ type: 'pipelines/resetLatestPipeline' },
{ type: 'setCurrentBranchId', payload: '' },
],
done,
);
const commit = jasmine.createSpy();
const dispatch = jasmine.createSpy().and.returnValue(Promise.resolve());
openMergeRequest({ commit, dispatch }, { projectPath: 'gitlab-org/gitlab-ce', id: '1' });
setTimeout(() => {
expect(commit.calls.argsFor(0)).toEqual(['CLEAR_PROJECTS', null, { root: true }]);
expect(commit.calls.argsFor(1)).toEqual(['SET_CURRENT_MERGE_REQUEST', '1', { root: true }]);
expect(commit.calls.argsFor(2)).toEqual(['RESET_OPEN_FILES', null, { root: true }]);
expect(dispatch.calls.argsFor(0)).toEqual([
'pipelines/resetLatestPipeline',
null,
{ root: true },
]);
expect(dispatch.calls.argsFor(1)).toEqual(['setCurrentBranchId', '', { root: true }]);
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', () => {
openMergeRequest(
{ commit() {}, dispatch() {} },
{ commit() {}, dispatch: () => Promise.resolve() },
{ projectPath: 'gitlab-org/gitlab-ce', id: '1' },
);
......
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';
describe('MRWidgetAuthorTime', () => {
describe('MrWidgetAuthorTime', () => {
let vm;
beforeEach(() => {
const Component = Vue.extend(authorTimeComponent);
const Component = Vue.extend(MrWidgetAuthorTime);
vm = mountComponent(Component, {
actionText: 'Merged by',
......@@ -34,7 +34,7 @@ describe('MRWidgetAuthorTime', () => {
});
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');
});
});
......@@ -186,7 +186,7 @@ describe('MRWidgetMerged', () => {
it('should use mergedEvent mergedAt as tooltip title', () => {
expect(
vm.$el.querySelector('time').getAttribute('title'),
vm.$el.querySelector('time').getAttribute('data-original-title'),
).toBe('Jan 24, 2018 1:02pm GMT+0000');
});
});
......@@ -9,24 +9,31 @@ describe Gitlab::Git::Hook do
end
describe "#trigger" do
let(:project) { create(:project, :repository) }
set(:project) { create(:project, :repository) }
let(:repository) { project.repository.raw_repository }
let(:repo_path) { repository.path }
let(:hooks_dir) { File.join(repo_path, 'hooks') }
let(:user) { create(:user) }
let(:gl_id) { Gitlab::GlId.gl_id(user) }
let(:gl_username) { user.username }
def create_hook(name)
FileUtils.mkdir_p(File.join(repo_path, 'hooks'))
File.open(File.join(repo_path, 'hooks', name), 'w', 0755) do |f|
f.write('exit 0')
FileUtils.mkdir_p(hooks_dir)
hook_path = File.join(hooks_dir, name)
File.open(hook_path, 'w', 0755) do |f|
f.write(<<~HOOK)
#!/bin/sh
exit 0
HOOK
end
end
def create_failing_hook(name)
FileUtils.mkdir_p(File.join(repo_path, 'hooks'))
File.open(File.join(repo_path, 'hooks', name), 'w', 0755) do |f|
f.write(<<-HOOK)
FileUtils.mkdir_p(hooks_dir)
hook_path = File.join(hooks_dir, name)
File.open(hook_path, 'w', 0755) do |f|
f.write(<<~HOOK)
#!/bin/sh
echo 'regular message from the hook'
echo 'error message from the hook' 1>&2
echo 'error message from the hook line 2' 1>&2
......@@ -38,7 +45,7 @@ describe Gitlab::Git::Hook do
['pre-receive', 'post-receive', 'update'].each do |hook_name|
context "when triggering a #{hook_name} hook" 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(:env) do
{
......@@ -76,7 +83,7 @@ describe Gitlab::Git::Hook do
status, errors = hook.trigger(gl_id, gl_username, blank, blank, ref)
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
......
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