From ce27ba9f6c36ecb36114887853a5820c83a7036c Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Thu, 29 Oct 2020 18:09:11 +0000 Subject: Add latest changes from gitlab-org/gitlab@master --- .../components/alerts_integrations_list.vue | 19 +- .../components/alerts_settings_wrapper.vue | 46 ++++- .../fragments/integration_item.fragment.graphql | 9 + .../graphql/queries/get_integrations.query.graphql | 11 ++ app/assets/javascripts/alerts_settings/index.js | 20 ++ .../feature_flags/components/edit_feature_flag.vue | 2 +- .../javascripts/pages/admin/runners/index.js | 13 +- .../pages/groups/settings/ci_cd/show/index.js | 24 +-- .../pages/projects/settings/ci_cd/show/index.js | 46 ++--- .../pages/shared/mount_runner_instructions.js | 32 +++ .../pipelines/components/graph/job_item.vue | 5 +- .../static_site_editor/components/edit_area.vue | 15 +- .../static_site_editor/services/front_matterify.js | 2 + .../services/parse_source_file.js | 18 +- .../queries/get_runner_platforms.query.graphql | 20 ++ .../graphql/queries/get_runner_setup.query.graphql | 16 ++ .../runner_instructions/runner_instructions.vue | 214 +++++++++++++++++++++ .../pages/incident_management_list.scss | 19 +- app/controllers/profiles_controller.rb | 2 +- app/graphql/types/availability_enum.rb | 12 ++ app/graphql/types/terraform/state_type.rb | 5 + app/graphql/types/terraform/state_version_type.rb | 29 +++ app/graphql/types/user_status_type.rb | 2 + app/helpers/operations_helper.rb | 3 +- app/models/deployment_merge_request.rb | 5 + app/models/terraform/state.rb | 11 +- app/models/user_status.rb | 2 + app/policies/terraform/state_version_policy.rb | 9 + .../projects/lfs_pointers/lfs_download_service.rb | 2 +- app/services/users/set_status_service.rb | 5 +- app/views/admin/runners/index.html.haml | 4 +- app/views/ci/runner/_how_to_setup_runner.html.haml | 2 + app/views/groups/runners/_group_runners.html.haml | 4 +- .../projects/runners/_specific_runners.html.haml | 4 +- bin/background_jobs | 2 +- bin/mail_room | 2 +- bin/web_unicorn | 2 +- .../267147-terraform-state-versions-graphql.yml | 5 + ...271550-fj-forbid-realtime_changes-in-robots.yml | 5 + .../ImproveShellScriptsChangeDirException.yml | 5 + ...ature-flags-edit-increase-loading-icon-size.yml | 5 + .../jivanvl-runner-guided-install-frontend.yml | 5 + changelogs/unreleased/job-dropdown-click.yml | 5 + changelogs/unreleased/set-user-availability-be.yml | 5 + .../development/lfs_link_existing_object.yml | 7 - ...1022103304_add_availability_to_user_statuses.rb | 9 + db/schema_migrations/20201022103304 | 1 + db/structure.sql | 3 +- doc/.vale/gitlab/Acronyms.yml | 1 + doc/administration/geo/index.md | 1 + .../geo/replication/troubleshooting.md | 10 + .../operations/moving_repositories.md | 48 ++--- doc/api/graphql/reference/gitlab_schema.graphql | 47 +++++ doc/api/graphql/reference/gitlab_schema.json | 136 +++++++++++++ doc/api/graphql/reference/index.md | 20 ++ doc/api/project_repository_storage_moves.md | 4 +- .../merge_trains/index.md | 4 +- doc/operations/incident_management/incidents.md | 48 +++-- doc/update/README.md | 4 +- doc/user/group/index.md | 7 +- doc/user/project/clusters/index.md | 3 +- lib/api/discussions.rb | 20 +- lib/api/entities/user_status.rb | 1 + lib/api/helpers/discussions_helpers.rb | 9 +- lib/api/helpers/notes_helpers.rb | 10 +- lib/api/import_bitbucket_server.rb | 2 + lib/api/import_github.rb | 2 + lib/api/issue_links.rb | 2 + lib/api/issues.rb | 4 +- lib/api/job_artifacts.rb | 2 + lib/api/jobs.rb | 2 + lib/api/keys.rb | 2 + lib/api/labels.rb | 2 + lib/api/lint.rb | 2 + lib/api/markdown.rb | 2 + lib/api/members.rb | 2 + lib/api/merge_request_approvals.rb | 2 + lib/api/merge_request_diffs.rb | 2 + lib/api/merge_requests.rb | 2 + lib/api/metrics/dashboard/annotations.rb | 2 + lib/api/metrics/user_starred_dashboards.rb | 2 + lib/api/namespaces.rb | 2 + lib/api/notes.rb | 10 +- lib/api/users.rb | 1 + lib/gitlab/repository_size_checker.rb | 4 +- locale/gitlab.pot | 24 +++ package.json | 2 +- public/robots.txt | 1 + scripts/lint-doc.sh | 2 +- spec/controllers/profiles_controller_spec.rb | 3 +- spec/factories/terraform/state.rb | 2 +- .../alerts_integrations_list_spec.js | 4 +- .../alerts_settings_form_new_spec.js | 2 - .../alerts_settings_wrapper_spec.js | 55 +++++- .../alerts_settings/mocks/integrations.json | 38 ++++ .../services/front_matterify_spec.js | 8 + .../components/runner_instructions/mock_data.js | 107 +++++++++++ .../runner_instructions_spec.js | 119 ++++++++++++ spec/graphql/types/availability_enum_spec.rb | 11 ++ spec/graphql/types/terraform/state_type_spec.rb | 5 +- .../types/terraform/state_version_type_spec.rb | 19 ++ spec/graphql/types/user_status_type_spec.rb | 1 + spec/helpers/operations_helper_spec.rb | 3 +- spec/lib/api/every_api_endpoint_spec.rb | 9 +- .../terraform/state_version_policy_spec.rb | 33 ++++ .../api/graphql/project/terraform/states_spec.rb | 25 ++- spec/requests/api/graphql/user_query_spec.rb | 9 +- spec/requests/robots_txt_spec.rb | 4 +- .../lfs_pointers/lfs_download_service_spec.rb | 12 -- spec/services/users/set_status_service_spec.rb | 23 ++- .../repository_size_checker_shared_examples.rb | 59 ++++-- yarn.lock | 142 ++++++++++---- 112 files changed, 1586 insertions(+), 253 deletions(-) create mode 100644 app/assets/javascripts/alerts_settings/graphql/fragments/integration_item.fragment.graphql create mode 100644 app/assets/javascripts/alerts_settings/graphql/queries/get_integrations.query.graphql create mode 100644 app/assets/javascripts/pages/shared/mount_runner_instructions.js create mode 100644 app/assets/javascripts/vue_shared/components/runner_instructions/graphql/queries/get_runner_platforms.query.graphql create mode 100644 app/assets/javascripts/vue_shared/components/runner_instructions/graphql/queries/get_runner_setup.query.graphql create mode 100644 app/assets/javascripts/vue_shared/components/runner_instructions/runner_instructions.vue create mode 100644 app/graphql/types/availability_enum.rb create mode 100644 app/graphql/types/terraform/state_version_type.rb create mode 100644 app/policies/terraform/state_version_policy.rb create mode 100644 changelogs/unreleased/267147-terraform-state-versions-graphql.yml create mode 100644 changelogs/unreleased/271550-fj-forbid-realtime_changes-in-robots.yml create mode 100644 changelogs/unreleased/ImproveShellScriptsChangeDirException.yml create mode 100644 changelogs/unreleased/feature-flags-edit-increase-loading-icon-size.yml create mode 100644 changelogs/unreleased/jivanvl-runner-guided-install-frontend.yml create mode 100644 changelogs/unreleased/job-dropdown-click.yml create mode 100644 changelogs/unreleased/set-user-availability-be.yml delete mode 100644 config/feature_flags/development/lfs_link_existing_object.yml create mode 100644 db/migrate/20201022103304_add_availability_to_user_statuses.rb create mode 100644 db/schema_migrations/20201022103304 create mode 100644 spec/frontend/alerts_settings/mocks/integrations.json create mode 100644 spec/frontend/vue_shared/components/runner_instructions/mock_data.js create mode 100644 spec/frontend/vue_shared/components/runner_instructions/runner_instructions_spec.js create mode 100644 spec/graphql/types/availability_enum_spec.rb create mode 100644 spec/graphql/types/terraform/state_version_type_spec.rb create mode 100644 spec/policies/terraform/state_version_policy_spec.rb diff --git a/app/assets/javascripts/alerts_settings/components/alerts_integrations_list.vue b/app/assets/javascripts/alerts_settings/components/alerts_integrations_list.vue index d377f0f2654..432271d2075 100644 --- a/app/assets/javascripts/alerts_settings/components/alerts_integrations_list.vue +++ b/app/assets/javascripts/alerts_settings/components/alerts_integrations_list.vue @@ -1,5 +1,5 @@ + diff --git a/app/assets/stylesheets/pages/incident_management_list.scss b/app/assets/stylesheets/pages/incident_management_list.scss index c0a1fa72b1f..9ba79dd1235 100644 --- a/app/assets/stylesheets/pages/incident_management_list.scss +++ b/app/assets/stylesheets/pages/incident_management_list.scss @@ -8,13 +8,12 @@ @include gl-text-gray-500; tbody { - tr:not(.b-table-busy-slot) { - // TODO replace with gitlab/ui utilities: https://gitlab.com/gitlab-org/gitlab-ui/-/merge_requests/1791 + tr:not(.b-table-busy-slot):not(.b-table-empty-row) { &:hover { - border-top-style: double; + @include gl-border-t-double; td { - border-bottom-style: initial; + @include gl-border-b-initial; } } } @@ -22,7 +21,7 @@ tr { &:focus { - outline: none; + @include gl-outline-none; } td, @@ -118,22 +117,22 @@ } .gl-tabs-nav { - border-bottom-width: 0; + @include gl-border-b-0; .gl-tab-nav-item { - color: $gray-500; + @include gl-text-gray-500; > .gl-tab-counter-badge { - color: inherit; + @include gl-reset-color; @include gl-font-sm; - background-color: $gray-50; + @include gl-bg-gray-50; } } } @include media-breakpoint-down(xs) { .list-header { - flex-direction: column-reverse; + @include gl-flex-direction-column-reverse; } .create-incident-button { diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index c85c83688a4..afebeafff7c 100644 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -127,7 +127,7 @@ class ProfilesController < Profiles::ApplicationController :include_private_contributions, :timezone, :job_title, - status: [:emoji, :message] + status: [:emoji, :message, :availability] ) end end diff --git a/app/graphql/types/availability_enum.rb b/app/graphql/types/availability_enum.rb new file mode 100644 index 00000000000..61686b9359f --- /dev/null +++ b/app/graphql/types/availability_enum.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Types + class AvailabilityEnum < BaseEnum + graphql_name 'AvailabilityEnum' + description 'User availability status' + + ::UserStatus.availabilities.keys.each do |availability_value| + value availability_value.upcase, value: availability_value, description: availability_value.titleize + end + end +end diff --git a/app/graphql/types/terraform/state_type.rb b/app/graphql/types/terraform/state_type.rb index 3ee7361baf1..05b6d130f19 100644 --- a/app/graphql/types/terraform/state_type.rb +++ b/app/graphql/types/terraform/state_type.rb @@ -27,6 +27,11 @@ module Types null: true, description: 'Timestamp the Terraform state was locked' + field :latest_version, Types::Terraform::StateVersionType, + complexity: 3, + null: true, + description: 'The latest version of the Terraform state' + field :created_at, Types::TimeType, null: false, description: 'Timestamp the Terraform state was created' diff --git a/app/graphql/types/terraform/state_version_type.rb b/app/graphql/types/terraform/state_version_type.rb new file mode 100644 index 00000000000..7a5663c6324 --- /dev/null +++ b/app/graphql/types/terraform/state_version_type.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module Types + module Terraform + class StateVersionType < BaseObject + graphql_name 'TerraformStateVersion' + + authorize :read_terraform_state + + field :id, GraphQL::ID_TYPE, + null: false, + description: 'ID of the Terraform state version' + + field :created_by_user, Types::UserType, + null: true, + authorize: :read_user, + description: 'The user that created this version', + resolve: -> (version, _, _) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, version.created_by_user_id).find } + + field :created_at, Types::TimeType, + null: false, + description: 'Timestamp the version was created' + + field :updated_at, Types::TimeType, + null: false, + description: 'Timestamp the version was updated' + end + end +end diff --git a/app/graphql/types/user_status_type.rb b/app/graphql/types/user_status_type.rb index ff277c1f8e8..9cf6c862d3d 100644 --- a/app/graphql/types/user_status_type.rb +++ b/app/graphql/types/user_status_type.rb @@ -11,5 +11,7 @@ module Types description: 'User status message' field :emoji, GraphQL::STRING_TYPE, null: true, description: 'String representation of emoji' + field :availability, Types::AvailabilityEnum, null: false, + description: 'User availability status' end end diff --git a/app/helpers/operations_helper.rb b/app/helpers/operations_helper.rb index 9965a705a01..7234cbb29cc 100644 --- a/app/helpers/operations_helper.rb +++ b/app/helpers/operations_helper.rb @@ -29,7 +29,8 @@ module OperationsHelper 'url' => alerts_service.url, 'alerts_setup_url' => help_page_path('operations/incident_management/alert_integrations.md', anchor: 'generic-http-endpoint'), 'alerts_usage_url' => project_alert_management_index_path(@project), - 'disabled' => disabled.to_s + 'disabled' => disabled.to_s, + 'project_path' => project_path(@project) } end diff --git a/app/models/deployment_merge_request.rb b/app/models/deployment_merge_request.rb index b67f96906f5..64a578e16bf 100644 --- a/app/models/deployment_merge_request.rb +++ b/app/models/deployment_merge_request.rb @@ -14,7 +14,12 @@ class DeploymentMergeRequest < ApplicationRecord end def self.deployed_to(name) + # We filter by project ID again so the query uses the index on + # (project_id, name), instead of using the index on + # (name varchar_pattern_ops). This results in better performance on + # GitLab.com. where('environments.name = ?', name) + .where('environments.project_id = merge_requests.target_project_id') end def self.deployed_after(time) diff --git a/app/models/terraform/state.rb b/app/models/terraform/state.rb index c0579c7eedc..d329b429c9d 100644 --- a/app/models/terraform/state.rb +++ b/app/models/terraform/state.rb @@ -17,8 +17,15 @@ module Terraform belongs_to :project belongs_to :locked_by_user, class_name: 'User' - has_many :versions, class_name: 'Terraform::StateVersion', foreign_key: :terraform_state_id - has_one :latest_version, -> { ordered_by_version_desc }, class_name: 'Terraform::StateVersion', foreign_key: :terraform_state_id + has_many :versions, + class_name: 'Terraform::StateVersion', + foreign_key: :terraform_state_id, + inverse_of: :terraform_state + + has_one :latest_version, -> { ordered_by_version_desc }, + class_name: 'Terraform::StateVersion', + foreign_key: :terraform_state_id, + inverse_of: :terraform_state scope :versioning_not_enabled, -> { where(versioning_enabled: false) } scope :ordered_by_name, -> { order(:name) } diff --git a/app/models/user_status.rb b/app/models/user_status.rb index 016b89bae81..0e1ae0b7338 100644 --- a/app/models/user_status.rb +++ b/app/models/user_status.rb @@ -9,6 +9,8 @@ class UserStatus < ApplicationRecord belongs_to :user + enum availability: { not_set: 0, busy: 1 } + validates :user, presence: true validates :emoji, inclusion: { in: Gitlab::Emoji.emojis_names } validates :message, length: { maximum: 100 }, allow_blank: true diff --git a/app/policies/terraform/state_version_policy.rb b/app/policies/terraform/state_version_policy.rb new file mode 100644 index 00000000000..ad0b2f6d594 --- /dev/null +++ b/app/policies/terraform/state_version_policy.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +module Terraform + class StateVersionPolicy < BasePolicy + alias_method :terraform_state_version, :subject + + delegate { terraform_state_version.terraform_state } + end +end diff --git a/app/services/projects/lfs_pointers/lfs_download_service.rb b/app/services/projects/lfs_pointers/lfs_download_service.rb index d6e5b825e13..525f8a25d04 100644 --- a/app/services/projects/lfs_pointers/lfs_download_service.rb +++ b/app/services/projects/lfs_pointers/lfs_download_service.rb @@ -22,7 +22,7 @@ module Projects def execute return unless project&.lfs_enabled? && lfs_download_object return error("LFS file with oid #{lfs_oid} has invalid attributes") unless lfs_download_object.valid? - return link_existing_lfs_object! if Feature.enabled?(:lfs_link_existing_object, project, default_enabled: true) && lfs_size > LARGE_FILE_SIZE && lfs_object + return link_existing_lfs_object! if lfs_size > LARGE_FILE_SIZE && lfs_object wrap_download_errors do download_lfs_file! diff --git a/app/services/users/set_status_service.rb b/app/services/users/set_status_service.rb index 89008368d5f..356c8782af1 100644 --- a/app/services/users/set_status_service.rb +++ b/app/services/users/set_status_service.rb @@ -14,7 +14,7 @@ module Users def execute return false unless can?(current_user, :update_user_status, target_user) - if params[:emoji].present? || params[:message].present? + if params[:emoji].present? || params[:message].present? || params[:availability].present? set_status else remove_status @@ -25,6 +25,9 @@ module Users def set_status params[:emoji] = UserStatus::DEFAULT_EMOJI if params[:emoji].blank? + params.delete(:availability) if params[:availability].blank? + return false if params[:availability].present? && UserStatus.availabilities.keys.exclude?(params[:availability]) + user_status.update(params) end diff --git a/app/views/admin/runners/index.html.haml b/app/views/admin/runners/index.html.haml index 3d3b8c28a17..c2d7b63f1f9 100644 --- a/app/views/admin/runners/index.html.haml +++ b/app/views/admin/runners/index.html.haml @@ -39,7 +39,9 @@ = render partial: 'ci/runner/how_to_setup_runner', locals: { registration_token: Gitlab::CurrentSettings.runners_registration_token, type: 'shared', - reset_token_url: reset_registration_token_admin_application_settings_path } + reset_token_url: reset_registration_token_admin_application_settings_path, + project_path: '', + group_path: '' } .row .col-sm-9 diff --git a/app/views/ci/runner/_how_to_setup_runner.html.haml b/app/views/ci/runner/_how_to_setup_runner.html.haml index 4ea3b0f0fb9..0ff6fdc6354 100644 --- a/app/views/ci/runner/_how_to_setup_runner.html.haml +++ b/app/views/ci/runner/_how_to_setup_runner.html.haml @@ -19,3 +19,5 @@ data: { confirm: _("Are you sure you want to reset registration token?") } %li = _("Start the Runner!") + +#js-install-runner{ data: { project_path: project_path, group_path: group_path } } diff --git a/app/views/groups/runners/_group_runners.html.haml b/app/views/groups/runners/_group_runners.html.haml index 554240b7aef..087c38c7b86 100644 --- a/app/views/groups/runners/_group_runners.html.haml +++ b/app/views/groups/runners/_group_runners.html.haml @@ -17,4 +17,6 @@ = render partial: 'ci/runner/how_to_setup_runner', locals: { registration_token: @group.runners_token, type: 'group', - reset_token_url: reset_registration_token_group_settings_ci_cd_path } + reset_token_url: reset_registration_token_group_settings_ci_cd_path, + project_path: '', + group_path: @group.path } diff --git a/app/views/projects/runners/_specific_runners.html.haml b/app/views/projects/runners/_specific_runners.html.haml index 4cc67a8f5d8..d7fe141e802 100644 --- a/app/views/projects/runners/_specific_runners.html.haml +++ b/app/views/projects/runners/_specific_runners.html.haml @@ -9,7 +9,9 @@ = render partial: 'ci/runner/how_to_setup_runner', locals: { registration_token: @project.runners_token, type: 'specific', - reset_token_url: reset_registration_token_namespace_project_settings_ci_cd_path } + reset_token_url: reset_registration_token_namespace_project_settings_ci_cd_path, + project_path: @project.path_with_namespace, + group_path: '' } - if @project_runners.any? %h4.underlined-title= _('Runners activated for this project') diff --git a/bin/background_jobs b/bin/background_jobs index 866f5c39cd6..cbc501094c4 100755 --- a/bin/background_jobs +++ b/bin/background_jobs @@ -1,6 +1,6 @@ #!/usr/bin/env bash -cd $(dirname $0)/.. +cd $(dirname $0)/.. || exit 1 if [ -n "$SIDEKIQ_WORKERS" ] ; then exec bin/background_jobs_sk_cluster "$@" diff --git a/bin/mail_room b/bin/mail_room index be608be4229..cf9d422909e 100755 --- a/bin/mail_room +++ b/bin/mail_room @@ -1,6 +1,6 @@ #!/bin/sh -cd $(dirname $0)/.. +cd $(dirname $0)/.. || exit 1 app_root=$(pwd) mail_room_pidfile="$app_root/tmp/pids/mail_room.pid" diff --git a/bin/web_unicorn b/bin/web_unicorn index 41e2ac44351..5fa15a8324b 100755 --- a/bin/web_unicorn +++ b/bin/web_unicorn @@ -1,6 +1,6 @@ #!/bin/sh -cd $(dirname $0)/.. +cd $(dirname $0)/.. || exit 1 app_root=$(pwd) unicorn_pidfile="$app_root/tmp/pids/unicorn.pid" diff --git a/changelogs/unreleased/267147-terraform-state-versions-graphql.yml b/changelogs/unreleased/267147-terraform-state-versions-graphql.yml new file mode 100644 index 00000000000..0eb03990dd1 --- /dev/null +++ b/changelogs/unreleased/267147-terraform-state-versions-graphql.yml @@ -0,0 +1,5 @@ +--- +title: Add latest version field to Terraform state GraphQL type +merge_request: 45848 +author: +type: added diff --git a/changelogs/unreleased/271550-fj-forbid-realtime_changes-in-robots.yml b/changelogs/unreleased/271550-fj-forbid-realtime_changes-in-robots.yml new file mode 100644 index 00000000000..b90a85fa043 --- /dev/null +++ b/changelogs/unreleased/271550-fj-forbid-realtime_changes-in-robots.yml @@ -0,0 +1,5 @@ +--- +title: Disallow realtime_changes route in robots.txt +merge_request: 45986 +author: +type: changed diff --git a/changelogs/unreleased/ImproveShellScriptsChangeDirException.yml b/changelogs/unreleased/ImproveShellScriptsChangeDirException.yml new file mode 100644 index 00000000000..8d14907e88d --- /dev/null +++ b/changelogs/unreleased/ImproveShellScriptsChangeDirException.yml @@ -0,0 +1,5 @@ +--- +title: Execute `exit 1` when shell script `cd` fails +merge_request: 46122 +author: Peter Dave Hello +type: other diff --git a/changelogs/unreleased/feature-flags-edit-increase-loading-icon-size.yml b/changelogs/unreleased/feature-flags-edit-increase-loading-icon-size.yml new file mode 100644 index 00000000000..89b3fe093ba --- /dev/null +++ b/changelogs/unreleased/feature-flags-edit-increase-loading-icon-size.yml @@ -0,0 +1,5 @@ +--- +title: Make loading icon on feature flag edit page larger +merge_request: 46268 +author: +type: fixed diff --git a/changelogs/unreleased/jivanvl-runner-guided-install-frontend.yml b/changelogs/unreleased/jivanvl-runner-guided-install-frontend.yml new file mode 100644 index 00000000000..d103c4015d4 --- /dev/null +++ b/changelogs/unreleased/jivanvl-runner-guided-install-frontend.yml @@ -0,0 +1,5 @@ +--- +title: Add install GitLab runner popup +merge_request: 42877 +author: +type: added diff --git a/changelogs/unreleased/job-dropdown-click.yml b/changelogs/unreleased/job-dropdown-click.yml new file mode 100644 index 00000000000..14e44273d5e --- /dev/null +++ b/changelogs/unreleased/job-dropdown-click.yml @@ -0,0 +1,5 @@ +--- +title: 'Job dropdown: Hide tooltip explicitly on click' +merge_request: 46465 +author: +type: fixed diff --git a/changelogs/unreleased/set-user-availability-be.yml b/changelogs/unreleased/set-user-availability-be.yml new file mode 100644 index 00000000000..39b821831c6 --- /dev/null +++ b/changelogs/unreleased/set-user-availability-be.yml @@ -0,0 +1,5 @@ +--- +title: Add availability to user status +merge_request: 45888 +author: +type: added diff --git a/config/feature_flags/development/lfs_link_existing_object.yml b/config/feature_flags/development/lfs_link_existing_object.yml deleted file mode 100644 index f38bb4525ec..00000000000 --- a/config/feature_flags/development/lfs_link_existing_object.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -name: lfs_link_existing_object -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41770 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/249246 -group: group::source code -type: development -default_enabled: true diff --git a/db/migrate/20201022103304_add_availability_to_user_statuses.rb b/db/migrate/20201022103304_add_availability_to_user_statuses.rb new file mode 100644 index 00000000000..9144c81fcfb --- /dev/null +++ b/db/migrate/20201022103304_add_availability_to_user_statuses.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class AddAvailabilityToUserStatuses < ActiveRecord::Migration[6.0] + DOWNTIME = false + + def change + add_column :user_statuses, :availability, :integer, limit: 2, default: 0, null: false + end +end diff --git a/db/schema_migrations/20201022103304 b/db/schema_migrations/20201022103304 new file mode 100644 index 00000000000..e54cb431bd4 --- /dev/null +++ b/db/schema_migrations/20201022103304 @@ -0,0 +1 @@ +aa15aad0b51f313f3cd59e1065023146fe53c6bd50319656ae992f8f43e1525e \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index b799ff61d74..15bcb7f7632 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -16782,7 +16782,8 @@ CREATE TABLE user_statuses ( cached_markdown_version integer, emoji character varying DEFAULT 'speech_balloon'::character varying NOT NULL, message character varying(100), - message_html character varying + message_html character varying, + availability smallint DEFAULT 0 NOT NULL ); CREATE SEQUENCE user_statuses_user_id_seq diff --git a/doc/.vale/gitlab/Acronyms.yml b/doc/.vale/gitlab/Acronyms.yml index 53690138300..4a6cb4ee479 100644 --- a/doc/.vale/gitlab/Acronyms.yml +++ b/doc/.vale/gitlab/Acronyms.yml @@ -95,6 +95,7 @@ exceptions: - URI - URL - USB + - UTC - UUID - VPC - WIP diff --git a/doc/administration/geo/index.md b/doc/administration/geo/index.md index 5ea53511458..10e5eb8cc61 100644 --- a/doc/administration/geo/index.md +++ b/doc/administration/geo/index.md @@ -116,6 +116,7 @@ The following are required to run Geo: - [Ubuntu](https://ubuntu.com) 16.04+ - PostgreSQL 11+ with [Streaming Replication](https://wiki.postgresql.org/wiki/Streaming_Replication) - Git 2.9+ +- Git-lfs 2.4.2+ on the user side when using LFS - All nodes must run the same GitLab version. Additionally, check GitLab's [minimum requirements](../../install/requirements.md), diff --git a/doc/administration/geo/replication/troubleshooting.md b/doc/administration/geo/replication/troubleshooting.md index b62c5c6f460..e60b9567c6f 100644 --- a/doc/administration/geo/replication/troubleshooting.md +++ b/doc/administration/geo/replication/troubleshooting.md @@ -782,3 +782,13 @@ To resolve this issue: using IPv6 to send its status to the **primary** node. If it is, add an entry to the **primary** node using IPv4 in the `/etc/hosts` file. Alternatively, you should [enable IPv6 on the **primary** node](https://docs.gitlab.com/omnibus/settings/nginx.html#setting-the-nginx-listen-address-or-addresses). + +## Fixing client errors + +### Authorization errors from LFS HTTP(s) client requests + +You may have problems if you're running a version of [Git LFS](https://git-lfs.github.com/) before 2.4.2. +As noted in [this authentication issue](https://github.com/git-lfs/git-lfs/issues/3025), +requests redirected from the secondary to the primary node do not properly send the +Authorization header. This may result in either an infinite `Authorization <-> Redirect` +loop, or Authorization errors. diff --git a/doc/administration/operations/moving_repositories.md b/doc/administration/operations/moving_repositories.md index 7074b696796..b311bee1a5b 100644 --- a/doc/administration/operations/moving_repositories.md +++ b/doc/administration/operations/moving_repositories.md @@ -12,15 +12,19 @@ another file system or another server. ## Moving data within a GitLab instance -The recommended way to move Git repositories between servers, between different storage, and -from unclustered to clustered Gitaly (Praefect) is using the API. +The GitLab API is the recommended way to move Git repositories: -Read more: +- Between servers. +- Between different storage. +- From single-node Gitaly to Gitaly Cluster. -- [Configuring additional storage for Gitaly](../gitaly/index.md#network-architecture) - - Within this example, additional storage called `storage1` and `storage2` is configured. -- [The API documentation](../../api/project_repository_storage_moves.md) details the endpoints for quering and scheduling repository moves. -- [Migrate existing repositories to Gitaly Cluster](../gitaly/praefect.md#migrate-existing-repositories-to-gitaly-cluster) +For more information, see: + +- [Configuring additional storage for Gitaly](../gitaly/index.md#network-architecture). Within this + example, additional storage called `storage1` and `storage2` is configured. +- [The API documentation](../../api/project_repository_storage_moves.md) details the endpoints for + querying and scheduling repository moves. +- [Migrate existing repositories to Gitaly Cluster](../gitaly/praefect.md#migrate-existing-repositories-to-gitaly-cluster). ### Limitations @@ -28,12 +32,13 @@ Read more in the [API documentation](../../api/project_repository_storage_moves. ## Migrating to another GitLab instance -Using the API isn't an option if you are migrating to a new GitLab environment, for example: +[Using the API](#moving-data-within-a-gitlab-instance) isn't an option if you are migrating to a new +GitLab environment, for example: - From a single-node GitLab to a scaled-out architecture. - From a GitLab instance in your private datacenter to a cloud provider. -The rest of the document will look +The rest of the document looks at some of the ways you can copy all your repositories from `/var/opt/gitlab/git-data/repositories` to `/mnt/gitlab/repositories`. @@ -49,10 +54,14 @@ Each of the approaches we list can or does overwrite data in the target director ### Recommended approach in all cases -GitLab's [backup and restore capability](../../raketasks/backup_restore.md) should be used. Git repositories are accessed, managed and stored on GitLab servers by the Gitaly component of the product as a database. Data loss can result from directly accessing and copying Gitaly's files using tools like `rsync`. +GitLab's [backup and restore capability](../../raketasks/backup_restore.md) should be used. Git +repositories are accessed, managed, and stored on GitLab servers by Gitaly as a database. Data loss +can result from directly accessing and copying Gitaly's files using tools like `rsync`. -- From GitLab 13.3, backup performance can be improved by [processing multiple repositories concurrently](../../raketasks/backup_restore.md#back-up-git-repositories-concurrently). -- Backups can be created of just the repositories using the [skip feature](../../raketasks/backup_restore.md#excluding-specific-directories-from-the-backup) +- From GitLab 13.3, backup performance can be improved by + [processing multiple repositories concurrently](../../raketasks/backup_restore.md#back-up-git-repositories-concurrently). +- Backups can be created of just the repositories using the + [skip feature](../../raketasks/backup_restore.md#excluding-specific-directories-from-the-backup). ### Target directory is empty: use a `tar` pipe @@ -86,8 +95,7 @@ If you want to compress the data before it goes over the network ### The target directory contains an outdated copy of the repositories: use `rsync` DANGER: **Warning:** -Using `rsync` to migrate -Git data can cause data loss and repository corruption. +Using `rsync` to migrate Git data can cause data loss and repository corruption. [These instructions are being reviewed](https://gitlab.com/gitlab-org/gitlab/-/issues/270422). If the target directory already contains a partial / outdated copy @@ -108,8 +116,7 @@ If you want to see progress, replace `-a` with `-av`. #### Single `rsync` to another server DANGER: **Warning:** -Using `rsync` to migrate -Git data can cause data loss and repository corruption. +Using `rsync` to migrate Git data can cause data loss and repository corruption. [These instructions are being reviewed](https://gitlab.com/gitlab-org/gitlab/-/issues/270422). If the `git` user on your source system has SSH access to the target @@ -123,8 +130,7 @@ sudo -u git sh -c 'rsync -a --delete /var/opt/gitlab/git-data/repositories/. \ ### Thousands of Git repositories: use one `rsync` per repository DANGER: **Warning:** -Using `rsync` to migrate -Git data can cause data loss and repository corruption. +Using `rsync` to migrate Git data can cause data loss and repository corruption. [These instructions are being reviewed](https://gitlab.com/gitlab-org/gitlab/-/issues/270422). Every time you start an `rsync` job it has to inspect all files in @@ -145,8 +151,7 @@ longer exist at the source.** #### Parallel `rsync` for all repositories known to GitLab DANGER: **Warning:** -Using `rsync` to migrate -Git data can cause data loss and repository corruption. +Using `rsync` to migrate Git data can cause data loss and repository corruption. [These instructions are being reviewed](https://gitlab.com/gitlab-org/gitlab/-/issues/270422). This syncs repositories with 10 `rsync` processes at a time. We keep @@ -207,8 +212,7 @@ cat /home/git/transfer-logs/* | sort | uniq -u |\ #### Parallel `rsync` only for repositories with recent activity DANGER: **Warning:** -Using `rsync` to migrate -Git data can cause data loss and repository corruption. +Using `rsync` to migrate Git data can cause data loss and repository corruption. [These instructions are being reviewed](https://gitlab.com/gitlab-org/gitlab/-/issues/270422). Suppose you have already done one sync that started after 2015-10-1 12:00 UTC. diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql index 3999f982a36..fd7890700f4 100644 --- a/doc/api/graphql/reference/gitlab_schema.graphql +++ b/doc/api/graphql/reference/gitlab_schema.graphql @@ -927,6 +927,21 @@ type AlertTodoCreatePayload { todo: Todo } +""" +User availability status +""" +enum AvailabilityEnum { + """ + Busy + """ + BUSY + + """ + Not Set + """ + NOT_SET +} + """ An emoji awarded by a user """ @@ -19319,6 +19334,11 @@ type TerraformState { """ id: ID! + """ + The latest version of the Terraform state + """ + latestVersion: TerraformStateVersion + """ Timestamp the Terraform state was locked """ @@ -19475,6 +19495,28 @@ type TerraformStateUnlockPayload { errors: [String!]! } +type TerraformStateVersion { + """ + Timestamp the version was created + """ + createdAt: Time! + + """ + The user that created this version + """ + createdByUser: User + + """ + ID of the Terraform state version + """ + id: ID! + + """ + Timestamp the version was updated + """ + updatedAt: Time! +} + """ Represents the Geo sync and verification state of a terraform state version """ @@ -21450,6 +21492,11 @@ enum UserState { } type UserStatus { + """ + User availability status + """ + availability: AvailabilityEnum! + """ String representation of emoji """ diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json index 0b4f3652cc8..0d723445d75 100644 --- a/doc/api/graphql/reference/gitlab_schema.json +++ b/doc/api/graphql/reference/gitlab_schema.json @@ -2391,6 +2391,29 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "ENUM", + "name": "AvailabilityEnum", + "description": "User availability status", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": [ + { + "name": "NOT_SET", + "description": "Not Set", + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "BUSY", + "description": "Busy", + "isDeprecated": false, + "deprecationReason": null + } + ], + "possibleTypes": null + }, { "kind": "OBJECT", "name": "AwardEmoji", @@ -56011,6 +56034,20 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "latestVersion", + "description": "The latest version of the Terraform state", + "args": [ + + ], + "type": { + "kind": "OBJECT", + "name": "TerraformStateVersion", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "lockedAt", "description": "Timestamp the Terraform state was locked", @@ -56487,6 +56524,87 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "OBJECT", + "name": "TerraformStateVersion", + "description": null, + "fields": [ + { + "name": "createdAt", + "description": "Timestamp the version was created", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Time", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "createdByUser", + "description": "The user that created this version", + "args": [ + + ], + "type": { + "kind": "OBJECT", + "name": "User", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id", + "description": "ID of the Terraform state version", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "updatedAt", + "description": "Timestamp the version was updated", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Time", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + + ], + "enumValues": null, + "possibleTypes": null + }, { "kind": "OBJECT", "name": "TerraformStateVersionRegistry", @@ -62028,6 +62146,24 @@ "name": "UserStatus", "description": null, "fields": [ + { + "name": "availability", + "description": "User availability status", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "AvailabilityEnum", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "emoji", "description": "String representation of emoji", diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 5e960f293bd..2e88624a550 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -2683,6 +2683,7 @@ Completion status of tasks. | ----- | ---- | ----------- | | `createdAt` | Time! | Timestamp the Terraform state was created | | `id` | ID! | ID of the Terraform state | +| `latestVersion` | TerraformStateVersion | The latest version of the Terraform state | | `lockedAt` | Time | Timestamp the Terraform state was locked | | `lockedByUser` | User | The user currently holding a lock on the Terraform state | | `name` | String! | Name of the Terraform state | @@ -2715,6 +2716,15 @@ Autogenerated return type of TerraformStateUnlock. | `clientMutationId` | String | A unique identifier for the client performing the mutation. | | `errors` | String! => Array | Errors encountered during execution of the mutation. | +### TerraformStateVersion + +| Field | Type | Description | +| ----- | ---- | ----------- | +| `createdAt` | Time! | Timestamp the version was created | +| `createdByUser` | User | The user that created this version | +| `id` | ID! | ID of the Terraform state version | +| `updatedAt` | Time! | Timestamp the version was updated | + ### TerraformStateVersionRegistry Represents the Geo sync and verification state of a terraform state version. @@ -2990,6 +3000,7 @@ Autogenerated return type of UpdateSnippet. | Field | Type | Description | | ----- | ---- | ----------- | +| `availability` | AvailabilityEnum! | User availability status | | `emoji` | String | String representation of emoji | | `message` | String | User status message | | `messageHtml` | String | HTML of the user status message | @@ -3318,6 +3329,15 @@ Alert status values. | `RESOLVED` | Resolved status | | `TRIGGERED` | Triggered status | +### AvailabilityEnum + +User availability status. + +| Value | Description | +| ----- | ----------- | +| `BUSY` | Busy | +| `NOT_SET` | Not Set | + ### BlobViewersType Types of blob viewers. diff --git a/doc/api/project_repository_storage_moves.md b/doc/api/project_repository_storage_moves.md index d9be616e4c1..50683a7b815 100644 --- a/doc/api/project_repository_storage_moves.md +++ b/doc/api/project_repository_storage_moves.md @@ -32,8 +32,8 @@ This API requires you to [authenticate yourself](README.md#authentication) as an ## Limitations -- [The repositories associated with snippets can't currently be moved with the API](https://gitlab.com/groups/gitlab-org/-/epics/3393). -- [Group level wikis can't currently be moved with the API](https://gitlab.com/gitlab-org/gitlab/-/issues/219003). +- The repositories associated with snippets [can't be moved with the API](https://gitlab.com/groups/gitlab-org/-/epics/3393). +- Group-level wikis [can't be moved with the API](https://gitlab.com/gitlab-org/gitlab/-/issues/219003). ## Retrieve all project repository storage moves diff --git a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md index 45cae49377f..86c66b5ea2d 100644 --- a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md +++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md @@ -208,8 +208,8 @@ ask an administrator to execute the following commands: ```shell > sudo gitlab-rails console # Login to Rails console of GitLab instance. > Feature.enabled?(:disable_merge_trains) # Check if it's disabled or not. -> Feature.enable(:disable_merge_trains) # Disable Merge Trains. -> Feature.disable(:disable_merge_trains) # Enable Merge Trains. +> Feature.enable(:disable_merge_trains) # Enable Merge Trains. +> Feature.disable(:disable_merge_trains) # Disable Merge Trains. ``` When you disable this feature, all existing merge trains are cancelled and diff --git a/doc/operations/incident_management/incidents.md b/doc/operations/incident_management/incidents.md index f397b03fe37..0e463735566 100644 --- a/doc/operations/incident_management/incidents.md +++ b/doc/operations/incident_management/incidents.md @@ -6,7 +6,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w # Incidents -Incidents are critical entities in incident management workflows. They represent a service disruption or outage that needs to be restored urgently. GitLab provides tools for the triage, response, and remediation of incidents. +Incidents are critical entities in incident management workflows. They represent +a service disruption or outage that needs to be restored urgently. GitLab provides +tools for the triage, response, and remediation of incidents. ## Incident Creation @@ -14,7 +16,8 @@ You can create an incident manually or automatically. ### Create incidents manually -If you have at least Guest [permissions](../../user/permissions.md), to create an Incident, you have two options to do this manually. +If you have at least Guest [permissions](../../user/permissions.md), to create an +Incident, you have two options to do this manually. **From the Incidents List:** @@ -43,17 +46,17 @@ If you have at least Guest [permissions](../../user/permissions.md), to create a With Maintainer or higher [permissions](../../user/permissions.md), you can enable GitLab to create incident automatically whenever an alert is triggered: -1. Navigate to **Settings > Operations > Incidents** and expand - **Incidents**: +1. Navigate to **Settings > Operations > Incidents** and expand **Incidents**: ![Incident Management Settings](./img/incident_management_settings_v13_3.png) -1. Check the **Create an incident** - checkbox. -1. To customize the incident, select an [issue templates](../../user/project/description_templates.md#creating-issue-templates). +1. Check the **Create an incident** checkbox. +1. To customize the incident, select an + [issue template](../../user/project/description_templates.md#creating-issue-templates). 1. To send [an email notification](alert_notifications.md#email-notifications) to users with [Developer permissions](../../user/permissions.md), select - **Send a separate email notification to Developers**. Email notifications will also be sent to users with **Maintainer** and **Owner** permissions. + **Send a separate email notification to Developers**. Email notifications are + also sent to users with **Maintainer** and **Owner** permissions. 1. Click **Save changes**. ### Create incidents via the PagerDuty webhook @@ -183,10 +186,22 @@ un-threaded and ordered chronologically, newest to oldest: > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/241663) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.5. -After enabling **Incident SLA** in the Incident Management configuration, newly-created -incidents display a SLA (Service Level Agreement) timer showing the time remaining before -the SLA period expires. If the incident is not closed before the SLA period ends, GitLab -adds a `missed::SLA` label to the incident. +You can enable the Service Level Agreement Countdown timer on incidents to track +the Service Level Agreements (SLAs) you hold with your customers. The timer is +automatically started when the incident is created, and shows the time +remaining before the SLA period expires. To configure the timer: + +1. Navigate to **Settings > Operations**. +1. Scroll to **Incidents** and click **Expand**, then select the + **Incident settings** tab. +1. Select **Activate "time to SLA" countdown timer**. +1. Set a time limit in increments of 15 minutes. +1. Click **Save changes**. + +After you enable the SLA countdown timer, the **Time to SLA** attribute is displayed +as a column in the Incidents List, and as a field on newly created Incidents. If +the incident isn't closed before the SLA period ends, GitLab adds a `missed::SLA` +label to the incident. ## Incident Actions @@ -194,15 +209,18 @@ There are different actions available to help triage and respond to incidents. ### Assign incidents -Assign incidents to users that are actively responding. Select **Edit** in the right-hand side bar to select or deselect assignees. +Assign incidents to users that are actively responding. Select **Edit** in the +right-hand side bar to select or deselect assignees. ### Change severity -See [Incident List](#incident-list) for a full description of the severities available. Select **Edit** in the right-hand side bar to change the severity of an incident. +See [Incident List](#incident-list) for a full description of the severity levels available. +Select **Edit** in the right-hand side bar to change the severity of an incident. ### Add a to-do item -Add a to-do for incidents that you want to track in your to-do list. Click the **Add a to do** button at the top of the right-hand side bar to add a to-do item. +Add a to-do for incidents that you want to track in your to-do list. Click the +**Add a to do** button at the top of the right-hand side bar to add a to-do item. ### Manage incidents from Slack diff --git a/doc/update/README.md b/doc/update/README.md index b5e99671278..901e187d2f5 100644 --- a/doc/update/README.md +++ b/doc/update/README.md @@ -263,9 +263,9 @@ with the older Rails version - which could cause non-GET requests to fail for [multi-node GitLab installations](https://docs.gitlab.com/omnibus/update/#multi-node--ha-deployment). So, if you are using multiple Rails servers and specifically upgrading from 13.0, -all servers must first be upgraded to 13.1.0 before upgrading to later versions: +all servers must first be upgraded to 13.1.X before upgrading to 13.2.0 or later: -1. Ensure all GitLab web nodes are on GitLab 13.1.0. +1. Ensure all GitLab web nodes are on GitLab 13.1.X. 1. Optionally, enable the `global_csrf_token` feature flag to enable new method of CSRF token generation: diff --git a/doc/user/group/index.md b/doc/user/group/index.md index 2c838724cb3..35e6f3b4136 100644 --- a/doc/user/group/index.md +++ b/doc/user/group/index.md @@ -414,8 +414,13 @@ There are a few limitations compared to project wikis: - Local Git access is not supported yet. - Group wikis are not included in global search, group exports, backups, and Geo replication. - Changes to group wikis don't show up in the group's activity feed. +- Group wikis [can't be moved](../../api/project_repository_storage_moves.md#limitations) using the project + repository moves API. -You can follow [this epic](https://gitlab.com/groups/gitlab-org/-/epics/2782) for updates. +For updates, you can follow: + +- [The epic tracking feature parity with project wikis](https://gitlab.com/groups/gitlab-org/-/epics/2782). +- [The issue for adding the ability to move group wikis using the API](https://gitlab.com/gitlab-org/gitlab/-/issues/219003). ### Enable or disable group wikis **(CORE ONLY)** diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md index f7275cec97c..92d31853d0b 100644 --- a/doc/user/project/clusters/index.md +++ b/doc/user/project/clusters/index.md @@ -47,7 +47,8 @@ version. The range of supported versions is based on the evaluation of: - The versions supported by major managed Kubernetes providers. - The versions [supported by the Kubernetes community](https://kubernetes.io/docs/setup/release/version-skew-policy/#supported-versions). -Currently, GitLab supports the following Kubernetes versions: +GitLab supports the following Kubernetes versions, and you can upgrade your +Kubernetes version to any supported version at any time: - 1.17 - 1.16 diff --git a/lib/api/discussions.rb b/lib/api/discussions.rb index 3d2608c8c5a..4c4ec200060 100644 --- a/lib/api/discussions.rb +++ b/lib/api/discussions.rb @@ -8,7 +8,7 @@ module API before { authenticate! } - Helpers::DiscussionsHelpers.noteable_types.each do |noteable_type| + Helpers::DiscussionsHelpers.feature_category_per_noteable_type.each do |noteable_type, feature_category| parent_type = noteable_type.parent_class.to_s.underscore noteables_str = noteable_type.to_s.underscore.pluralize noteables_path = noteable_type == Commit ? "repository/#{noteables_str}" : noteables_str @@ -25,7 +25,7 @@ module API use :pagination end - get ":id/#{noteables_path}/:noteable_id/discussions" do + get ":id/#{noteables_path}/:noteable_id/discussions", feature_category: feature_category do noteable = find_noteable(noteable_type, params[:noteable_id]) discussion_ids = paginate(noteable.discussion_ids_relation) @@ -41,7 +41,7 @@ module API requires :discussion_id, type: String, desc: 'The ID of a discussion' requires :noteable_id, types: [Integer, String], desc: 'The ID of the noteable' end - get ":id/#{noteables_path}/:noteable_id/discussions/:discussion_id" do + get ":id/#{noteables_path}/:noteable_id/discussions/:discussion_id", feature_category: feature_category do noteable = find_noteable(noteable_type, params[:noteable_id]) notes = readable_discussion_notes(noteable, params[:discussion_id]) @@ -91,7 +91,7 @@ module API end end end - post ":id/#{noteables_path}/:noteable_id/discussions" do + post ":id/#{noteables_path}/:noteable_id/discussions", feature_category: feature_category do noteable = find_noteable(noteable_type, params[:noteable_id]) type = params[:position] ? 'DiffNote' : 'DiscussionNote' id_key = noteable.is_a?(Commit) ? :commit_id : :noteable_id @@ -121,7 +121,7 @@ module API requires :discussion_id, type: String, desc: 'The ID of a discussion' requires :noteable_id, types: [Integer, String], desc: 'The ID of the noteable' end - get ":id/#{noteables_path}/:noteable_id/discussions/:discussion_id/notes" do + get ":id/#{noteables_path}/:noteable_id/discussions/:discussion_id/notes", feature_category: feature_category do noteable = find_noteable(noteable_type, params[:noteable_id]) notes = readable_discussion_notes(noteable, params[:discussion_id]) @@ -141,7 +141,7 @@ module API requires :body, type: String, desc: 'The content of a note' optional :created_at, type: String, desc: 'The creation date of the note' end - post ":id/#{noteables_path}/:noteable_id/discussions/:discussion_id/notes" do + post ":id/#{noteables_path}/:noteable_id/discussions/:discussion_id/notes", feature_category: feature_category do noteable = find_noteable(noteable_type, params[:noteable_id]) notes = readable_discussion_notes(noteable, params[:discussion_id]) first_note = notes.first @@ -175,7 +175,7 @@ module API requires :discussion_id, type: String, desc: 'The ID of a discussion' requires :note_id, type: Integer, desc: 'The ID of a note' end - get ":id/#{noteables_path}/:noteable_id/discussions/:discussion_id/notes/:note_id" do + get ":id/#{noteables_path}/:noteable_id/discussions/:discussion_id/notes/:note_id", feature_category: feature_category do noteable = find_noteable(noteable_type, params[:noteable_id]) get_note(noteable, params[:note_id]) @@ -192,7 +192,7 @@ module API optional :resolved, type: Boolean, desc: 'Mark note resolved/unresolved' exactly_one_of :body, :resolved end - put ":id/#{noteables_path}/:noteable_id/discussions/:discussion_id/notes/:note_id" do + put ":id/#{noteables_path}/:noteable_id/discussions/:discussion_id/notes/:note_id", feature_category: feature_category do noteable = find_noteable(noteable_type, params[:noteable_id]) if params[:resolved].nil? @@ -210,7 +210,7 @@ module API requires :discussion_id, type: String, desc: 'The ID of a discussion' requires :note_id, type: Integer, desc: 'The ID of a note' end - delete ":id/#{noteables_path}/:noteable_id/discussions/:discussion_id/notes/:note_id" do + delete ":id/#{noteables_path}/:noteable_id/discussions/:discussion_id/notes/:note_id", feature_category: feature_category do noteable = find_noteable(noteable_type, params[:noteable_id]) delete_note(noteable, params[:note_id]) @@ -225,7 +225,7 @@ module API requires :discussion_id, type: String, desc: 'The ID of a discussion' requires :resolved, type: Boolean, desc: 'Mark discussion resolved/unresolved' end - put ":id/#{noteables_path}/:noteable_id/discussions/:discussion_id" do + put ":id/#{noteables_path}/:noteable_id/discussions/:discussion_id", feature_category: feature_category do noteable = find_noteable(noteable_type, params[:noteable_id]) resolve_discussion(noteable, params[:discussion_id], params[:resolved]) diff --git a/lib/api/entities/user_status.rb b/lib/api/entities/user_status.rb index 9bc4cbf240f..1d5cc27e5ef 100644 --- a/lib/api/entities/user_status.rb +++ b/lib/api/entities/user_status.rb @@ -5,6 +5,7 @@ module API class UserStatus < Grape::Entity expose :emoji expose :message + expose :availability expose :message_html do |entity| MarkupHelper.markdown_field(entity, :message) end diff --git a/lib/api/helpers/discussions_helpers.rb b/lib/api/helpers/discussions_helpers.rb index 799d5582b38..3c0db1d0ea9 100644 --- a/lib/api/helpers/discussions_helpers.rb +++ b/lib/api/helpers/discussions_helpers.rb @@ -3,10 +3,15 @@ module API module Helpers module DiscussionsHelpers - def self.noteable_types + def self.feature_category_per_noteable_type # This is a method instead of a constant, allowing EE to more easily # extend it. - [Issue, Snippet, MergeRequest, Commit] + { + Issue => :issue_tracking, + Snippet => :snippets, + MergeRequest => :code_review, + Commit => :code_review + } end end end diff --git a/lib/api/helpers/notes_helpers.rb b/lib/api/helpers/notes_helpers.rb index f61bcfe963e..6798c4d284b 100644 --- a/lib/api/helpers/notes_helpers.rb +++ b/lib/api/helpers/notes_helpers.rb @@ -5,10 +5,12 @@ module API module NotesHelpers include ::RendersNotes - def self.noteable_types - # This is a method instead of a constant, allowing EE to more easily - # extend it. - [Issue, MergeRequest, Snippet] + def self.feature_category_per_noteable_type + { + Issue => :issue_tracking, + MergeRequest => :code_review, + Snippet => :snippets + } end def update_note(noteable, note_id) diff --git a/lib/api/import_bitbucket_server.rb b/lib/api/import_bitbucket_server.rb index a0238c24f3b..ecd78c6e6db 100644 --- a/lib/api/import_bitbucket_server.rb +++ b/lib/api/import_bitbucket_server.rb @@ -2,6 +2,8 @@ module API class ImportBitbucketServer < ::API::Base + feature_category :importers + helpers do def client @client ||= BitbucketServer::Client.new(credentials) diff --git a/lib/api/import_github.rb b/lib/api/import_github.rb index f3894818f28..c91a7700f58 100644 --- a/lib/api/import_github.rb +++ b/lib/api/import_github.rb @@ -2,6 +2,8 @@ module API class ImportGithub < ::API::Base + feature_category :importers + rescue_from Octokit::Unauthorized, with: :provider_unauthorized before do diff --git a/lib/api/issue_links.rb b/lib/api/issue_links.rb index db4979c9052..e938dbbae87 100644 --- a/lib/api/issue_links.rb +++ b/lib/api/issue_links.rb @@ -6,6 +6,8 @@ module API before { authenticate! } + feature_category :issue_tracking + params do requires :id, type: String, desc: 'The ID of a project' requires :issue_iid, type: Integer, desc: 'The internal ID of a project issue' diff --git a/lib/api/issues.rb b/lib/api/issues.rb index 25fce1bf473..864952d160e 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -6,10 +6,10 @@ module API helpers Helpers::IssuesHelpers helpers Helpers::RateLimiter - feature_category :issue_tracking - before { authenticate_non_get! } + feature_category :issue_tracking + helpers do params :negatable_issue_filter_params do optional :labels, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'Comma-separated list of label names' diff --git a/lib/api/job_artifacts.rb b/lib/api/job_artifacts.rb index 536b361b308..1faa28d6f07 100644 --- a/lib/api/job_artifacts.rb +++ b/lib/api/job_artifacts.rb @@ -4,6 +4,8 @@ module API class JobArtifacts < ::API::Base before { authenticate_non_get! } + feature_category :continuous_integration + # EE::API::JobArtifacts would override the following helpers helpers do def authorize_download_artifacts! diff --git a/lib/api/jobs.rb b/lib/api/jobs.rb index bdb23b4a9be..51659c2e8a1 100644 --- a/lib/api/jobs.rb +++ b/lib/api/jobs.rb @@ -6,6 +6,8 @@ module API before { authenticate! } + feature_category :continuous_integration + params do requires :id, type: String, desc: 'The ID of a project' end diff --git a/lib/api/keys.rb b/lib/api/keys.rb index 2e4568029b5..fb1bedd5e92 100644 --- a/lib/api/keys.rb +++ b/lib/api/keys.rb @@ -5,6 +5,8 @@ module API class Keys < ::API::Base before { authenticate! } + feature_category :authentication_and_authorization + resource :keys do desc 'Get single ssh key by id. Only available to admin users' do success Entities::SSHKeyWithUser diff --git a/lib/api/labels.rb b/lib/api/labels.rb index c9a75583cee..a8fc277989e 100644 --- a/lib/api/labels.rb +++ b/lib/api/labels.rb @@ -7,6 +7,8 @@ module API before { authenticate! } + feature_category :issue_tracking + params do requires :id, type: String, desc: 'The ID of a project' end diff --git a/lib/api/lint.rb b/lib/api/lint.rb index bfd152f70b1..ac8cc49c986 100644 --- a/lib/api/lint.rb +++ b/lib/api/lint.rb @@ -2,6 +2,8 @@ module API class Lint < ::API::Base + feature_category :pipeline_authoring + namespace :ci do desc 'Validation of .gitlab-ci.yml content' params do diff --git a/lib/api/markdown.rb b/lib/api/markdown.rb index 97549abd273..de612ff8321 100644 --- a/lib/api/markdown.rb +++ b/lib/api/markdown.rb @@ -2,6 +2,8 @@ module API class Markdown < ::API::Base + feature_category :not_owned + params do requires :text, type: String, desc: "The markdown text to render" optional :gfm, type: Boolean, desc: "Render text using GitLab Flavored Markdown" diff --git a/lib/api/members.rb b/lib/api/members.rb index c28b3b1cc7c..f2405589280 100644 --- a/lib/api/members.rb +++ b/lib/api/members.rb @@ -6,6 +6,8 @@ module API before { authenticate! } + feature_category :authentication_and_authorization + helpers ::API::Helpers::MembersHelpers %w[group project].each do |source_type| diff --git a/lib/api/merge_request_approvals.rb b/lib/api/merge_request_approvals.rb index 14d6e3995ea..27ef0b9c7cd 100644 --- a/lib/api/merge_request_approvals.rb +++ b/lib/api/merge_request_approvals.rb @@ -4,6 +4,8 @@ module API class MergeRequestApprovals < ::API::Base before { authenticate_non_get! } + feature_category :code_review + helpers do params :ee_approval_params do end diff --git a/lib/api/merge_request_diffs.rb b/lib/api/merge_request_diffs.rb index 22023888bbd..0ffb38438eb 100644 --- a/lib/api/merge_request_diffs.rb +++ b/lib/api/merge_request_diffs.rb @@ -7,6 +7,8 @@ module API before { authenticate! } + feature_category :code_review + params do requires :id, type: String, desc: 'The ID of a project' end diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index b24dd870c8b..d9640d95e32 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -8,6 +8,8 @@ module API before { authenticate_non_get! } + feature_category :code_review + helpers Helpers::MergeRequestsHelpers # EE::API::MergeRequests would override the following helpers diff --git a/lib/api/metrics/dashboard/annotations.rb b/lib/api/metrics/dashboard/annotations.rb index b6bc0af2202..0989340b3ea 100644 --- a/lib/api/metrics/dashboard/annotations.rb +++ b/lib/api/metrics/dashboard/annotations.rb @@ -4,6 +4,8 @@ module API module Metrics module Dashboard class Annotations < ::API::Base + feature_category :metrics + desc 'Create a new monitoring dashboard annotation' do success Entities::Metrics::Dashboard::Annotation end diff --git a/lib/api/metrics/user_starred_dashboards.rb b/lib/api/metrics/user_starred_dashboards.rb index cb6e7099247..909f7f0405d 100644 --- a/lib/api/metrics/user_starred_dashboards.rb +++ b/lib/api/metrics/user_starred_dashboards.rb @@ -3,6 +3,8 @@ module API module Metrics class UserStarredDashboards < ::API::Base + feature_category :metrics + resource :projects do desc 'Marks selected metrics dashboard as starred' do success Entities::Metrics::UserStarredDashboard diff --git a/lib/api/namespaces.rb b/lib/api/namespaces.rb index f98a1f6dd1d..25a901c18b6 100644 --- a/lib/api/namespaces.rb +++ b/lib/api/namespaces.rb @@ -6,6 +6,8 @@ module API before { authenticate! } + feature_category :subgroups + helpers do params :optional_list_params_ee do # EE::API::Namespaces would override this helper diff --git a/lib/api/notes.rb b/lib/api/notes.rb index 0db537ca616..d249431b2f8 100644 --- a/lib/api/notes.rb +++ b/lib/api/notes.rb @@ -7,7 +7,7 @@ module API before { authenticate! } - Helpers::NotesHelpers.noteable_types.each do |noteable_type| + Helpers::NotesHelpers.feature_category_per_noteable_type.each do |noteable_type, feature_category| parent_type = noteable_type.parent_class.to_s.underscore noteables_str = noteable_type.to_s.underscore.pluralize @@ -29,7 +29,7 @@ module API use :pagination end # rubocop: disable CodeReuse/ActiveRecord - get ":id/#{noteables_str}/:noteable_id/notes" do + get ":id/#{noteables_str}/:noteable_id/notes", feature_category: feature_category do noteable = find_noteable(noteable_type, params[:noteable_id]) # We exclude notes that are cross-references and that cannot be viewed @@ -57,7 +57,7 @@ module API requires :note_id, type: Integer, desc: 'The ID of a note' requires :noteable_id, type: Integer, desc: 'The ID of the noteable' end - get ":id/#{noteables_str}/:noteable_id/notes/:note_id" do + get ":id/#{noteables_str}/:noteable_id/notes/:note_id", feature_category: feature_category do noteable = find_noteable(noteable_type, params[:noteable_id]) get_note(noteable, params[:note_id]) end @@ -71,7 +71,7 @@ module API optional :confidential, type: Boolean, desc: 'Confidentiality note flag, default is false' optional :created_at, type: String, desc: 'The creation date of the note' end - post ":id/#{noteables_str}/:noteable_id/notes" do + post ":id/#{noteables_str}/:noteable_id/notes", feature_category: feature_category do noteable = find_noteable(noteable_type, params[:noteable_id]) opts = { @@ -104,7 +104,7 @@ module API optional :body, type: String, allow_blank: false, desc: 'The content of a note' optional :confidential, type: Boolean, desc: 'Confidentiality note flag' end - put ":id/#{noteables_str}/:noteable_id/notes/:note_id" do + put ":id/#{noteables_str}/:noteable_id/notes/:note_id", feature_category: feature_category do noteable = find_noteable(noteable_type, params[:noteable_id]) update_note(noteable, params[:note_id]) diff --git a/lib/api/users.rb b/lib/api/users.rb index 2f54b8c0fae..54228373512 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -952,6 +952,7 @@ module API params do optional :emoji, type: String, desc: "The emoji to set on the status" optional :message, type: String, desc: "The status message to set" + optional :availability, type: String, desc: "The availability of user to set" end put "status", feature_category: :users do forbidden! unless can?(current_user, :update_user_status, current_user) diff --git a/lib/gitlab/repository_size_checker.rb b/lib/gitlab/repository_size_checker.rb index dbfec77cb18..64d58c15208 100644 --- a/lib/gitlab/repository_size_checker.rb +++ b/lib/gitlab/repository_size_checker.rb @@ -37,7 +37,9 @@ module Gitlab # @param change_size [int] in bytes def exceeded_size(change_size = 0) - current_size + change_size - limit + size = current_size + change_size - limit + + [size, 0].max end def error_message diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 5c31006122e..2f9183700a3 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -2831,6 +2831,9 @@ msgstr "" msgid "An error has occurred" msgstr "" +msgid "An error has occurred fetching instructions" +msgstr "" + msgid "An error occured while making the changes: %{error}" msgstr "" @@ -3952,6 +3955,12 @@ msgstr "" msgid "AutoDevOps|The Auto DevOps pipeline has been enabled and will be used if no alternative CI configuration file is found." msgstr "" +msgid "AutoRemediation|%{mrsCount} ready for review" +msgstr "" + +msgid "AutoRemediation|Auto-fix solutions" +msgstr "" + msgid "AutoRemediation|If you're using dependency and/or container scanning, and auto-fix is enabled, auto-fix automatically creates merge requests with fixes to vulnerabilities." msgstr "" @@ -14215,6 +14224,9 @@ msgstr "" msgid "Install Runner on Kubernetes" msgstr "" +msgid "Install a Runner" +msgstr "" + msgid "Install a soft token authenticator like %{free_otp_link} or Google Authenticator from your application repository and use that app to scan this QR code. More information is available in the %{help_link_start}documentation%{help_link_end}." msgstr "" @@ -22974,6 +22986,12 @@ msgstr "" msgid "Runners|Description" msgstr "" +msgid "Runners|Download Latest Binary" +msgstr "" + +msgid "Runners|Download and Install Binary" +msgstr "" + msgid "Runners|Group" msgstr "" @@ -23001,6 +23019,9 @@ msgstr "" msgid "Runners|Protected" msgstr "" +msgid "Runners|Register Runner" +msgstr "" + msgid "Runners|Revision" msgstr "" @@ -24408,6 +24429,9 @@ msgstr "" msgid "Should you ever lose your phone or access to your one time password secret, each of these recovery codes can be used one time each to regain access to your account. Please save them in a safe place, or you %{b_start}will%{b_end} lose access to your account." msgstr "" +msgid "Show Runner installation instructions" +msgstr "" + msgid "Show all activity" msgstr "" diff --git a/package.json b/package.json index c9a13178f0d..a9cb06b6487 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "mock-apollo-client": "^0.4.0", "monaco-editor": "^0.20.0", "monaco-editor-webpack-plugin": "^1.9.0", - "monaco-yaml": "^2.4.1", + "monaco-yaml": "^2.5.1", "mousetrap": "1.6.5", "pdfjs-dist": "^2.0.943", "pikaday": "^1.8.0", diff --git a/public/robots.txt b/public/robots.txt index 50bddbc5a77..4029cae5145 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -36,6 +36,7 @@ User-Agent: * Disallow: /*/new Disallow: /*/edit Disallow: /*/raw +Disallow: /*/realtime_changes # Group details User-Agent: * diff --git a/scripts/lint-doc.sh b/scripts/lint-doc.sh index 87256269de2..9d6a4dbccee 100755 --- a/scripts/lint-doc.sh +++ b/scripts/lint-doc.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -cd "$(dirname "$0")/.." +cd "$(dirname "$0")/.." || exit 1 echo "=> Linting documents at path $(pwd) as $(whoami)..." echo ERRORCODE=0 diff --git a/spec/controllers/profiles_controller_spec.rb b/spec/controllers/profiles_controller_spec.rb index 249e6322d1c..7a72a13febe 100644 --- a/spec/controllers/profiles_controller_spec.rb +++ b/spec/controllers/profiles_controller_spec.rb @@ -84,9 +84,10 @@ RSpec.describe ProfilesController, :request_store do it 'allows setting a user status' do sign_in(user) - put :update, params: { user: { status: { message: 'Working hard!' } } } + put :update, params: { user: { status: { message: 'Working hard!', availability: 'busy' } } } expect(user.reload.status.message).to eq('Working hard!') + expect(user.reload.status.availability).to eq('busy') expect(response).to have_gitlab_http_status(:found) end diff --git a/spec/factories/terraform/state.rb b/spec/factories/terraform/state.rb index e5cea9e252e..c54a8aedbc6 100644 --- a/spec/factories/terraform/state.rb +++ b/spec/factories/terraform/state.rb @@ -19,7 +19,7 @@ FactoryBot.define do trait :with_version do after(:create) do |state| - create(:terraform_state_version, :with_file, terraform_state: state) + create(:terraform_state_version, terraform_state: state) end end diff --git a/spec/frontend/alerts_settings/alerts_integrations_list_spec.js b/spec/frontend/alerts_settings/alerts_integrations_list_spec.js index 4377cd0a60d..5d1feffe84a 100644 --- a/spec/frontend/alerts_settings/alerts_integrations_list_spec.js +++ b/spec/frontend/alerts_settings/alerts_integrations_list_spec.js @@ -8,12 +8,12 @@ import { trackAlertIntegrationsViewsOptions } from '~/alerts_settings/constants' const mockIntegrations = [ { - activated: true, + active: true, name: 'Integration 1', type: 'HTTP endpoint', }, { - activated: false, + active: false, name: 'Integration 2', type: 'HTTP endpoint', }, diff --git a/spec/frontend/alerts_settings/alerts_settings_form_new_spec.js b/spec/frontend/alerts_settings/alerts_settings_form_new_spec.js index ae12f6c9bef..50038ecb9ff 100644 --- a/spec/frontend/alerts_settings/alerts_settings_form_new_spec.js +++ b/spec/frontend/alerts_settings/alerts_settings_form_new_spec.js @@ -3,8 +3,6 @@ import { GlForm, GlFormSelect, GlCollapse, GlFormInput } from '@gitlab/ui'; import AlertsSettingsForm from '~/alerts_settings/components/alerts_settings_form_new.vue'; import { defaultAlertSettingsConfig } from './util'; -jest.mock('~/alerts_settings/services'); - describe('AlertsSettingsFormNew', () => { let wrapper; diff --git a/spec/frontend/alerts_settings/alerts_settings_wrapper_spec.js b/spec/frontend/alerts_settings/alerts_settings_wrapper_spec.js index 74f3aa1d995..8c289cb0f1c 100644 --- a/spec/frontend/alerts_settings/alerts_settings_wrapper_spec.js +++ b/spec/frontend/alerts_settings/alerts_settings_wrapper_spec.js @@ -1,17 +1,20 @@ -import { shallowMount } from '@vue/test-utils'; +import { mount } from '@vue/test-utils'; +import { GlLoadingIcon } from '@gitlab/ui'; import AlertsSettingsWrapper from '~/alerts_settings/components/alerts_settings_wrapper.vue'; import AlertsSettingsFormOld from '~/alerts_settings/components/alerts_settings_form_old.vue'; import AlertsSettingsFormNew from '~/alerts_settings/components/alerts_settings_form_new.vue'; import IntegrationsList from '~/alerts_settings/components/alerts_integrations_list.vue'; import { defaultAlertSettingsConfig } from './util'; +import mockIntegrations from './mocks/integrations.json'; -jest.mock('~/alerts_settings/services'); - -describe('AlertsSettingsFormWrapper', () => { +describe('AlertsSettingsWrapper', () => { let wrapper; - const createComponent = (data = {}, provide = {}) => { - wrapper = shallowMount(AlertsSettingsWrapper, { + const findLoader = () => wrapper.find(IntegrationsList).find(GlLoadingIcon); + const findIntegrations = () => wrapper.find(IntegrationsList).findAll('table tbody tr'); + + const createComponent = ({ data = {}, provide = {}, loading = false } = {}) => { + wrapper = mount(AlertsSettingsWrapper, { data() { return { ...data }; }, @@ -20,6 +23,16 @@ describe('AlertsSettingsFormWrapper', () => { glFeatures: { httpIntegrationsList: false }, ...provide, }, + mocks: { + $apollo: { + query: jest.fn(), + queries: { + integrations: { + loading, + }, + }, + }, + }, }); }; @@ -30,19 +43,41 @@ describe('AlertsSettingsFormWrapper', () => { } }); - describe('with default values', () => { - it('renders alerts integrations list and old form by default', () => { + describe('with httpIntegrationsList feature flag disabled', () => { + it('renders data driven alerts integrations list and old form by default', () => { createComponent(); expect(wrapper.find(IntegrationsList).exists()).toBe(true); expect(wrapper.find(AlertsSettingsFormOld).exists()).toBe(true); expect(wrapper.find(AlertsSettingsFormNew).exists()).toBe(false); }); + }); - it('renders alerts integrations list and new form when httpIntegrationsList feature flag is enabled', () => { - createComponent({}, { glFeatures: { httpIntegrationsList: true } }); + describe('with httpIntegrationsList feature flag enabled', () => { + it('renders the GraphQL alerts integrations list and new form', () => { + createComponent({ provide: { glFeatures: { httpIntegrationsList: true } } }); expect(wrapper.find(IntegrationsList).exists()).toBe(true); expect(wrapper.find(AlertsSettingsFormOld).exists()).toBe(false); expect(wrapper.find(AlertsSettingsFormNew).exists()).toBe(true); }); + + it('uses a loading state inside the IntegrationsList table', () => { + createComponent({ + data: { integrations: {} }, + provide: { glFeatures: { httpIntegrationsList: true } }, + loading: true, + }); + expect(wrapper.find(IntegrationsList).exists()).toBe(true); + expect(findLoader().exists()).toBe(true); + }); + + it('renders the IntegrationsList table using the API data', () => { + createComponent({ + data: { integrations: { list: mockIntegrations } }, + provide: { glFeatures: { httpIntegrationsList: true } }, + loading: false, + }); + expect(findLoader().exists()).toBe(false); + expect(findIntegrations()).toHaveLength(mockIntegrations.length); + }); }); }); diff --git a/spec/frontend/alerts_settings/mocks/integrations.json b/spec/frontend/alerts_settings/mocks/integrations.json new file mode 100644 index 00000000000..b1284fc55a2 --- /dev/null +++ b/spec/frontend/alerts_settings/mocks/integrations.json @@ -0,0 +1,38 @@ +[ + { + "id": "gid://gitlab/AlertManagement::HttpIntegration/7", + "type": "HTTP", + "active": true, + "name": "test", + "url": "http://192.168.1.152:3000/root/autodevops/alerts/notify/test/eddd36969b2d3d6a.json", + "token": "7eb24af194116411ec8d66b58c6b0d2e", + "apiUrl": null + }, + { + "id": "gid://gitlab/AlertManagement::HttpIntegration/6", + "type": "HTTP", + "active": false, + "name": "test", + "url": "http://192.168.1.152:3000/root/autodevops/alerts/notify/test/abce123.json", + "token": "8639e0ce06c731b00ee3e8dcdfd14fe0", + "apiUrl": null + }, + { + "id": "gid://gitlab/AlertManagement::HttpIntegration/5", + "type": "HTTP", + "active": false, + "name": "test", + "url": "http://192.168.1.152:3000/root/autodevops/alerts/notify/test/bcd64c85f918a2e2.json", + "token": "5c8101533d970a55d5c105f8abff2192", + "apiUrl": null + }, + { + "id": "gid://gitlab/PrometheusService/12", + "type": "PROMETHEUS", + "active": true, + "name": "Prometheus", + "url": "http://192.168.1.152:3000/root/autodevops/prometheus/alerts/notify.json", + "token": "0b18c37caa8fe980799b349916fe5ddf", + "apiUrl": "https://another-url-2.com" + } +] diff --git a/spec/frontend/static_site_editor/services/front_matterify_spec.js b/spec/frontend/static_site_editor/services/front_matterify_spec.js index dbaedc30849..866897f21ef 100644 --- a/spec/frontend/static_site_editor/services/front_matterify_spec.js +++ b/spec/frontend/static_site_editor/services/front_matterify_spec.js @@ -11,6 +11,7 @@ describe('static_site_editor/services/front_matterify', () => { const frontMatterifiedContent = { source: content, matter: yamlFrontMatterObj, + hasMatter: true, spacing, content: body, delimiter: '---', @@ -19,6 +20,7 @@ describe('static_site_editor/services/front_matterify', () => { const frontMatterifiedBody = { source: body, matter: null, + hasMatter: false, spacing: null, content: body, delimiter: null, @@ -33,6 +35,12 @@ describe('static_site_editor/services/front_matterify', () => { `('returns $target from $frontMatterified', ({ frontMatterified, target }) => { expect(frontMatterified).toEqual(target); }); + + it('should throw when matter is invalid', () => { + const invalidContent = `---\nkey: val\nkeyNoVal\n---\n${body}`; + + expect(() => frontMatterify(invalidContent)).toThrow(); + }); }); describe('stringify', () => { diff --git a/spec/frontend/vue_shared/components/runner_instructions/mock_data.js b/spec/frontend/vue_shared/components/runner_instructions/mock_data.js new file mode 100644 index 00000000000..01f7f3d49c7 --- /dev/null +++ b/spec/frontend/vue_shared/components/runner_instructions/mock_data.js @@ -0,0 +1,107 @@ +export const mockGraphqlRunnerPlatforms = { + data: { + runnerPlatforms: { + nodes: [ + { + name: 'linux', + humanReadableName: 'Linux', + architectures: { + nodes: [ + { + name: 'amd64', + downloadLocation: + 'https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64', + __typename: 'RunnerArchitecture', + }, + { + name: '386', + downloadLocation: + 'https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-386', + __typename: 'RunnerArchitecture', + }, + { + name: 'arm', + downloadLocation: + 'https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-arm', + __typename: 'RunnerArchitecture', + }, + { + name: 'arm64', + downloadLocation: + 'https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-arm64', + __typename: 'RunnerArchitecture', + }, + ], + __typename: 'RunnerArchitectureConnection', + }, + __typename: 'RunnerPlatform', + }, + { + name: 'osx', + humanReadableName: 'macOS', + architectures: { + nodes: [ + { + name: 'amd64', + downloadLocation: + 'https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-amd64', + __typename: 'RunnerArchitecture', + }, + ], + __typename: 'RunnerArchitectureConnection', + }, + __typename: 'RunnerPlatform', + }, + { + name: 'windows', + humanReadableName: 'Windows', + architectures: { + nodes: [ + { + name: 'amd64', + downloadLocation: + 'https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-windows-amd64.exe', + __typename: 'RunnerArchitecture', + }, + { + name: '386', + downloadLocation: + 'https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-windows-386.exe', + __typename: 'RunnerArchitecture', + }, + ], + __typename: 'RunnerArchitectureConnection', + }, + __typename: 'RunnerPlatform', + }, + { + name: 'docker', + humanReadableName: 'Docker', + architectures: null, + __typename: 'RunnerPlatform', + }, + { + name: 'kubernetes', + humanReadableName: 'Kubernetes', + architectures: null, + __typename: 'RunnerPlatform', + }, + ], + __typename: 'RunnerPlatformConnection', + }, + project: { id: 'gid://gitlab/Project/1', __typename: 'Project' }, + group: null, + }, +}; + +export const mockGraphqlInstructions = { + data: { + runnerSetup: { + installInstructions: + "# Download the binary for your system\nsudo curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64\n\n# Give it permissions to execute\nsudo chmod +x /usr/local/bin/gitlab-runner\n\n# Create a GitLab CI user\nsudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash\n\n# Install and run as service\nsudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner\nsudo gitlab-runner start\n", + registerInstructions: + 'sudo gitlab-runner register --url http://192.168.1.81:3000/ --registration-token GE5gsjeep_HAtBf9s3Yz', + __typename: 'RunnerSetup', + }, + }, +}; diff --git a/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_spec.js b/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_spec.js new file mode 100644 index 00000000000..afbcee506c7 --- /dev/null +++ b/spec/frontend/vue_shared/components/runner_instructions/runner_instructions_spec.js @@ -0,0 +1,119 @@ +import { shallowMount, createLocalVue } from '@vue/test-utils'; +import VueApollo from 'vue-apollo'; +import createMockApollo from 'jest/helpers/mock_apollo_helper'; +import RunnerInstructions from '~/vue_shared/components/runner_instructions/runner_instructions.vue'; +import getRunnerPlatforms from '~/vue_shared/components/runner_instructions/graphql/queries/get_runner_platforms.query.graphql'; +import getRunnerSetupInstructions from '~/vue_shared/components/runner_instructions/graphql/queries/get_runner_setup.query.graphql'; + +import { mockGraphqlRunnerPlatforms, mockGraphqlInstructions } from './mock_data'; + +const projectPath = 'gitlab-org/gitlab'; +const localVue = createLocalVue(); +localVue.use(VueApollo); + +describe('RunnerInstructions component', () => { + let wrapper; + let fakeApollo; + + const findModalButton = () => wrapper.find('[data-testid="show-modal-button"]'); + const findPlatformButtons = () => wrapper.findAll('[data-testid="platform-button"]'); + const findArchitectureDropdownItems = () => + wrapper.findAll('[data-testid="architecture-dropdown-item"]'); + const findBinaryInstructionsSection = () => wrapper.find('[data-testid="binary-instructions"]'); + const findRunnerInstructionsSection = () => wrapper.find('[data-testid="runner-instructions"]'); + + beforeEach(() => { + const requestHandlers = [ + [getRunnerPlatforms, jest.fn().mockResolvedValue(mockGraphqlRunnerPlatforms)], + [getRunnerSetupInstructions, jest.fn().mockResolvedValue(mockGraphqlInstructions)], + ]; + + fakeApollo = createMockApollo(requestHandlers); + + wrapper = shallowMount(RunnerInstructions, { + provide: { + projectPath, + }, + localVue, + apolloProvider: fakeApollo, + }); + }); + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + it('should show the "Show Runner installation instructions" button', () => { + const button = findModalButton(); + + expect(button.exists()).toBe(true); + expect(button.text()).toBe('Show Runner installation instructions'); + }); + + it('should contain a number of platforms buttons', () => { + const buttons = findPlatformButtons(); + + expect(buttons).toHaveLength(mockGraphqlRunnerPlatforms.data.runnerPlatforms.nodes.length); + }); + + it('should contain a number of dropdown items for the architecture options', () => { + const platformButton = findPlatformButtons().at(0); + platformButton.vm.$emit('click'); + + return wrapper.vm.$nextTick(() => { + const dropdownItems = findArchitectureDropdownItems(); + + expect(dropdownItems).toHaveLength( + mockGraphqlRunnerPlatforms.data.runnerPlatforms.nodes[0].architectures.nodes.length, + ); + }); + }); + + it('should display the binary installation instructions for a selected architecture', async () => { + const platformButton = findPlatformButtons().at(0); + platformButton.vm.$emit('click'); + + await wrapper.vm.$nextTick(); + + const dropdownItem = findArchitectureDropdownItems().at(0); + dropdownItem.vm.$emit('click'); + + await wrapper.vm.$nextTick(); + + const runner = findBinaryInstructionsSection(); + + expect(runner.text()).toEqual( + expect.stringContaining('sudo chmod +x /usr/local/bin/gitlab-runner'), + ); + expect(runner.text()).toEqual( + expect.stringContaining( + `sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash`, + ), + ); + expect(runner.text()).toEqual( + expect.stringContaining( + 'sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner', + ), + ); + expect(runner.text()).toEqual(expect.stringContaining('sudo gitlab-runner start')); + }); + + it('should display the runner register instructions for a selected architecture', async () => { + const platformButton = findPlatformButtons().at(0); + platformButton.vm.$emit('click'); + + await wrapper.vm.$nextTick(); + + const dropdownItem = findArchitectureDropdownItems().at(0); + dropdownItem.vm.$emit('click'); + + await wrapper.vm.$nextTick(); + + const runner = findRunnerInstructionsSection(); + + expect(runner.text()).toEqual( + expect.stringContaining(mockGraphqlInstructions.data.runnerSetup.registerInstructions), + ); + }); +}); diff --git a/spec/graphql/types/availability_enum_spec.rb b/spec/graphql/types/availability_enum_spec.rb new file mode 100644 index 00000000000..a9bdf5e4da6 --- /dev/null +++ b/spec/graphql/types/availability_enum_spec.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['AvailabilityEnum'] do + specify { expect(described_class.graphql_name).to eq('AvailabilityEnum') } + + it 'exposes all the existing access levels' do + expect(described_class.values.keys).to match_array(%w[NOT_SET BUSY]) + end +end diff --git a/spec/graphql/types/terraform/state_type_spec.rb b/spec/graphql/types/terraform/state_type_spec.rb index 51508208046..9f65bb926d7 100644 --- a/spec/graphql/types/terraform/state_type_spec.rb +++ b/spec/graphql/types/terraform/state_type_spec.rb @@ -7,7 +7,7 @@ RSpec.describe GitlabSchema.types['TerraformState'] do it { expect(described_class).to require_graphql_authorizations(:read_terraform_state) } describe 'fields' do - let(:fields) { %i[id name locked_by_user locked_at created_at updated_at] } + let(:fields) { %i[id name locked_by_user locked_at latest_version created_at updated_at] } it { expect(described_class).to have_graphql_fields(fields) } @@ -17,5 +17,8 @@ RSpec.describe GitlabSchema.types['TerraformState'] do it { expect(described_class.fields['lockedAt'].type).not_to be_non_null } it { expect(described_class.fields['createdAt'].type).to be_non_null } it { expect(described_class.fields['updatedAt'].type).to be_non_null } + + it { expect(described_class.fields['latestVersion'].type).not_to be_non_null } + it { expect(described_class.fields['latestVersion'].complexity).to eq(3) } end end diff --git a/spec/graphql/types/terraform/state_version_type_spec.rb b/spec/graphql/types/terraform/state_version_type_spec.rb new file mode 100644 index 00000000000..2fa41f47028 --- /dev/null +++ b/spec/graphql/types/terraform/state_version_type_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['TerraformStateVersion'] do + it { expect(described_class.graphql_name).to eq('TerraformStateVersion') } + it { expect(described_class).to require_graphql_authorizations(:read_terraform_state) } + + describe 'fields' do + let(:fields) { %i[id created_by_user created_at updated_at] } + + it { expect(described_class).to have_graphql_fields(fields) } + + it { expect(described_class.fields['id'].type).to be_non_null } + it { expect(described_class.fields['createdByUser'].type).not_to be_non_null } + it { expect(described_class.fields['createdAt'].type).to be_non_null } + it { expect(described_class.fields['updatedAt'].type).to be_non_null } + end +end diff --git a/spec/graphql/types/user_status_type_spec.rb b/spec/graphql/types/user_status_type_spec.rb index c4421a9cc10..ced9c40d552 100644 --- a/spec/graphql/types/user_status_type_spec.rb +++ b/spec/graphql/types/user_status_type_spec.rb @@ -10,6 +10,7 @@ RSpec.describe Types::UserStatusType do emoji message message_html + availability ] expect(described_class).to have_graphql_fields(*expected_fields) diff --git a/spec/helpers/operations_helper_spec.rb b/spec/helpers/operations_helper_spec.rb index 8d2fc643caa..2ed52716802 100644 --- a/spec/helpers/operations_helper_spec.rb +++ b/spec/helpers/operations_helper_spec.rb @@ -43,7 +43,8 @@ RSpec.describe OperationsHelper do 'prometheus_api_url' => nil, 'prometheus_activated' => 'false', 'prometheus_url' => notify_project_prometheus_alerts_url(project, format: :json), - 'disabled' => 'false' + 'disabled' => 'false', + 'project_path' => project_path(project) ) end end diff --git a/spec/lib/api/every_api_endpoint_spec.rb b/spec/lib/api/every_api_endpoint_spec.rb index 4a8998b89f9..ac424a511c0 100644 --- a/spec/lib/api/every_api_endpoint_spec.rb +++ b/spec/lib/api/every_api_endpoint_spec.rb @@ -31,8 +31,13 @@ RSpec.describe 'Every API endpoint' do ::API::FeatureFlagsUserLists, ::API::Features, ::API::Files, ::API::FreezePeriods, ::API::GroupBoards, ::API::GroupClusters, ::API::GroupExport, ::API::GroupImport, ::API::GroupLabels, ::API::GroupMilestones, ::API::Groups, - ::API::GroupContainerRepositories, ::API::GroupVariables - + ::API::GroupContainerRepositories, ::API::GroupVariables, + ::API::ImportBitbucketServer, ::API::ImportGithub, ::API::IssueLinks, + ::API::Issues, ::API::JobArtifacts, ::API::Jobs, ::API::Keys, ::API::Labels, + ::API::Lint, ::API::Markdown, ::API::Members, ::API::MergeRequestDiffs, + ::API::MergeRequests, ::API::MergeRequestApprovals, ::API::Metrics::Dashboard::Annotations, + ::API::Metrics::UserStarredDashboards, ::API::Namespaces, ::API::Notes, + ::API::Discussions ] next unless completed_classes.include?(klass) diff --git a/spec/policies/terraform/state_version_policy_spec.rb b/spec/policies/terraform/state_version_policy_spec.rb new file mode 100644 index 00000000000..6614e073332 --- /dev/null +++ b/spec/policies/terraform/state_version_policy_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Terraform::StateVersionPolicy do + let_it_be(:project) { create(:project) } + let_it_be(:terraform_state) { create(:terraform_state, :with_version, project: project)} + + subject { described_class.new(user, terraform_state.latest_version) } + + describe 'rules' do + context 'no access' do + let(:user) { create(:user) } + + it { is_expected.to be_disallowed(:read_terraform_state) } + it { is_expected.to be_disallowed(:admin_terraform_state) } + end + + context 'developer' do + let(:user) { create(:user, developer_projects: [project]) } + + it { is_expected.to be_allowed(:read_terraform_state) } + it { is_expected.to be_disallowed(:admin_terraform_state) } + end + + context 'maintainer' do + let(:user) { create(:user, maintainer_projects: [project]) } + + it { is_expected.to be_allowed(:read_terraform_state) } + it { is_expected.to be_allowed(:admin_terraform_state) } + end + end +end diff --git a/spec/requests/api/graphql/project/terraform/states_spec.rb b/spec/requests/api/graphql/project/terraform/states_spec.rb index 533f913926c..c72af19a7a3 100644 --- a/spec/requests/api/graphql/project/terraform/states_spec.rb +++ b/spec/requests/api/graphql/project/terraform/states_spec.rb @@ -6,7 +6,8 @@ RSpec.describe 'query terraform states' do include GraphqlHelpers let_it_be(:project) { create(:project) } - let_it_be(:terraform_state) { create(:terraform_state, :locked, project: project) } + let_it_be(:terraform_state) { create(:terraform_state, :with_version, :locked, project: project) } + let_it_be(:latest_version) { terraform_state.latest_version } let(:query) do graphql_query_for(:project, { fullPath: project.full_path }, @@ -20,6 +21,16 @@ RSpec.describe 'query terraform states' do createdAt updatedAt + latestVersion { + id + createdAt + updatedAt + + createdByUser { + id + } + } + lockedByUser { id } @@ -37,13 +48,19 @@ RSpec.describe 'query terraform states' do it 'returns terraform state data', :aggregate_failures do state = data.dig('nodes', 0) + version = state['latestVersion'] expect(state['id']).to eq(terraform_state.to_global_id.to_s) expect(state['name']).to eq(terraform_state.name) - expect(state['lockedAt']).to eq(terraform_state.locked_at.strftime('%Y-%m-%dT%H:%M:%SZ')) - expect(state['createdAt']).to eq(terraform_state.created_at.strftime('%Y-%m-%dT%H:%M:%SZ')) - expect(state['updatedAt']).to eq(terraform_state.updated_at.strftime('%Y-%m-%dT%H:%M:%SZ')) + expect(state['lockedAt']).to eq(terraform_state.locked_at.iso8601) + expect(state['createdAt']).to eq(terraform_state.created_at.iso8601) + expect(state['updatedAt']).to eq(terraform_state.updated_at.iso8601) expect(state.dig('lockedByUser', 'id')).to eq(terraform_state.locked_by_user.to_global_id.to_s) + + expect(version['id']).to eq(latest_version.to_global_id.to_s) + expect(version['createdAt']).to eq(terraform_state.created_at.iso8601) + expect(version['updatedAt']).to eq(terraform_state.updated_at.iso8601) + expect(version.dig('createdByUser', 'id')).to eq(latest_version.created_by_user.to_global_id.to_s) end it 'returns count of terraform states' do diff --git a/spec/requests/api/graphql/user_query_spec.rb b/spec/requests/api/graphql/user_query_spec.rb index 79debd0b7ef..d64fd3868c2 100644 --- a/spec/requests/api/graphql/user_query_spec.rb +++ b/spec/requests/api/graphql/user_query_spec.rb @@ -59,6 +59,7 @@ RSpec.describe 'getting user information' do let(:user_params) { { username: user.username } } before do + create(:user_status, user: user) post_graphql(query, current_user: current_user) end @@ -76,9 +77,15 @@ RSpec.describe 'getting user information' do 'username' => presenter.username, 'webUrl' => presenter.web_url, 'avatarUrl' => presenter.avatar_url, - 'status' => presenter.status, 'email' => presenter.email )) + + expect(graphql_data['user']['status']).to match( + a_hash_including( + 'emoji' => presenter.status.emoji, + 'message' => presenter.status.message, + 'availability' => presenter.status.availability.upcase + )) end describe 'assignedMergeRequests' do diff --git a/spec/requests/robots_txt_spec.rb b/spec/requests/robots_txt_spec.rb index b8e02827ba1..a8be4093a71 100644 --- a/spec/requests/robots_txt_spec.rb +++ b/spec/requests/robots_txt_spec.rb @@ -79,7 +79,9 @@ RSpec.describe 'Robots.txt Requests', :aggregate_failures do '/foo/bar/-/incidents', '/foo/bar/-/value_stream_analytics', '/foo/bar/-/analytics', - '/foo/bar/insights' + '/foo/bar/insights', + '/foo/bar/-/issues/123/realtime_changes', + '/groups/group/-/epics/123/realtime_changes' ] requests.each do |request| diff --git a/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb b/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb index cfe8e863223..1b829df6e6a 100644 --- a/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb +++ b/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb @@ -241,18 +241,6 @@ RSpec.describe Projects::LfsPointers::LfsDownloadService do context 'and first fragments are the same' do let(:lfs_content) { existing_lfs_object.file.read } - context 'when lfs_link_existing_object feature flag disabled' do - before do - stub_feature_flags(lfs_link_existing_object: false) - end - - it 'does not call link_existing_lfs_object!' do - expect(subject).not_to receive(:link_existing_lfs_object!) - - subject.execute - end - end - it 'returns success' do expect(subject.execute).to eq({ status: :success }) end diff --git a/spec/services/users/set_status_service_spec.rb b/spec/services/users/set_status_service_spec.rb index 54489adceb0..319723b5201 100644 --- a/spec/services/users/set_status_service_spec.rb +++ b/spec/services/users/set_status_service_spec.rb @@ -9,13 +9,14 @@ RSpec.describe Users::SetStatusService do describe '#execute' do context 'when params are set' do - let(:params) { { emoji: 'taurus', message: 'a random status' } } + let(:params) { { emoji: 'taurus', message: 'a random status', availability: 'busy' } } it 'creates a status' do service.execute expect(current_user.status.emoji).to eq('taurus') expect(current_user.status.message).to eq('a random status') + expect(current_user.status.availability).to eq('busy') end it 'updates a status if it already existed' do @@ -25,6 +26,26 @@ RSpec.describe Users::SetStatusService do expect(current_user.status.message).to eq('a random status') end + it 'returns true' do + create(:user_status, user: current_user) + expect(service.execute).to be(true) + end + + context 'when the given availability value is not valid' do + let(:params) { { availability: 'not a valid value' } } + + it 'does not update the status' do + user_status = create(:user_status, user: current_user) + + expect { service.execute }.not_to change { user_status.reload } + end + + it 'returns false' do + create(:user_status, user: current_user) + expect(service.execute).to be(false) + end + end + context 'for another user' do let(:target_user) { create(:user) } let(:params) do diff --git a/spec/support/shared_examples/lib/gitlab/repository_size_checker_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/repository_size_checker_shared_examples.rb index bb909ffe82a..30413f206f8 100644 --- a/spec/support/shared_examples/lib/gitlab/repository_size_checker_shared_examples.rb +++ b/spec/support/shared_examples/lib/gitlab/repository_size_checker_shared_examples.rb @@ -17,35 +17,58 @@ RSpec.shared_examples 'checker size not over limit' do end RSpec.shared_examples 'checker size exceeded' do - context 'when current size is below or equal to the limit' do - let(:current_size) { 50 } + context 'when no change size provided' do + context 'when current size is below the limit' do + let(:current_size) { limit - 1 } - it 'returns zero' do - expect(subject.exceeded_size).to eq(0) + it 'returns zero' do + expect(subject.exceeded_size).to eq(0) + end end - end - context 'when current size is over the limit' do - let(:current_size) { 51 } + context 'when current size is equal to the limit' do + let(:current_size) { limit } - it 'returns zero' do - expect(subject.exceeded_size).to eq(1.megabytes) + it 'returns zero' do + expect(subject.exceeded_size).to eq(0) + end end - end - context 'when change size will be over the limit' do - let(:current_size) { 50 } + context 'when current size is over the limit' do + let(:current_size) { limit + 1 } + let(:total_repository_size_excess) { 1 } - it 'returns zero' do - expect(subject.exceeded_size(1.megabytes)).to eq(1.megabytes) + it 'returns a positive number' do + expect(subject.exceeded_size).to eq(1.megabyte) + end end end - context 'when change size will not be over the limit' do - let(:current_size) { 49 } + context 'when a change size is provided' do + let(:change_size) { 1.megabyte } + + context 'when change size will be over the limit' do + let(:current_size) { limit } + + it 'returns a positive number' do + expect(subject.exceeded_size(change_size)).to eq(1.megabyte) + end + end + + context 'when change size will be at the limit' do + let(:current_size) { limit - 1 } + + it 'returns zero' do + expect(subject.exceeded_size(change_size)).to eq(0) + end + end + + context 'when change size will be under the limit' do + let(:current_size) { limit - 2 } - it 'returns zero' do - expect(subject.exceeded_size(1.megabytes)).to eq(0) + it 'returns zero' do + expect(subject.exceeded_size(change_size)).to eq(0) + end end end end diff --git a/yarn.lock b/yarn.lock index 633694cc093..d2939cb94c0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1659,6 +1659,13 @@ after@0.8.2: resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8= +agent-base@4, agent-base@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" + integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== + dependencies: + es6-promisify "^5.0.0" + aggregate-error@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.0.1.tgz#db2fe7246e536f40d9b5442a39e117d7dd6a24e0" @@ -3833,7 +3840,14 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: dependencies: ms "2.0.0" -debug@^3.1.1, debug@^3.2.5, debug@^3.2.6: +debug@3.1.0, debug@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + +debug@^3.1.0, debug@^3.1.1, debug@^3.2.5, debug@^3.2.6: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== @@ -3847,13 +3861,6 @@ debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: dependencies: ms "^2.1.1" -debug@~3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - decamelize-keys@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" @@ -4446,11 +4453,23 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" +es6-promise@^4.0.3: + version "4.2.8" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + es6-promise@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.0.2.tgz#010d5858423a5f118979665f46486a95c6ee2bb6" integrity sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y= +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= + dependencies: + es6-promise "^4.0.3" + escape-goat@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" @@ -5897,6 +5916,14 @@ http-errors@~1.6.2: setprototypeof "1.0.3" statuses ">= 1.3.1 < 2" +http-proxy-agent@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" + integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg== + dependencies: + agent-base "4" + debug "3.1.0" + http-proxy-middleware@0.19.1: version "0.19.1" resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a" @@ -5930,6 +5957,14 @@ https-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= +https-proxy-agent@^2.2.3: + version "2.2.4" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" + integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== + dependencies: + agent-base "^4.3.0" + debug "^3.1.0" + human-signals@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" @@ -7166,7 +7201,7 @@ js-cookie@^2.2.1: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@^3.12.0, js-yaml@^3.13.1, js-yaml@~3.13.1: +js-yaml@^3.13.1, js-yaml@~3.13.1: version "3.13.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== @@ -7305,7 +7340,12 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" -jsonc-parser@^2.2.1, jsonc-parser@~2.2.0: +jsonc-parser@^2.2.1, jsonc-parser@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.3.1.tgz#59549150b133f2efacca48fe9ce1ec0659af2342" + integrity sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg== + +jsonc-parser@~2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.2.1.tgz#db73cd59d78cce28723199466b2a03d1be1df2bc" integrity sha512-o6/yDBYccGvTz1+QFevz6l6OBZ2+fMVu2JZ9CIhzsYRX4mjaK5IyX9eldUdCmga16zlgQxyrj5pt9kzuj2C02w== @@ -8381,17 +8421,12 @@ monaco-editor@0.20.0, monaco-editor@^0.20.0: resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.20.0.tgz#5d5009343a550124426cb4d965a4d27a348b4dea" integrity sha512-hkvf4EtPJRMQlPC3UbMoRs0vTAFAYdzFQ+gpMb8A+9znae1c43q8Mab9iVsgTcg/4PNiLGGn3SlDIa8uvK1FIQ== -monaco-yaml@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/monaco-yaml/-/monaco-yaml-2.4.1.tgz#f0d3384b1f10cc7af2b60e3a30b0adc6683b728a" - integrity sha512-Q0Yj6FNok97AslptS1OVfyX07rJ5uhOYsHKaVoU0usiUqeL7gzl6l8TL8W3QGdwCKm4WhfKpJ9bqPDtiQvCirg== +monaco-yaml@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/monaco-yaml/-/monaco-yaml-2.5.1.tgz#af9303a4aa6e3b94db62b8a8659362f31944590d" + integrity sha512-U+zIAcwnQzlUgy6vdzFdNf5PToFzuz099FxYmUxIeen9GTiq6XYDX9mmXSR31mMrgiSaU5a2bGEyG4p2fbW/7A== dependencies: - js-yaml "^3.12.0" - vscode-json-languageservice "^3.4.11" - vscode-languageserver "^5.2.1" - vscode-uri "^2.1.1" - optionalDependencies: - prettier "^1.19.1" + yaml-language-server "^0.11.1" mousetrap@1.6.5: version "1.6.5" @@ -9501,15 +9536,15 @@ pretender@^3.4.3: fake-xml-http-request "^2.1.1" route-recognizer "^0.3.3" -prettier@1.18.2: +prettier@1.18.2, prettier@^1.18.2: version "1.18.2" resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea" integrity sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw== -prettier@^1.18.2, prettier@^1.19.1: - version "1.19.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" - integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== +prettier@2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.5.tgz#d6d56282455243f2f92cc1716692c08aa31522d4" + integrity sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg== pretty-format@^25.2.1, pretty-format@^25.5.0: version "25.5.0" @@ -10175,6 +10210,15 @@ replace-ext@1.0.0: resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" integrity sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs= +request-light@^0.2.4: + version "0.2.5" + resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.2.5.tgz#38a3da7b2e56f7af8cbba57e8a94930ee2380746" + integrity sha512-eBEh+GzJAftUnex6tcL6eV2JCifY0+sZMIUpUPOVXbs2nV5hla4ZMmO3icYKGuGVuQ2zHE9evh4OrRcH4iyYYw== + dependencies: + http-proxy-agent "^2.1.0" + https-proxy-agent "^2.2.3" + vscode-nls "^4.1.1" + request-promise-core@1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.4.tgz#3eedd4223208d419867b78ce815167d10593a22f" @@ -12247,15 +12291,15 @@ void-elements@^2.0.0: resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w= -vscode-json-languageservice@^3.4.11: - version "3.7.0" - resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.7.0.tgz#0174417f139cf41dd60c84538fd052385bfb46f6" - integrity sha512-nGLqcBhTjdfkl8Dz9sYGK/ZCTjscYFoIjYw+qqkWB+vyNfM0k/AyIoT73DQvB/PArteCKjEVfQUF72GRZEDSbQ== +vscode-json-languageservice@^3.6.0: + version "3.9.1" + resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.9.1.tgz#f72b581f8cd2bd9b47445ccf8b0ddcde6aba7483" + integrity sha512-oJkknkdCVitQ5XPSRa0weHjUxt8eSCptaL+MBQQlRsa6Nb8XnEY0S5wYnLUFHzEvKzwt01/LKk8LdOixWEXkNA== dependencies: - jsonc-parser "^2.2.1" + jsonc-parser "^2.3.1" vscode-languageserver-textdocument "^1.0.1" - vscode-languageserver-types "^3.15.1" - vscode-nls "^4.1.2" + vscode-languageserver-types "3.16.0-next.2" + vscode-nls "^5.0.0" vscode-uri "^2.1.2" vscode-jsonrpc@^4.0.0: @@ -12281,6 +12325,11 @@ vscode-languageserver-types@3.14.0: resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz#d3b5952246d30e5241592b6dde8280e03942e743" integrity sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A== +vscode-languageserver-types@3.16.0-next.2: + version "3.16.0-next.2" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0-next.2.tgz#940bd15c992295a65eae8ab6b8568a1e8daa3083" + integrity sha512-QjXB7CKIfFzKbiCJC4OWC8xUncLsxo19FzGVp/ADFvvi87PlmBSCAtZI5xwGjF5qE0xkLf0jjKUn3DzmpDP52Q== + vscode-languageserver-types@^3.15.1: version "3.15.1" resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.15.1.tgz#17be71d78d2f6236d414f0001ce1ef4d23e6b6de" @@ -12294,11 +12343,16 @@ vscode-languageserver@^5.2.1: vscode-languageserver-protocol "3.14.1" vscode-uri "^1.0.6" -vscode-nls@^4.1.2: +vscode-nls@^4.1.1, vscode-nls@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.2.tgz#ca8bf8bb82a0987b32801f9fddfdd2fb9fd3c167" integrity sha512-7bOHxPsfyuCqmP+hZXscLhiHwe7CSuFE4hyhbs22xPIhQ4jv99FcR4eBzfYYVLP356HNFpdvz63FFb/xw6T4Iw== +vscode-nls@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-5.0.0.tgz#99f0da0bd9ea7cda44e565a74c54b1f2bc257840" + integrity sha512-u0Lw+IYlgbEJFF6/qAqG2d1jQmJl0eyAGJHoAJqr2HT4M2BNuQYSEiSE75f52pXHSJm8AlTjnLLbBFPrdz2hpA== + vscode-uri@^1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-1.0.8.tgz#9769aaececae4026fb6e22359cb38946580ded59" @@ -12869,6 +12923,28 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yaml-ast-parser-custom-tags@0.0.43: + version "0.0.43" + resolved "https://registry.yarnpkg.com/yaml-ast-parser-custom-tags/-/yaml-ast-parser-custom-tags-0.0.43.tgz#46968145ce4e24cb03c3312057f0f141b93a7d02" + integrity sha512-R5063FF/JSAN6qXCmylwjt9PcDH6M0ExEme/nJBzLspc6FJDmHHIqM7xh2WfEmsTJqClF79A9VkXjkAqmZw9SQ== + +yaml-language-server@^0.11.1: + version "0.11.1" + resolved "https://registry.yarnpkg.com/yaml-language-server/-/yaml-language-server-0.11.1.tgz#4ddc72eb9a6dd7dc41f31af2a8f5c72cce456cc9" + integrity sha512-N3Tu3g4O6ZWV7W0LVsNk62DtKJDQkbnPZRDd7ntaAeEl8QkxL1vnMunI26uzDU4PwwG4tPJ8g/VRS6U+fVp/6A== + dependencies: + js-yaml "^3.13.1" + jsonc-parser "^2.2.1" + request-light "^0.2.4" + vscode-json-languageservice "^3.6.0" + vscode-languageserver "^5.2.1" + vscode-languageserver-types "^3.15.1" + vscode-nls "^4.1.2" + vscode-uri "^2.1.1" + yaml-ast-parser-custom-tags "0.0.43" + optionalDependencies: + prettier "2.0.5" + yargs-parser@20.x: version "20.2.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.1.tgz#28f3773c546cdd8a69ddae68116b48a5da328e77" -- cgit v1.2.3