summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/issue_templates/Feature Flag Roll Out.md1
-rw-r--r--app/assets/javascripts/ide/components/file_row_extra.vue1
-rw-r--r--app/assets/javascripts/mr_notes/init_notes.js4
-rw-r--r--app/assets/javascripts/notes/components/discussion_keyboard_navigator.vue4
-rw-r--r--app/assets/javascripts/vue_shared/components/changed_file_icon.vue9
-rw-r--r--app/assets/stylesheets/framework/flash.scss1
-rw-r--r--app/controllers/application_controller.rb1
-rw-r--r--app/controllers/concerns/confirm_email_warning.rb25
-rw-r--r--app/controllers/confirmations_controller.rb2
-rw-r--r--app/controllers/registrations_controller.rb12
-rw-r--r--app/models/ci/build.rb2
-rw-r--r--app/models/user.rb7
-rw-r--r--app/serializers/deployment_entity.rb1
-rw-r--r--app/serializers/deployment_serializer.rb2
-rw-r--r--app/services/ci/process_pipeline_service.rb4
-rw-r--r--changelogs/unreleased/56130-deployment-date.yml5
-rw-r--r--changelogs/unreleased/61335-fix-file-icon-status.yml5
-rw-r--r--config/initializers/8_devise.rb2
-rw-r--r--doc/administration/integration/plantuml.md4
-rw-r--r--doc/ci/directed_acyclic_graph/index.md4
-rw-r--r--doc/development/documentation/styleguide.md22
-rw-r--r--doc/development/go_guide/index.md26
-rw-r--r--doc/security/rate_limits.md5
-rw-r--r--doc/topics/autodevops/index.md10
-rw-r--r--doc/university/training/end-user/README.md81
-rw-r--r--doc/university/training/topics/bisect.md4
-rw-r--r--doc/university/training/topics/cherry_picking.md6
-rw-r--r--doc/university/training/topics/feature_branching.md4
-rw-r--r--doc/university/training/topics/getting_started.md4
-rw-r--r--doc/university/training/topics/git_add.md4
-rw-r--r--doc/university/training/topics/merge_conflicts.md4
-rw-r--r--doc/university/training/topics/merge_requests.md2
-rw-r--r--doc/university/training/topics/stash.md6
-rw-r--r--doc/university/training/topics/tags.md12
-rw-r--r--doc/university/training/topics/unstage.md2
-rw-r--r--doc/user/admin_area/settings/img/rate_limits_on_raw_endpoints.pngbin0 -> 58254 bytes
-rw-r--r--doc/user/admin_area/settings/rate_limits_on_raw_endpoints.md20
-rw-r--r--doc/user/analytics/productivity_analytics.md69
-rw-r--r--doc/user/asciidoc.md4
-rw-r--r--doc/user/profile/preferences.md10
-rw-r--r--doc/user/project/clusters/index.md3
-rw-r--r--locale/gitlab.pot9
-rw-r--r--spec/controllers/concerns/confirm_email_warning_spec.rb98
-rw-r--r--spec/controllers/registrations_controller_spec.rb31
-rw-r--r--spec/features/boards/multiple_boards_spec.rb15
-rw-r--r--spec/features/invites_spec.rb72
-rw-r--r--spec/features/projects/files/user_browses_a_tree_with_a_folder_containing_only_a_folder_spec.rb7
-rw-r--r--spec/features/users/login_spec.rb35
-rw-r--r--spec/features/users/signup_spec.rb49
-rw-r--r--spec/fixtures/api/schemas/deployment.json2
-rw-r--r--spec/frontend/notes/components/discussion_keyboard_navigator_spec.js27
-rw-r--r--spec/frontend/vue_shared/components/changed_file_icon_spec.js123
-rw-r--r--spec/javascripts/vue_shared/components/changed_file_icon_spec.js63
-rw-r--r--spec/serializers/deployment_entity_spec.rb4
-rw-r--r--spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb144
55 files changed, 751 insertions, 322 deletions
diff --git a/.gitlab/issue_templates/Feature Flag Roll Out.md b/.gitlab/issue_templates/Feature Flag Roll Out.md
index b7db5a33faf..0cac769bd55 100644
--- a/.gitlab/issue_templates/Feature Flag Roll Out.md
+++ b/.gitlab/issue_templates/Feature Flag Roll Out.md
@@ -39,5 +39,6 @@ If applicable, any groups/projects that are happy to have this feature turned on
- [ ] Cross post chatops slack command to `#support_gitlab-com` and in your team channel
- [ ] Announce on the issue that the flag has been enabled
- [ ] Remove feature flag and add changelog entry
+- [ ] After the flag removal is deployed, [clean up the feature flag](https://docs.gitlab.com/ee/development/feature_flags/controls.html#cleaning-up) by running chatops command in `#production` channel
/label ~"feature flag"
diff --git a/app/assets/javascripts/ide/components/file_row_extra.vue b/app/assets/javascripts/ide/components/file_row_extra.vue
index 80a6ab9598a..7254c50a568 100644
--- a/app/assets/javascripts/ide/components/file_row_extra.vue
+++ b/app/assets/javascripts/ide/components/file_row_extra.vue
@@ -87,7 +87,6 @@ export default {
:file="file"
:show-tooltip="true"
:show-staged-icon="true"
- :force-modified-icon="true"
/>
<new-dropdown
:type="file.type"
diff --git a/app/assets/javascripts/mr_notes/init_notes.js b/app/assets/javascripts/mr_notes/init_notes.js
index 8caac68e0d4..622db360d1f 100644
--- a/app/assets/javascripts/mr_notes/init_notes.js
+++ b/app/assets/javascripts/mr_notes/init_notes.js
@@ -59,6 +59,10 @@ export default () => {
render(createElement) {
const isDiffView = this.activeTab === 'diffs';
+ // NOTE: Even though `discussionKeyboardNavigator` is added to the `notes-app`,
+ // it adds a global key listener so it works on the diffs tab as well.
+ // If we create a single Vue app for all of the MR tabs, we should move this
+ // up the tree, to the root.
return createElement(discussionKeyboardNavigator, { props: { isDiffView } }, [
createElement('notes-app', {
props: {
diff --git a/app/assets/javascripts/notes/components/discussion_keyboard_navigator.vue b/app/assets/javascripts/notes/components/discussion_keyboard_navigator.vue
index 5fc2b6ba04c..7fbfe8eebb2 100644
--- a/app/assets/javascripts/notes/components/discussion_keyboard_navigator.vue
+++ b/app/assets/javascripts/notes/components/discussion_keyboard_navigator.vue
@@ -25,6 +25,10 @@ export default {
Mousetrap.bind('n', () => this.jumpToNextDiscussion());
Mousetrap.bind('p', () => this.jumpToPreviousDiscussion());
},
+ beforeDestroy() {
+ Mousetrap.unbind('n');
+ Mousetrap.unbind('p');
+ },
methods: {
...mapActions(['expandDiscussion']),
jumpToNextDiscussion() {
diff --git a/app/assets/javascripts/vue_shared/components/changed_file_icon.vue b/app/assets/javascripts/vue_shared/components/changed_file_icon.vue
index cdf2d1020ba..beb2ac09992 100644
--- a/app/assets/javascripts/vue_shared/components/changed_file_icon.vue
+++ b/app/assets/javascripts/vue_shared/components/changed_file_icon.vue
@@ -26,11 +26,6 @@ export default {
required: false,
default: false,
},
- forceModifiedIcon: {
- type: Boolean,
- required: false,
- default: false,
- },
size: {
type: Number,
required: false,
@@ -48,8 +43,6 @@ export default {
// eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
const suffix = !this.file.changed && this.file.staged && !this.showStagedIcon ? '-solid' : '';
- if (this.forceModifiedIcon) return `file-modified${suffix}`;
-
return `${getCommitIconMap(this.file).icon}${suffix}`;
},
changedIconClass() {
@@ -88,7 +81,7 @@ export default {
v-gl-tooltip.right
:title="tooltipTitle"
:class="{ 'ml-auto': isCentered }"
- class="file-changed-icon"
+ class="file-changed-icon d-inline-block"
>
<icon v-if="showIcon" :name="changedIcon" :size="size" :css-classes="changedIconClass" />
</span>
diff --git a/app/assets/stylesheets/framework/flash.scss b/app/assets/stylesheets/framework/flash.scss
index e3dd127366d..96f6d02a68f 100644
--- a/app/assets/stylesheets/framework/flash.scss
+++ b/app/assets/stylesheets/framework/flash.scss
@@ -43,6 +43,7 @@
@extend .alert;
background-color: $orange-100;
color: $orange-900;
+ cursor: default;
margin: 0;
}
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 5e65084a110..af6644b8fcc 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -12,6 +12,7 @@ class ApplicationController < ActionController::Base
include EnforcesTwoFactorAuthentication
include WithPerformanceBar
include SessionlessAuthentication
+ include ConfirmEmailWarning
before_action :authenticate_user!
before_action :enforce_terms!, if: :should_enforce_terms?
diff --git a/app/controllers/concerns/confirm_email_warning.rb b/app/controllers/concerns/confirm_email_warning.rb
new file mode 100644
index 00000000000..5a4b5897a4f
--- /dev/null
+++ b/app/controllers/concerns/confirm_email_warning.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module ConfirmEmailWarning
+ extend ActiveSupport::Concern
+
+ included do
+ before_action :set_confirm_warning, if: -> { Feature.enabled?(:soft_email_confirmation) }
+ end
+
+ protected
+
+ def set_confirm_warning
+ return unless current_user
+ return if current_user.confirmed?
+ return if peek_request? || json_request? || !request.get?
+
+ email = current_user.unconfirmed_email || current_user.email
+
+ flash.now[:warning] = _("Please check your email (%{email}) to verify that you own this address. Didn't receive it? %{resend_link}. Wrong email address? %{update_link}.").html_safe % {
+ email: email,
+ resend_link: view_context.link_to(_('Resend it'), user_confirmation_path(user: { email: email }), method: :post),
+ update_link: view_context.link_to(_('Update it'), profile_path)
+ }
+ end
+end
diff --git a/app/controllers/confirmations_controller.rb b/app/controllers/confirmations_controller.rb
index 2ae500a2fdf..b192189ba3c 100644
--- a/app/controllers/confirmations_controller.rb
+++ b/app/controllers/confirmations_controller.rb
@@ -11,7 +11,7 @@ class ConfirmationsController < Devise::ConfirmationsController
protected
def after_resending_confirmation_instructions_path_for(resource)
- users_almost_there_path
+ Feature.enabled?(:soft_email_confirmation) ? stored_location_for(resource) || dashboard_projects_path : users_almost_there_path
end
def after_confirmation_path_for(resource_name, resource)
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb
index db10515c0b4..e773ec09924 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -69,12 +69,12 @@ class RegistrationsController < Devise::RegistrationsController
def after_sign_up_path_for(user)
Gitlab::AppLogger.info(user_created_message(confirmed: user.confirmed?))
- user.confirmed? ? stored_location_for(user) || dashboard_projects_path : users_almost_there_path
+ confirmed_or_unconfirmed_access_allowed(user) ? stored_location_or_dashboard(user) : users_almost_there_path
end
def after_inactive_sign_up_path_for(resource)
Gitlab::AppLogger.info(user_created_message)
- users_almost_there_path
+ Feature.enabled?(:soft_email_confirmation) ? dashboard_projects_path : users_almost_there_path
end
private
@@ -135,4 +135,12 @@ class RegistrationsController < Devise::RegistrationsController
def terms_accepted?
Gitlab::Utils.to_boolean(params[:terms_opt_in])
end
+
+ def confirmed_or_unconfirmed_access_allowed(user)
+ user.confirmed? || Feature.enabled?(:soft_email_confirmation)
+ end
+
+ def stored_location_or_dashboard(user)
+ stored_location_for(user) || dashboard_projects_path
+ end
end
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index f705e67121f..3c0efca31db 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -716,7 +716,7 @@ module Ci
depended_jobs = depends_on_builds
# find all jobs that are needed
- if Feature.enabled?(:ci_dag_support, project) && needs.exists?
+ if Feature.enabled?(:ci_dag_support, project, default_enabled: true) && needs.exists?
depended_jobs = depended_jobs.where(name: needs.select(:name))
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 374e00987c5..6131a8dc710 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -1507,6 +1507,13 @@ class User < ApplicationRecord
super
end
+ # override from Devise::Confirmable
+ def confirmation_period_valid?
+ return false if Feature.disabled?(:soft_email_confirmation)
+
+ super
+ end
+
private
def default_private_profile_to_false
diff --git a/app/serializers/deployment_entity.rb b/app/serializers/deployment_entity.rb
index 943c707218d..6e91317eb20 100644
--- a/app/serializers/deployment_entity.rb
+++ b/app/serializers/deployment_entity.rb
@@ -18,6 +18,7 @@ class DeploymentEntity < Grape::Entity
end
expose :created_at
+ expose :finished_at
expose :tag
expose :last?
expose :user, using: UserEntity
diff --git a/app/serializers/deployment_serializer.rb b/app/serializers/deployment_serializer.rb
index 04db6b88489..3fd3e1b9cc8 100644
--- a/app/serializers/deployment_serializer.rb
+++ b/app/serializers/deployment_serializer.rb
@@ -4,7 +4,7 @@ class DeploymentSerializer < BaseSerializer
entity DeploymentEntity
def represent_concise(resource, opts = {})
- opts[:only] = [:iid, :id, :sha, :created_at, :tag, :last?, :id, ref: [:name]]
+ opts[:only] = [:iid, :id, :sha, :created_at, :finished_at, :tag, :last?, :id, ref: [:name]]
represent(resource, opts)
end
end
diff --git a/app/services/ci/process_pipeline_service.rb b/app/services/ci/process_pipeline_service.rb
index f4bd457ebc6..3b145a65d79 100644
--- a/app/services/ci/process_pipeline_service.rb
+++ b/app/services/ci/process_pipeline_service.rb
@@ -40,7 +40,7 @@ module Ci
def process_builds_with_needs(trigger_build_ids)
return false unless trigger_build_ids.present?
- return false unless Feature.enabled?(:ci_dag_support, project)
+ return false unless Feature.enabled?(:ci_dag_support, project, default_enabled: true)
# we find processables that are dependent:
# 1. because of current dependency,
@@ -96,7 +96,7 @@ module Ci
end
def created_processables_without_needs
- if Feature.enabled?(:ci_dag_support, project)
+ if Feature.enabled?(:ci_dag_support, project, default_enabled: true)
pipeline.processables.created.without_needs
else
pipeline.processables.created
diff --git a/changelogs/unreleased/56130-deployment-date.yml b/changelogs/unreleased/56130-deployment-date.yml
new file mode 100644
index 00000000000..7d1e84bbaa4
--- /dev/null
+++ b/changelogs/unreleased/56130-deployment-date.yml
@@ -0,0 +1,5 @@
+---
+title: Add finished_at to the internal API Deployment entity
+merge_request: 31808
+author:
+type: other
diff --git a/changelogs/unreleased/61335-fix-file-icon-status.yml b/changelogs/unreleased/61335-fix-file-icon-status.yml
new file mode 100644
index 00000000000..d524d91b246
--- /dev/null
+++ b/changelogs/unreleased/61335-fix-file-icon-status.yml
@@ -0,0 +1,5 @@
+---
+title: Fix IDE new files icon in tree
+merge_request: 31560
+author:
+type: fixed
diff --git a/config/initializers/8_devise.rb b/config/initializers/8_devise.rb
index 3dd12c7e64d..8ef9ff6b7fc 100644
--- a/config/initializers/8_devise.rb
+++ b/config/initializers/8_devise.rb
@@ -81,7 +81,7 @@ Devise.setup do |config|
# You can use this to let your user access some features of your application
# without confirming the account, but blocking it after a certain period
# (ie 2 days).
- # config.allow_unconfirmed_access_for = 2.days
+ config.allow_unconfirmed_access_for = 30.days
# Defines which key will be used when confirming an account
# config.confirmation_keys = [ :email ]
diff --git a/doc/administration/integration/plantuml.md b/doc/administration/integration/plantuml.md
index c2ac063ce37..16a193550a1 100644
--- a/doc/administration/integration/plantuml.md
+++ b/doc/administration/integration/plantuml.md
@@ -72,12 +72,12 @@ our AsciiDoc snippets, wikis and repos using delimited blocks:
- **Markdown**
- ````markdown
+ ~~~markdown
```plantuml
Bob -> Alice : hello
Alice -> Bob : Go Away
```
- ````
+ ~~~
- **AsciiDoc**
diff --git a/doc/ci/directed_acyclic_graph/index.md b/doc/ci/directed_acyclic_graph/index.md
index 2f000719c04..e54be9f3bd9 100644
--- a/doc/ci/directed_acyclic_graph/index.md
+++ b/doc/ci/directed_acyclic_graph/index.md
@@ -72,5 +72,5 @@ giving your powerful options for parallelization within your pipeline.
A directed acyclic graph is a complicated feature, and as of the initial MVC there
are certain use cases that you may need to work around. For more information:
- - [`needs` requirements and limitations](../yaml/README.md#requirements-and-limitations).
- - Related epic [gitlab-org#1716](https://gitlab.com/groups/gitlab-org/-/epics/1716).
+- [`needs` requirements and limitations](../yaml/README.md#requirements-and-limitations).
+- Related epic [gitlab-org#1716](https://gitlab.com/groups/gitlab-org/-/epics/1716).
diff --git a/doc/development/documentation/styleguide.md b/doc/development/documentation/styleguide.md
index 680f2cd13c2..c1e3eb9680b 100644
--- a/doc/development/documentation/styleguide.md
+++ b/doc/development/documentation/styleguide.md
@@ -655,15 +655,16 @@ nicely on different mobile devices.
## Code blocks
-- Always wrap code added to a sentence in inline code blocks (``` ` ```).
+- Always wrap code added to a sentence in inline code blocks (`` ` ``).
E.g., `.gitlab-ci.yml`, `git add .`, `CODEOWNERS`, `only: master`.
File names, commands, entries, and anything that refers to code should be added to code blocks.
To make things easier for the user, always add a full code block for things that can be
useful to copy and paste, as they can easily do it with the button on code blocks.
+- Add a blank line above and below code blocks.
- For regular code blocks, always use a highlighting class corresponding to the
language for better readability. Examples:
- ````md
+ ~~~md
```ruby
Ruby code
```
@@ -673,16 +674,17 @@ nicely on different mobile devices.
```
```md
- Markdown code
+ [Markdown code example](example.md)
```
```text
- Code for which no specific highlighting class is available.
+ Code or text for which no specific highlighting class is available.
```
- ````
+ ~~~
-- To display raw markdown instead of rendered markdown, use four backticks on their own lines around the
- markdown to display. See [example](https://gitlab.com/gitlab-org/gitlab-ce/blob/8c1991b9bb7e3b8d606481fdea316d633cfa5eb7/doc/development/documentation/styleguide.md#L275-287).
+- To display raw markdown instead of rendered markdown, you can use triple backticks
+ with `md`, like the `Markdown code` example above, unless you want to include triple
+ backticks in the code block as well. In that case, use triple tildes (`~~~`) instead.
- For a complete reference on code blocks, check the [Kramdown guide](https://about.gitlab.com/handbook/product/technical-writing/markdown-guide/#code-blocks).
## Alert boxes
@@ -1024,7 +1026,7 @@ on this document. Further explanation is given below.
The following can be used as a template to get started:
-````md
+~~~md
## Descriptive title
One or two sentence description of what endpoint does.
@@ -1052,7 +1054,7 @@ Example response:
}
]
```
-````
+~~~
### Fake tokens
@@ -1080,7 +1082,7 @@ You can use the following fake tokens as examples.
### Method description
Use the following table headers to describe the methods. Attributes should
-always be in code blocks using backticks (``` ` ```).
+always be in code blocks using backticks (`` ` ``).
```md
| Attribute | Type | Required | Description |
diff --git a/doc/development/go_guide/index.md b/doc/development/go_guide/index.md
index 9f0ac8cc753..83444093f9c 100644
--- a/doc/development/go_guide/index.md
+++ b/doc/development/go_guide/index.md
@@ -107,6 +107,32 @@ Modules](https://github.com/golang/go/wiki/Modules). It provides a way to
define and lock dependencies for reproducible builds. It should be used
whenever possible.
+When Go Modules are in use, there should not be a `vendor/` directory. Instead,
+Go will automatically download dependencies when they are needed to build the
+project. This is in line with how dependencies are handled with Bundler in Ruby
+projects, and makes merge requests easier to review.
+
+In some cases, such as building a Go project for it to act as a dependency of a
+CI run for another project, removing the `vendor/` directory means the code must
+be downloaded repeatedly, which can lead to intermittent problems due to rate
+limiting or network failures. In these circumstances, you should cache the
+downloaded code between runs with a `.gitlab-ci.yml` snippet like this:
+
+```yaml
+.go-cache:
+ variables:
+ GOPATH: $CI_PROJECT_DIR/.go
+ before_script:
+ - mkdir -p .go
+ cache:
+ paths:
+ - .go/pkg/mod/
+
+test:
+ extends: .go-cache
+ # ...
+```
+
There was a [bug on modules
checksums](https://github.com/golang/go/issues/29278) in Go < v1.11.4, so make
sure to use at least this version to avoid `checksum mismatch` errors.
diff --git a/doc/security/rate_limits.md b/doc/security/rate_limits.md
index 0e5bdcd9c79..c80f2f264b2 100644
--- a/doc/security/rate_limits.md
+++ b/doc/security/rate_limits.md
@@ -22,11 +22,12 @@ similarly mitigated by a rate limit.
## Admin Area settings
-See
-[User and IP rate limits](../user/admin_area/settings/user_and_ip_rate_limits.md).
+- [User and IP rate limits](../user/admin_area/settings/user_and_ip_rate_limits.md).
+- [Rate limits on raw endpoints](../user/admin_area/settings/rate_limits_on_raw_endpoints.md)
## Rack Attack initializer
This method of rate limiting is cumbersome, but has some advantages. It allows
throttling of specific paths, and is also integrated into Git and container
registry requests. See [Rack Attack initializer](rack_attack.md).
+
diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md
index 95220d6364c..9c1258fa1aa 100644
--- a/doc/topics/autodevops/index.md
+++ b/doc/topics/autodevops/index.md
@@ -816,7 +816,7 @@ To configure your application variables:
1. Create a CI Variable, ensuring the key is prefixed with
`K8S_SECRET_`. For example, you can create a variable with key
-`K8S_SECRET_RAILS_MASTER_KEY`.
+ `K8S_SECRET_RAILS_MASTER_KEY`.
1. Run an Auto Devops pipeline either by manually creating a new
pipeline or by pushing a code change to GitLab.
@@ -1017,10 +1017,10 @@ Everything behaves the same way, except:
- It's enabled by setting the `INCREMENTAL_ROLLOUT_MODE` variable to `timed`.
- Instead of the standard `production` job, the following jobs with a 5 minute delay between each are created:
- 1. `timed rollout 10%`
- 1. `timed rollout 25%`
- 1. `timed rollout 50%`
- 1. `timed rollout 100%`
+ 1. `timed rollout 10%`
+ 1. `timed rollout 25%`
+ 1. `timed rollout 50%`
+ 1. `timed rollout 100%`
## Currently supported languages
diff --git a/doc/university/training/end-user/README.md b/doc/university/training/end-user/README.md
index 423ba1cfbd7..1218465c87a 100644
--- a/doc/university/training/end-user/README.md
+++ b/doc/university/training/end-user/README.md
@@ -9,12 +9,8 @@ which can be found at [End User Slides](https://gitlab-org.gitlab.io/end-user-tr
through it's [RevealJS](https://gitlab.com/gitlab-org/end-user-training-slides)
project.
----
-
## Git Intro
----
-
### What is a Version Control System (VCS)
- Records changes to a file
@@ -22,8 +18,6 @@ project.
- Disaster Recovery
- Types of VCS: Local, Centralized and Distributed
----
-
### Short Story of Git
- 1991-2002: The Linux kernel was being maintained by sharing archived files
@@ -31,8 +25,6 @@ project.
- 2002: The Linux kernel project began using a DVCS called BitKeeper
- 2005: BitKeeper revoked the free-of-charge status and Git was created
----
-
### What is Git
- Distributed Version Control System
@@ -42,8 +34,6 @@ project.
- Disaster recovery friendly
- Open Source
----
-
### Getting Help
- Use the tools at your disposal when you get stuck.
@@ -51,14 +41,10 @@ project.
- Use Google (i.e. StackOverflow, Google groups)
- Read documentation at <https://git-scm.com>
----
-
## Git Setup
Workshop Time!
----
-
### Setup
- Windows: Install 'Git for Windows'
@@ -69,8 +55,6 @@ Workshop Time!
- Debian: `sudo apt-get install git-all`
- Red Hat `sudo yum install git-all`
----
-
### Configure
- One-time configuration of the Git client:
@@ -91,16 +75,12 @@ git config --global --list
- You might want or be required to use an SSH key.
- Instructions: [SSH](http://doc.gitlab.com/ce/ssh/README.html)
----
-
### Workspace
- Choose a directory on you machine easy to access
- Create a workspace or development directory
- This is where we'll be working and adding content
----
-
```bash
mkdir ~/development
cd ~/development
@@ -111,12 +91,8 @@ mkdir ~/workspace
cd ~/workspace
```
----
-
## Git Basics
----
-
### Git Workflow
- Untracked files
@@ -128,8 +104,6 @@ cd ~/workspace
- Upstream
- Hosted repository on a shared server
----
-
### GitLab
- GitLab is an application to code, test and deploy.
@@ -137,8 +111,6 @@ cd ~/workspace
issue tracking, Merge Requests, and other features.
- The hosted version of GitLab is gitlab.com
----
-
### New Project
- Sign in into your gitlab.com account
@@ -146,8 +118,6 @@ cd ~/workspace
- Choose to import from 'Any Repo by URL' and use <https://gitlab.com/gitlab-org/training-examples.git>
- On your machine clone the `training-examples` project
----
-
### Git and GitLab basics
1. Edit `edit_this_file.rb` in `training-examples`
@@ -158,8 +128,6 @@ cd ~/workspace
1. Push the commit to the remote
1. View the git log
----
-
```shell
# Edit `edit_this_file.rb`
git status
@@ -170,8 +138,6 @@ git push origin master
git log
```
----
-
### Feature Branching
1. Create a new feature branch called `squash_some_bugs`
@@ -179,8 +145,6 @@ git log
1. Commit
1. Push
----
-
```shell
git checkout -b squash_some_bugs
# Edit `bugs.rb`
@@ -190,14 +154,8 @@ git commit -m 'Fix some buggy code'
git push origin squash_some_bugs
```
----
-
## Merge Request
----
-
-### Merge requests
-
- When you want feedback create a merge request
- Target is the ‘default’ branch (usually master)
- Assign or mention the person you would like to review
@@ -206,8 +164,6 @@ git push origin squash_some_bugs
- Anyone can comment, not just the assignee
- Push corrections to the same branch
----
-
### Merge request example
- Create your first merge request
@@ -216,8 +172,6 @@ git push origin squash_some_bugs
- Push a new commit to the same branch
- Review the changes again and notice the update
----
-
### Feedback and Collaboration
- Merge requests are a time for feedback and collaboration
@@ -230,24 +184,17 @@ git push origin squash_some_bugs
---
-- Review the Thoughtbot code-review guide for suggestions to follow when reviewing merge requests:[Thoughtbot](https://github.com/thoughtbot/guides/tree/master/code-review)
+- Review the Thoughtbot code-review guide for suggestions to follow when reviewing merge requests:
+ [Thoughtbot](https://github.com/thoughtbot/guides/tree/master/code-review)
- See GitLab merge requests for examples: [Merge Requests](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests)
----
-
## Merge Conflicts
----
-
-### Merge Conflicts
-
- Happen often
- Learning to fix conflicts is hard
- Practice makes perfect
- Force push after fixing conflicts. Be careful!
----
-
### Example Plan
1. Checkout a new branch and edit conflicts.rb. Add 'Line4' and 'Line5'.
@@ -261,8 +208,6 @@ git push origin squash_some_bugs
1. Force push the changes
1. Finally continue with the Merge Request
----
-
### Example 1/2
```sh
@@ -282,8 +227,6 @@ git commit -am "add line6 and line7"
git push origin master
```
----
-
### Example 2/2
Create a merge request on the GitLab web UI. You'll see a conflict warning.
@@ -305,8 +248,6 @@ git rebase --continue
git push origin conflicts_branch -f
```
----
-
### Notes
- When to use `git merge` and when to use `git rebase`
@@ -314,12 +255,8 @@ git push origin conflicts_branch -f
- Merge when bringing changes from feature to master
- Reference: <https://www.atlassian.com/git/tutorials/merging-vs-rebasing/>
----
-
## Revert and Unstage
----
-
### Unstage
To remove files from stage use reset HEAD. Where HEAD is the last commit of the current branch:
@@ -347,8 +284,6 @@ If we want to remove a file from the repository but keep it on disk, say we forg
git rm <filename> --cache
```
----
-
### Undo Commits
Undo last commit putting everything back into the staging area:
@@ -377,8 +312,6 @@ git reset --hard HEAD^^
Don't reset after pushing
----
-
### Reset Workflow
1. Edit file again 'edit_this_file.rb'
@@ -392,8 +325,6 @@ Don't reset after pushing
1. Pull for updates
1. Push changes
----
-
```sh
# Change file edit_this_file.rb
git status
@@ -407,8 +338,6 @@ git pull origin master
git push origin master
```
----
-
### git revert vs git reset
Reset removes the commit while revert removes the changes but leaves the commit
@@ -425,16 +354,10 @@ git revert <rev commit hash>
# reverted commit is back (new commit created again)
```
----
-
## Questions
----
-
## Instructor Notes
----
-
### Version Control
- Local VCS was used with a filesystem or a simple db.
diff --git a/doc/university/training/topics/bisect.md b/doc/university/training/topics/bisect.md
index 4178afa2086..24dc670d9d5 100644
--- a/doc/university/training/topics/bisect.md
+++ b/doc/university/training/topics/bisect.md
@@ -4,13 +4,11 @@ comments: false
# Bisect
-## Bisect
-
- Find a commit that introduced a bug
- Works through a process of elimination
- Specify a known good and bad revision to begin
-## Bisect
+## Bisect sample workflow
1. Start the bisect process
1. Enter the bad revision (usually latest commit)
diff --git a/doc/university/training/topics/cherry_picking.md b/doc/university/training/topics/cherry_picking.md
index fa0cb5fe6a4..f5bcdfcbf12 100644
--- a/doc/university/training/topics/cherry_picking.md
+++ b/doc/university/training/topics/cherry_picking.md
@@ -4,13 +4,11 @@ comments: false
# Cherry Pick
-## Cherry Pick
-
- Given an existing commit on one branch, apply the change to another branch
- Useful for backporting bug fixes to previous release branches
- Make the commit on the master branch and pick in to stable
-## Cherry Pick
+## Cherry Pick sample workflow
1. Check out a new 'stable' branch from 'master'
1. Change back to 'master'
@@ -19,8 +17,6 @@ comments: false
1. Check out the 'stable' branch
1. Cherry pick the commit using the SHA obtained earlier
-## Commands
-
```bash
git checkout master
git checkout -b stable
diff --git a/doc/university/training/topics/feature_branching.md b/doc/university/training/topics/feature_branching.md
index d2efe634533..f530389d4da 100644
--- a/doc/university/training/topics/feature_branching.md
+++ b/doc/university/training/topics/feature_branching.md
@@ -11,15 +11,13 @@ comments: false
- Push branches to the server frequently
- Hint: This is a cheap backup for your work-in-progress code
-## Feature branching
+## Feature branching sample workflow
1. Create a new feature branch called 'squash_some_bugs'
1. Edit '`bugs.rb`' and remove all the bugs.
1. Commit
1. Push
-## Commands
-
```sh
git checkout -b squash_some_bugs
# Edit `bugs.rb`
diff --git a/doc/university/training/topics/getting_started.md b/doc/university/training/topics/getting_started.md
index e8ff7916590..3fadb58e804 100644
--- a/doc/university/training/topics/getting_started.md
+++ b/doc/university/training/topics/getting_started.md
@@ -35,8 +35,6 @@ comments: false
1. Create a '`Workspace`' directory in your home directory.
1. Clone the '`training-examples`' project.
-## Commands
-
```sh
mkdir ~/workspace
cd ~/workspace
@@ -69,8 +67,6 @@ Modified files that have been marked to go in the next commit.
1. Push the commit to the remote
1. View the git log
-## Commands
-
```sh
# Edit `edit_this_file.rb`
git status
diff --git a/doc/university/training/topics/git_add.md b/doc/university/training/topics/git_add.md
index 7152fc2030b..0c9a50bb5e1 100644
--- a/doc/university/training/topics/git_add.md
+++ b/doc/university/training/topics/git_add.md
@@ -4,8 +4,6 @@ comments: false
# Git Add
-## Git Add
-
Adds content to the index or staging area.
- Adds a list of file:
@@ -20,8 +18,6 @@ Adds content to the index or staging area.
git add -A
```
-## Git add continued
-
- Add all text files in current dir:
```bash
diff --git a/doc/university/training/topics/merge_conflicts.md b/doc/university/training/topics/merge_conflicts.md
index dd235fe3a81..97bb038f405 100644
--- a/doc/university/training/topics/merge_conflicts.md
+++ b/doc/university/training/topics/merge_conflicts.md
@@ -9,7 +9,7 @@ comments: false
- Practice makes perfect
- Force push after fixing conflicts. Be careful!
-## Merge conflicts
+## Merge conflicts sample workflow
1. Checkout a new branch and edit `conflicts.rb`. Add 'Line4' and 'Line5'.
1. Commit and push.
@@ -22,8 +22,6 @@ comments: false
1. Force push the changes.
1. Finally continue with the Merge Request.
-## Commands
-
```sh
git checkout -b conflicts_branch
diff --git a/doc/university/training/topics/merge_requests.md b/doc/university/training/topics/merge_requests.md
index b5bbe7b2e1e..656871ae5b2 100644
--- a/doc/university/training/topics/merge_requests.md
+++ b/doc/university/training/topics/merge_requests.md
@@ -30,8 +30,6 @@ comments: false
- Be as receptive as possible
- Feedback is about the best code, not the person. You are not your code
-## Feedback and Collaboration
-
Review the Thoughtbot code-review guide for suggestions to follow when reviewing merge requests:
[https://github.com/thoughtbot/guides/tree/master/code-review](https://github.com/thoughtbot/guides/tree/master/code-review)
diff --git a/doc/university/training/topics/stash.md b/doc/university/training/topics/stash.md
index 21abad88cfa..d3e63db0c6a 100644
--- a/doc/university/training/topics/stash.md
+++ b/doc/university/training/topics/stash.md
@@ -25,7 +25,7 @@ and we need to change to a different branch.
git stash apply stash@{3}
```
-- Every time we save a stash it gets stacked so by using list we can see all our
+- Every time we save a stash it gets stacked so by using `list` we can see all our
stashes.
```sh
@@ -54,7 +54,7 @@ and we need to change to a different branch.
- If we meet conflicts we need to either reset or commit our changes.
- Conflicts through `pop` will not drop a stash afterwards.
-## Git Stash
+## Git Stash sample workflow
1. Modify a file
1. Stage file
@@ -64,8 +64,6 @@ and we need to change to a different branch.
1. Apply with pop
1. View list to confirm changes
-## Commands
-
```sh
# Modify edit_this_file.rb file
git add .
diff --git a/doc/university/training/topics/tags.md b/doc/university/training/topics/tags.md
index cdbb8a2da7c..631b93cc384 100644
--- a/doc/university/training/topics/tags.md
+++ b/doc/university/training/topics/tags.md
@@ -11,18 +11,12 @@ type: reference
- Many projects combine an annotated release tag with a stable branch
- Consider setting deployment/release tags automatically
-# Tags
+## Tags sample workflow
- Create a lightweight tag
- Create an annotated tag
- Push the tags to the remote repository
-**Additional resources**
-
-<https://git-scm.com/book/en/Git-Basics-Tagging>
-
-# Commands
-
```sh
git checkout master
@@ -36,6 +30,10 @@ git tag
git push origin --tags
```
+**Additional resources**
+
+<https://git-scm.com/book/en/Git-Basics-Tagging>
+
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
diff --git a/doc/university/training/topics/unstage.md b/doc/university/training/topics/unstage.md
index fa1f63f9ec4..d7482bf2bd5 100644
--- a/doc/university/training/topics/unstage.md
+++ b/doc/university/training/topics/unstage.md
@@ -4,8 +4,6 @@ comments: false
# Unstage
-## Unstage
-
- To remove files from stage use reset HEAD where HEAD is the last commit of the current branch. This will unstage the file but maintain the modifications.
```bash
diff --git a/doc/user/admin_area/settings/img/rate_limits_on_raw_endpoints.png b/doc/user/admin_area/settings/img/rate_limits_on_raw_endpoints.png
new file mode 100644
index 00000000000..c32eb93c8a8
--- /dev/null
+++ b/doc/user/admin_area/settings/img/rate_limits_on_raw_endpoints.png
Binary files differ
diff --git a/doc/user/admin_area/settings/rate_limits_on_raw_endpoints.md b/doc/user/admin_area/settings/rate_limits_on_raw_endpoints.md
new file mode 100644
index 00000000000..b2d56be154b
--- /dev/null
+++ b/doc/user/admin_area/settings/rate_limits_on_raw_endpoints.md
@@ -0,0 +1,20 @@
+---
+type: reference
+---
+
+# Rate limits on raw endpoints **(CORE ONLY)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/30829) in GitLab 12.2.
+
+This setting allows you to rate limit the requests to raw endpoints, defaults to `300` requests per minute.
+It can be modified in **Admin Area > Network > Performance Optimization**.
+
+For example, requests over `300` per minute to `https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/controllers/application_controller.rb` will be blocked.
+
+![Rate limits on raw endpoints](img/rate_limits_on_raw_endpoints.png)
+
+This limit is:
+
+- Applied independently per project, per commit and per file path.
+- Not applied per IP address.
+- Active by default. To disable, set the option to `0`.
diff --git a/doc/user/analytics/productivity_analytics.md b/doc/user/analytics/productivity_analytics.md
deleted file mode 100644
index db3e37bd0fb..00000000000
--- a/doc/user/analytics/productivity_analytics.md
+++ /dev/null
@@ -1,69 +0,0 @@
-# Productivity Analytics **(PREMIUM)**
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/12079) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.2 (enabled by feature flags `analytics` and `productivity_analytics`).
-
-Track development velocity with Productivity Analytics.
-
-For many companies, the development cycle is a blackbox and getting an estimate of how
-long, on average, it takes to deliver features is an enormous endeavor.
-
-While [Cycle Analytics](../project/cycle_analytics.md) focuses on the entire
-SDLC process, Productivity Analytics provides a way for Engineering Management to
-drill down in a systematic way to uncover patterns and causes for success or failure at
-an individual, project or group level.
-
-Productivity can slow down for many reasons ranging from degrading code base to quickly
-growing teams. In order to investigate, department or team leaders can start by visualizing the time
-it takes for merge requests to be merged.
-
-## Supported features
-
-Productivity Analytics allows GitLab users to:
-
-- Visualize typical Merge Request lifetime and statistics. Use a histogram
- that shows the distribution of the time elapsed between creating and merging
- Merge Requests.
-- Drill down into the most time consuming Merge Requests, select a number of outliers,
- and filter down all subsequent charts to investigate potential causes.
-- Filter by group, project, author, label, milestone, or a specific date range.
- Filter down, for example, to the Merge Requests of a specific author in a group
- or project during a milestone or specific date range.
-
-## Accessing metrics and visualizations
-
-To access the **Productivity Analytics** page, go to **Analytics > Productivity Analytics**.
-
-The following metrics and visualizations are available on a project or group level:
-
-- Histogram showing the number of Merge Request that took a specified number of days to
- merge after creation. Select a specific column to filter down subsequent charts.
-- Histogram showing a breakdown of the time taken (in hours) to merge a Merge Request.
- The following intervals are available:
- - Time from first commit to first comment.
- - Time from first comment until last commit.
- - Time from last commit to merge.
-- Histogram showing the size or complexity of a Merge Request, using the following:
- - Number of commits per Merge Request.
- - Number of lines of code per commit.
- - Number of files touched.
-- Table showing list of Merge Requests with their respective times and size metrics.
- Can be sorted by the above metrics.
- - Users can sort by any of the above metrics
-
-## Retrieving data
-
-Users can retrieve three months of data when they deploy Productivity Analytics for the first time.
-
-To retrieve data for a different time span, run the following in the GitLab directory:
-
-```sh
-MERGED_AT_AFTER = <your_date> rake gitlab:productivity_analytics:recalc
-```
-
-## Permissions
-
-The **Productivity Analytics** dashboard can be accessed only:
-
-- On GitLab instances and namespaces on
- [Premium or Silver tier](https://about.gitlab.com/pricing/) and above.
-- By users with [Reporter access](../permissions.md) and above.
diff --git a/doc/user/asciidoc.md b/doc/user/asciidoc.md
index df86b2a1cbe..862316b57da 100644
--- a/doc/user/asciidoc.md
+++ b/doc/user/asciidoc.md
@@ -277,11 +277,11 @@ source - a listing that is embellished with (colorized) syntax highlighting
----
```
-````asciidoc
+~~~asciidoc
\```language
fenced code - a shorthand syntax for the source block
\```
-````
+~~~
```asciidoc
[,attribution,citetitle]
diff --git a/doc/user/profile/preferences.md b/doc/user/profile/preferences.md
index 5bd4b263a58..82a6d2b3703 100644
--- a/doc/user/profile/preferences.md
+++ b/doc/user/profile/preferences.md
@@ -87,6 +87,16 @@ You have 8 options here that you can use for your default dashboard view:
- Assigned Merge Requests
- Operations Dashboard **(PREMIUM)**
+### Group overview content
+
+The **Group overview content** dropdown allows you to choose what information is
+displayed on a group’s home page.
+
+You can choose between 2 options:
+
+- Details (default)
+- [Security dashboard](../application_security/security_dashboard/index.md) **(ULTIMATE)**
+
### Project overview content
The project overview content setting allows you to choose what content you want to
diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md
index ffaa07cb3a4..cf3a3fef79f 100644
--- a/doc/user/project/clusters/index.md
+++ b/doc/user/project/clusters/index.md
@@ -173,6 +173,9 @@ Starting from [GitLab 12.1](https://gitlab.com/gitlab-org/gitlab-ce/issues/55902
### Add existing Kubernetes cluster
+NOTE: **Note:**
+Kubernetes integration is not supported for arm64 clusters. See the issue [Helm Tiller fails to install on arm64 cluster](https://gitlab.com/gitlab-org/gitlab-ce/issues/64044) for details.
+
To add an existing Kubernetes cluster to your project:
1. Navigate to your project's **Operations > Kubernetes** page.
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 6227ca9afc3..d85b514ecfb 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -8146,6 +8146,9 @@ msgstr ""
msgid "Please add a list to your board first"
msgstr ""
+msgid "Please check your email (%{email}) to verify that you own this address. Didn't receive it? %{resend_link}. Wrong email address? %{update_link}."
+msgstr ""
+
msgid "Please choose a group URL with no special characters."
msgstr ""
@@ -9528,6 +9531,9 @@ msgstr ""
msgid "Resend invite"
msgstr ""
+msgid "Resend it"
+msgstr ""
+
msgid "Reset health check access token"
msgstr ""
@@ -12304,6 +12310,9 @@ msgstr ""
msgid "Update failed"
msgstr ""
+msgid "Update it"
+msgstr ""
+
msgid "Update now"
msgstr ""
diff --git a/spec/controllers/concerns/confirm_email_warning_spec.rb b/spec/controllers/concerns/confirm_email_warning_spec.rb
new file mode 100644
index 00000000000..0c598a360af
--- /dev/null
+++ b/spec/controllers/concerns/confirm_email_warning_spec.rb
@@ -0,0 +1,98 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe ConfirmEmailWarning do
+ before do
+ stub_feature_flags(soft_email_confirmation: true)
+ allow(User).to receive(:allow_unconfirmed_access_for).and_return 2.days
+ end
+
+ controller(ApplicationController) do
+ # `described_class` is not available in this context
+ include ConfirmEmailWarning # rubocop:disable RSpec/DescribedClass
+
+ def index
+ head :ok
+ end
+ end
+
+ RSpec::Matchers.define :set_confirm_warning_for do |email|
+ match do |response|
+ expect(response).to set_flash.now[:warning].to include("Please check your email (#{email}) to verify that you own this address.")
+ end
+ end
+
+ describe 'confirm email flash warning' do
+ context 'when not signed in' do
+ let(:user) { create(:user, confirmed_at: nil) }
+
+ before do
+ get :index
+ end
+
+ it { is_expected.not_to set_confirm_warning_for(user.email) }
+ end
+
+ context 'when signed in' do
+ before do
+ sign_in(user)
+ end
+
+ context 'with a confirmed user' do
+ let(:user) { create(:user) }
+
+ before do
+ get :index
+ end
+
+ it { is_expected.not_to set_confirm_warning_for(user.email) }
+ end
+
+ context 'with an unconfirmed user' do
+ let(:user) { create(:user, confirmed_at: nil) }
+
+ context 'when executing a peek request' do
+ before do
+ request.path = '/-/peek'
+ get :index
+ end
+
+ it { is_expected.not_to set_confirm_warning_for(user.email) }
+ end
+
+ context 'when executing a json request' do
+ before do
+ get :index, format: :json
+ end
+
+ it { is_expected.not_to set_confirm_warning_for(user.email) }
+ end
+
+ context 'when executing a post request' do
+ before do
+ post :index
+ end
+
+ it { is_expected.not_to set_confirm_warning_for(user.email) }
+ end
+
+ context 'when executing a get request' do
+ before do
+ get :index
+ end
+
+ context 'with an unconfirmed email address present' do
+ let(:user) { create(:user, confirmed_at: nil, unconfirmed_email: 'unconfirmed@gitlab.com') }
+
+ it { is_expected.to set_confirm_warning_for(user.unconfirmed_email) }
+ end
+
+ context 'without an unconfirmed email address present' do
+ it { is_expected.to set_confirm_warning_for(user.email) }
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb
index d05482f095e..fed4fc810f2 100644
--- a/spec/controllers/registrations_controller_spec.rb
+++ b/spec/controllers/registrations_controller_spec.rb
@@ -30,13 +30,36 @@ describe RegistrationsController do
end
context 'when send_user_confirmation_email is true' do
- it 'does not authenticate user and sends confirmation email' do
+ before do
stub_application_setting(send_user_confirmation_email: true)
+ end
+
+ context 'when soft email confirmation is not enabled' do
+ before do
+ stub_feature_flags(soft_email_confirmation: false)
+ allow(User).to receive(:allow_unconfirmed_access_for).and_return 0
+ end
+
+ it 'does not authenticate the user and sends a confirmation email' do
+ post(:create, params: user_params)
+
+ expect(ActionMailer::Base.deliveries.last.to.first).to eq(user_params[:user][:email])
+ expect(subject.current_user).to be_nil
+ end
+ end
- post(:create, params: user_params)
+ context 'when soft email confirmation is enabled' do
+ before do
+ stub_feature_flags(soft_email_confirmation: true)
+ allow(User).to receive(:allow_unconfirmed_access_for).and_return 2.days
+ end
- expect(ActionMailer::Base.deliveries.last.to.first).to eq(user_params[:user][:email])
- expect(subject.current_user).to be_nil
+ it 'authenticates the user and sends a confirmation email' do
+ post(:create, params: user_params)
+
+ expect(ActionMailer::Base.deliveries.last.to.first).to eq(user_params[:user][:email])
+ expect(response).to redirect_to(dashboard_projects_path)
+ end
end
end
diff --git a/spec/features/boards/multiple_boards_spec.rb b/spec/features/boards/multiple_boards_spec.rb
new file mode 100644
index 00000000000..9a2b7a80498
--- /dev/null
+++ b/spec/features/boards/multiple_boards_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+describe 'Multiple Issue Boards', :js do
+ set(:user) { create(:user) }
+ set(:project) { create(:project, :public) }
+ set(:planning) { create(:label, project: project, name: 'Planning') }
+ set(:board) { create(:board, name: 'board1', project: project) }
+ set(:board2) { create(:board, name: 'board2', project: project) }
+ let(:parent) { project }
+ let(:boards_path) { project_boards_path(project) }
+
+ it_behaves_like 'multiple issue boards'
+end
diff --git a/spec/features/invites_spec.rb b/spec/features/invites_spec.rb
index 832c4a57aa3..1e054a7b358 100644
--- a/spec/features/invites_spec.rb
+++ b/spec/features/invites_spec.rb
@@ -17,11 +17,10 @@ describe 'Invites' do
group_invite.generate_invite_token!
end
- def confirm_email_and_sign_in(new_user)
+ def confirm_email(new_user)
new_user_token = User.find_by_email(new_user.email).confirmation_token
visit user_confirmation_path(confirmation_token: new_user_token)
- fill_in_sign_in_form(new_user)
end
def fill_in_sign_up_form(new_user)
@@ -155,17 +154,41 @@ describe 'Invites' do
context 'email confirmation enabled' do
let(:send_email_confirmation) { true }
- it 'signs up and redirects to root page with all the project/groups invitation automatically accepted' do
- fill_in_sign_up_form(new_user)
- confirm_email_and_sign_in(new_user)
+ context 'when soft email confirmation is not enabled' do
+ before do
+ # stub_feature_flags(soft_email_confirmation: false)
+ allow(User).to receive(:allow_unconfirmed_access_for).and_return 0
+ end
- expect(current_path).to eq(root_path)
- expect(page).to have_content(project.full_name)
- visit group_path(group)
- expect(page).to have_content(group.full_name)
+ it 'signs up and redirects to root page with all the project/groups invitation automatically accepted' do
+ fill_in_sign_up_form(new_user)
+ confirm_email(new_user)
+ fill_in_sign_in_form(new_user)
+
+ expect(current_path).to eq(root_path)
+ expect(page).to have_content(project.full_name)
+ visit group_path(group)
+ expect(page).to have_content(group.full_name)
+ end
end
- it "doesn't accept invitations until the user confirm his email" do
+ context 'when soft email confirmation is enabled' do
+ before do
+ allow(User).to receive(:allow_unconfirmed_access_for).and_return 2.days
+ end
+
+ it 'signs up and redirects to root page with all the project/groups invitation automatically accepted' do
+ fill_in_sign_up_form(new_user)
+ confirm_email(new_user)
+
+ expect(current_path).to eq(root_path)
+ expect(page).to have_content(project.full_name)
+ visit group_path(group)
+ expect(page).to have_content(group.full_name)
+ end
+ end
+
+ it "doesn't accept invitations until the user confirms his email" do
fill_in_sign_up_form(new_user)
sign_in(owner)
@@ -176,11 +199,32 @@ describe 'Invites' do
context 'the user sign-up using a different email address' do
let(:invite_email) { build_stubbed(:user).email }
- it 'signs up and redirects to the invitation page' do
- fill_in_sign_up_form(new_user)
- confirm_email_and_sign_in(new_user)
+ context 'when soft email confirmation is not enabled' do
+ before do
+ stub_feature_flags(soft_email_confirmation: false)
+ allow(User).to receive(:allow_unconfirmed_access_for).and_return 0
+ end
- expect(current_path).to eq(invite_path(group_invite.raw_invite_token))
+ it 'signs up and redirects to the invitation page' do
+ fill_in_sign_up_form(new_user)
+ confirm_email(new_user)
+ fill_in_sign_in_form(new_user)
+
+ expect(current_path).to eq(invite_path(group_invite.raw_invite_token))
+ end
+ end
+
+ context 'when soft email confirmation is enabled' do
+ before do
+ stub_feature_flags(soft_email_confirmation: true)
+ allow(User).to receive(:allow_unconfirmed_access_for).and_return 2.days
+ end
+
+ it 'signs up and redirects to the invitation page' do
+ fill_in_sign_up_form(new_user)
+
+ expect(current_path).to eq(invite_path(group_invite.raw_invite_token))
+ end
end
end
end
diff --git a/spec/features/projects/files/user_browses_a_tree_with_a_folder_containing_only_a_folder_spec.rb b/spec/features/projects/files/user_browses_a_tree_with_a_folder_containing_only_a_folder_spec.rb
index c19e46da913..6bd569e5ee2 100644
--- a/spec/features/projects/files/user_browses_a_tree_with_a_folder_containing_only_a_folder_spec.rb
+++ b/spec/features/projects/files/user_browses_a_tree_with_a_folder_containing_only_a_folder_spec.rb
@@ -3,18 +3,15 @@
require 'spec_helper'
# This is a regression test for https://gitlab.com/gitlab-org/gitlab-ce/issues/37569
-# Quarantine: https://gitlab.com/gitlab-org/gitlab-ce/issues/65329
-describe 'Projects > Files > User browses a tree with a folder containing only a folder', :quarantine do
+describe 'Projects > Files > User browses a tree with a folder containing only a folder', :js do
let(:project) { create(:project, :empty_repo) }
let(:user) { project.owner }
before do
- # We need to disable the tree.flat_path provided by Gitaly to reproduce the issue
- allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(false)
-
project.repository.create_dir(user, 'foo/bar', branch_name: 'master', message: 'Add the foo/bar folder')
sign_in(user)
visit(project_tree_path(project, project.repository.root_ref))
+ wait_for_requests
end
it 'shows the nested folder on a single row' do
diff --git a/spec/features/users/login_spec.rb b/spec/features/users/login_spec.rb
index 1d8c9e7e426..8e4db2ca840 100644
--- a/spec/features/users/login_spec.rb
+++ b/spec/features/users/login_spec.rb
@@ -781,4 +781,39 @@ describe 'Login' do
end
end
end
+
+ context 'when sending confirmation email and not yet confirmed' do
+ let!(:user) { create(:user, confirmed_at: nil) }
+ let(:grace_period) { 2.days }
+
+ before do
+ stub_application_setting(send_user_confirmation_email: true)
+ stub_feature_flags(soft_email_confirmation: true)
+ allow(User).to receive(:allow_unconfirmed_access_for).and_return grace_period
+ end
+
+ it 'allows login and shows a flash warning to confirm the email address' do
+ expect(authentication_metrics).to increment(:user_authenticated_counter)
+
+ gitlab_sign_in(user)
+
+ expect(current_path).to eq root_path
+ expect(page).to have_content("Please check your email (#{user.email}) to verify that you own this address.")
+ end
+
+ context "when not having confirmed within Devise's allow_unconfirmed_access_for time" do
+ it 'does not allow login and shows a flash alert to confirm the email address' do
+ travel_to((grace_period + 1.day).from_now) do
+ expect(authentication_metrics)
+ .to increment(:user_unauthenticated_counter)
+ .and increment(:user_session_destroyed_counter).twice
+
+ gitlab_sign_in(user)
+
+ expect(current_path).to eq new_user_session_path
+ expect(page).to have_content('You have to confirm your email address before continuing.')
+ end
+ end
+ end
+ end
end
diff --git a/spec/features/users/signup_spec.rb b/spec/features/users/signup_spec.rb
index cf57fafc4f5..fb927a9ca3b 100644
--- a/spec/features/users/signup_spec.rb
+++ b/spec/features/users/signup_spec.rb
@@ -166,24 +166,51 @@ describe 'Signup' do
end
context 'with no errors' do
- context "when sending confirmation email" do
+ context 'when sending confirmation email' do
before do
stub_application_setting(send_user_confirmation_email: true)
end
- it 'creates the user account and sends a confirmation email' do
- visit root_path
+ context 'when soft email confirmation is not enabled' do
+ before do
+ stub_feature_flags(soft_email_confirmation: false)
+ end
- 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
+ it 'creates the user account and sends a confirmation email' 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
+
+ expect { click_button 'Register' }.to change { User.count }.by(1)
+
+ expect(current_path).to eq users_almost_there_path
+ expect(page).to have_content('Please check your email to confirm your account')
+ end
+ end
+
+ context 'when soft email confirmation is enabled' do
+ before do
+ stub_feature_flags(soft_email_confirmation: true)
+ end
+
+ it 'creates the user account and sends a confirmation email' 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
- expect { click_button 'Register' }.to change { User.count }.by(1)
+ expect { click_button 'Register' }.to change { User.count }.by(1)
- expect(current_path).to eq users_almost_there_path
- expect(page).to have_content("Please check your email to confirm your account")
+ expect(current_path).to eq dashboard_projects_path
+ expect(page).to have_content("Please check your email (#{new_user.email}) to verify that you own this address.")
+ end
end
end
diff --git a/spec/fixtures/api/schemas/deployment.json b/spec/fixtures/api/schemas/deployment.json
index 0828f113495..9216ad0060b 100644
--- a/spec/fixtures/api/schemas/deployment.json
+++ b/spec/fixtures/api/schemas/deployment.json
@@ -3,6 +3,7 @@
"required": [
"sha",
"created_at",
+ "finished_at",
"iid",
"tag",
"last?",
@@ -11,6 +12,7 @@
],
"properties": {
"created_at": { "type": "string" },
+ "finished_at": { "type": ["string", "null"] },
"id": { "type": "integer" },
"iid": { "type": "integer" },
"last?": { "type": "boolean" },
diff --git a/spec/frontend/notes/components/discussion_keyboard_navigator_spec.js b/spec/frontend/notes/components/discussion_keyboard_navigator_spec.js
index 6d50713999d..8881bedf3cc 100644
--- a/spec/frontend/notes/components/discussion_keyboard_navigator_spec.js
+++ b/spec/frontend/notes/components/discussion_keyboard_navigator_spec.js
@@ -74,4 +74,31 @@ describe('notes/components/discussion_keyboard_navigator', () => {
expect(wrapper.vm.currentDiscussionId).toEqual(expectedPrevId);
});
});
+
+ describe('on destroy', () => {
+ beforeEach(() => {
+ jest.spyOn(Mousetrap, 'unbind');
+
+ createComponent();
+
+ wrapper.destroy();
+ });
+
+ it('unbinds keys', () => {
+ expect(Mousetrap.unbind).toHaveBeenCalledWith('n');
+ expect(Mousetrap.unbind).toHaveBeenCalledWith('p');
+ });
+
+ it('does not call jumpToNextDiscussion when pressing `n`', () => {
+ Mousetrap.trigger('n');
+
+ expect(wrapper.vm.jumpToDiscussion).not.toHaveBeenCalled();
+ });
+
+ it('does not call jumpToNextDiscussion when pressing `p`', () => {
+ Mousetrap.trigger('p');
+
+ expect(wrapper.vm.jumpToDiscussion).not.toHaveBeenCalled();
+ });
+ });
});
diff --git a/spec/frontend/vue_shared/components/changed_file_icon_spec.js b/spec/frontend/vue_shared/components/changed_file_icon_spec.js
new file mode 100644
index 00000000000..806602877ef
--- /dev/null
+++ b/spec/frontend/vue_shared/components/changed_file_icon_spec.js
@@ -0,0 +1,123 @@
+import { shallowMount } from '@vue/test-utils';
+import ChangedFileIcon from '~/vue_shared/components/changed_file_icon.vue';
+import Icon from '~/vue_shared/components/icon.vue';
+
+const changedFile = () => ({ changed: true });
+const stagedFile = () => ({ changed: false, staged: true });
+const changedAndStagedFile = () => ({ changed: true, staged: true });
+const newFile = () => ({ changed: true, tempFile: true });
+const unchangedFile = () => ({ changed: false, tempFile: false, staged: false, deleted: false });
+
+describe('Changed file icon', () => {
+ let wrapper;
+
+ const factory = (props = {}) => {
+ wrapper = shallowMount(ChangedFileIcon, {
+ propsData: {
+ file: changedFile(),
+ showTooltip: true,
+ ...props,
+ },
+ sync: false,
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ const findIcon = () => wrapper.find(Icon);
+ const findIconName = () => findIcon().props('name');
+ const findIconClasses = () =>
+ findIcon()
+ .props('cssClasses')
+ .split(' ');
+ const findTooltipText = () => wrapper.attributes('data-original-title');
+
+ it('with isCentered true, adds center class', () => {
+ factory({
+ isCentered: true,
+ });
+
+ expect(wrapper.classes('ml-auto')).toBe(true);
+ });
+
+ it('with isCentered false, does not center', () => {
+ factory({
+ isCentered: false,
+ });
+
+ expect(wrapper.classes('ml-auto')).toBe(false);
+ });
+
+ it('with showTooltip false, does not show tooltip', () => {
+ factory({
+ showTooltip: false,
+ });
+
+ expect(findTooltipText()).toBeFalsy();
+ });
+
+ describe.each`
+ file | iconName | tooltipText | desc
+ ${changedFile()} | ${'file-modified'} | ${'Unstaged modification'} | ${'with file changed'}
+ ${stagedFile()} | ${'file-modified-solid'} | ${'Staged modification'} | ${'with file staged'}
+ ${changedAndStagedFile()} | ${'file-modified'} | ${'Unstaged and staged modification'} | ${'with file changed and staged'}
+ ${newFile()} | ${'file-addition'} | ${'Unstaged addition'} | ${'with file new'}
+ `('$desc', ({ file, iconName, tooltipText }) => {
+ beforeEach(() => {
+ factory({ file });
+ });
+
+ it('renders icon', () => {
+ expect(findIconName()).toBe(iconName);
+ expect(findIconClasses()).toContain(iconName);
+ });
+
+ it('renders tooltip text', () => {
+ expect(findTooltipText()).toBe(tooltipText);
+ });
+ });
+
+ describe('with file unchanged', () => {
+ beforeEach(() => {
+ factory({
+ file: unchangedFile(),
+ });
+ });
+
+ it('does not show icon', () => {
+ expect(findIcon().exists()).toBe(false);
+ });
+
+ it('does not have tooltip text', () => {
+ expect(findTooltipText()).toBe('');
+ });
+ });
+
+ it('with size set, sets icon size', () => {
+ const size = 8;
+
+ factory({
+ file: changedFile(),
+ size,
+ });
+
+ expect(findIcon().props('size')).toBe(size);
+ });
+
+ // NOTE: It looks like 'showStagedIcon' behavior is backwards to what the name suggests
+ // https://gitlab.com/gitlab-org/gitlab-ce/issues/66071
+ it.each`
+ showStagedIcon | iconName | desc
+ ${false} | ${'file-modified-solid'} | ${'with showStagedIcon false, renders staged icon'}
+ ${true} | ${'file-modified'} | ${'with showStagedIcon true, renders regular icon'}
+ `('$desc', ({ showStagedIcon, iconName }) => {
+ factory({
+ file: stagedFile(),
+ showStagedIcon,
+ });
+
+ expect(findIconName()).toEqual(iconName);
+ });
+});
diff --git a/spec/javascripts/vue_shared/components/changed_file_icon_spec.js b/spec/javascripts/vue_shared/components/changed_file_icon_spec.js
deleted file mode 100644
index 634ba8403d5..00000000000
--- a/spec/javascripts/vue_shared/components/changed_file_icon_spec.js
+++ /dev/null
@@ -1,63 +0,0 @@
-import Vue from 'vue';
-import changedFileIcon from '~/vue_shared/components/changed_file_icon.vue';
-import createComponent from 'spec/helpers/vue_mount_component_helper';
-
-describe('Changed file icon', () => {
- let vm;
-
- function factory(props = {}) {
- const component = Vue.extend(changedFileIcon);
-
- vm = createComponent(component, {
- ...props,
- file: {
- tempFile: false,
- changed: true,
- },
- });
- }
-
- afterEach(() => {
- vm.$destroy();
- });
-
- it('centers icon', () => {
- factory({
- isCentered: true,
- });
-
- expect(vm.$el.classList).toContain('ml-auto');
- });
-
- describe('changedIcon', () => {
- it('equals file-modified when not a temp file and has changes', () => {
- factory();
-
- expect(vm.changedIcon).toBe('file-modified');
- });
-
- it('equals file-addition when a temp file', () => {
- factory();
-
- vm.file.tempFile = true;
-
- expect(vm.changedIcon).toBe('file-addition');
- });
- });
-
- describe('changedIconClass', () => {
- it('includes file-modified when not a temp file', () => {
- factory();
-
- expect(vm.changedIconClass).toContain('file-modified');
- });
-
- it('includes file-addition when a temp file', () => {
- factory();
-
- vm.file.tempFile = true;
-
- expect(vm.changedIconClass).toContain('file-addition');
- });
- });
-});
diff --git a/spec/serializers/deployment_entity_spec.rb b/spec/serializers/deployment_entity_spec.rb
index 76ad2aee5c5..c0ea2b3c389 100644
--- a/spec/serializers/deployment_entity_spec.rb
+++ b/spec/serializers/deployment_entity_spec.rb
@@ -32,6 +32,10 @@ describe DeploymentEntity do
expect(subject).to include(:created_at)
end
+ it 'exposes finished_at' do
+ expect(subject).to include(:finished_at)
+ end
+
context 'when the pipeline has another manual action' do
let(:other_build) { create(:ci_build, :manual, name: 'another deploy', pipeline: pipeline) }
let!(:other_deployment) { create(:deployment, deployable: other_build) }
diff --git a/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb b/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb
new file mode 100644
index 00000000000..76d82649c5f
--- /dev/null
+++ b/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb
@@ -0,0 +1,144 @@
+# frozen_string_literal: true
+
+shared_examples_for 'multiple issue boards' do
+ dropdown_selector = '.js-boards-selector .dropdown-menu'
+
+ context 'authorized user' do
+ before do
+ parent.add_maintainer(user)
+
+ login_as(user)
+
+ visit boards_path
+ wait_for_requests
+ end
+
+ it 'shows current board name' do
+ page.within('.boards-switcher') do
+ expect(page).to have_content(board.name)
+ end
+ end
+
+ it 'shows a list of boards' do
+ click_button board.name
+
+ page.within(dropdown_selector) do
+ expect(page).to have_content(board.name)
+ expect(page).to have_content(board2.name)
+ end
+ end
+
+ it 'switches current board' do
+ click_button board.name
+
+ page.within(dropdown_selector) do
+ click_link board2.name
+ end
+
+ wait_for_requests
+
+ page.within('.boards-switcher') do
+ expect(page).to have_content(board2.name)
+ end
+ end
+
+ it 'creates new board without detailed configuration' do
+ click_button board.name
+
+ page.within(dropdown_selector) do
+ click_button 'Create new board'
+ end
+
+ fill_in 'board-new-name', with: 'This is a new board'
+ click_button 'Create board'
+ wait_for_requests
+
+ expect(page).to have_button('This is a new board')
+ end
+
+ it 'deletes board' do
+ click_button board.name
+
+ wait_for_requests
+
+ page.within(dropdown_selector) do
+ click_button 'Delete board'
+ end
+
+ expect(page).to have_content('Are you sure you want to delete this board?')
+ click_button 'Delete'
+
+ click_button board2.name
+ page.within(dropdown_selector) do
+ expect(page).not_to have_content(board.name)
+ expect(page).to have_content(board2.name)
+ end
+ end
+
+ it 'adds a list to the none default board' do
+ click_button board.name
+
+ page.within(dropdown_selector) do
+ click_link board2.name
+ end
+
+ wait_for_requests
+
+ page.within('.boards-switcher') do
+ expect(page).to have_content(board2.name)
+ end
+
+ click_button 'Add list'
+
+ wait_for_requests
+
+ page.within '.dropdown-menu-issues-board-new' do
+ click_link planning.title
+ end
+
+ wait_for_requests
+
+ expect(page).to have_selector('.board', count: 3)
+
+ click_button board2.name
+
+ page.within(dropdown_selector) do
+ click_link board.name
+ end
+
+ wait_for_requests
+
+ expect(page).to have_selector('.board', count: 2)
+ end
+
+ it 'maintains sidebar state over board switch' do
+ assert_boards_nav_active
+
+ find('.boards-switcher').click
+ wait_for_requests
+ click_link board2.name
+
+ assert_boards_nav_active
+ end
+ end
+
+ context 'unauthorized user' do
+ before do
+ visit boards_path
+ wait_for_requests
+ end
+
+ it 'does not show action links' do
+ click_button board.name
+
+ page.within(dropdown_selector) do
+ expect(page).not_to have_content('Create new board')
+ expect(page).not_to have_content('Delete board')
+ end
+ end
+ end
+
+ def assert_boards_nav_active
+ expect(find('.nav-sidebar .active .active')).to have_selector('a', text: 'Boards')
+ end
+end