Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-03-23 03:07:30 +00:00
parent 1b6de87b5c
commit 5316a9bca9
53 changed files with 681 additions and 199 deletions

View File

@ -215,18 +215,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/administration/audit_events.md @eread
/doc/administration/audit_reports.md @eread
/doc/administration/auditor_users.md @axil
/doc/administration/auth/atlassian.md @eread
/doc/administration/auth/authentiq.md @eread
/doc/administration/auth/cognito.md @eread
/doc/administration/auth/crowd.md @eread
/doc/administration/auth/index.md @eread
/doc/administration/auth/ldap/google_secure_ldap.md @eread
/doc/administration/auth/jwt.md @eread
/doc/administration/auth/ldap/ldap-troubleshooting.md @eread
/doc/administration/auth/ldap/ldap_synchronization.md @eread
/doc/administration/auth/ldap/index.md @eread
/doc/administration/auth/oidc.md @eread
/doc/administration/auth/smartcard.md @eread
/doc/administration/auth/ @eread
/doc/administration/cicd.md @marcel.amirault
/doc/administration/clusters/kas.md @sselhorn
/doc/administration/compliance.md @eread
@ -269,8 +258,8 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/administration/operations/sidekiq_memory_killer.md @marcel.amirault
/doc/administration/package_information/ @axil
/doc/administration/packages/ @ngaskill
/doc/administration/pages/index.md @rdickenson
/doc/administration/pages/source.md @rdickenson
/doc/administration/pages/index.md @aqualls
/doc/administration/pages/source.md @aqualls
/doc/administration/polling.md @axil
/doc/administration/postgresql/ @aqualls
/doc/administration/pseudonymizer.md @axil
@ -291,6 +280,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/administration/smime_signing_email.md @axil
/doc/administration/snippets/index.md @aqualls
/doc/administration/static_objects_external_storage.md @aqualls
/doc/administration/system_hooks.md @kpaizee
/doc/administration/terraform_state.md @sselhorn
/doc/administration/timezone.md @axil
/doc/administration/troubleshooting/ @axil
@ -340,6 +330,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/api/graphql/ @kpaizee
/doc/api/graphql/custom_emoji.md @msedlakjakubowski
/doc/api/graphql/sample_issue_boards.md @msedlakjakubowski
/doc/api/group_access_tokens.md @eread
/doc/api/group_activity_analytics.md @fneill
/doc/api/group_badges.md @eread
/doc/api/group_boards.md @msedlakjakubowski
@ -369,6 +360,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/api/keys.md @aqualls
/doc/api/labels.md @msedlakjakubowski
/doc/api/license.md @kpaizee
/doc/api/linked_epics.md @msedlakjakubowski
/doc/api/lint.md @marcel.amirault
/doc/api/managed_licenses.md @kpaizee
/doc/api/markdown.md @aqualls
@ -387,13 +379,15 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/api/openapi/openapi_interactive.md @kpaizee
/doc/api/packages.md @ngaskill
/doc/api/packages/ @ngaskill
/doc/api/pages_domains.md @rdickenson
/doc/api/pages.md @rdickenson
/doc/api/pages_domains.md @aqualls
/doc/api/pages.md @aqualls
/doc/api/personal_access_tokens.md @eread
/doc/api/pipeline_schedules.md @marcel.amirault
/doc/api/pipeline_triggers.md @marcel.amirault
/doc/api/pipelines.md @marcel.amirault
/doc/api/scim.md @eread
/doc/api/plan_limits.md @eread
/doc/api/project_access_tokens.md @eread
/doc/api/project_aliases.md @aqualls
/doc/api/project_badges.md @aqualls
/doc/api/project_clusters.md @sselhorn
@ -422,7 +416,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/api/resource_state_events.md @msedlakjakubowski
/doc/api/resource_weight_events.md @msedlakjakubowski
/doc/api/runners.md @sselhorn
/doc/api/scim.md @eread
/doc/api/plan_limits.md @eread
/doc/api/search.md @aqualls
/doc/api/secure_files.md @marcel.amirault
/doc/api/settings.md @eread
@ -509,6 +503,8 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/development/auto_devops.md @sselhorn
/doc/development/avoiding_downtime_in_migrations.md @aqualls
/doc/development/backend/create_source_code_be/index.md @aqualls
/doc/development/backend/ruby_style_guide.md @marcia
/doc/development/background_migrations.md @marcia
/doc/development/build_test_package.md @axil
/doc/development/bulk_import.md @ngaskill
/doc/development/cascading_settings.md @eread
@ -518,11 +514,15 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/development/cicd/schema.md @marcel.amirault
/doc/development/cicd/templates.md @marcel.amirault
/doc/development/code_intelligence/index.md @aqualls
/doc/development/contributing/ @marcia
/doc/development/contributing/merge_request_workflow.md @aqualls
/doc/development/creating_enums.md @aqualls
/doc/development/database_debugging.md @aqualls
/doc/development/database_query_comments.md @aqualls
/doc/development/database_review.md @aqualls
/doc/development/database/client_side_connection_pool.md @marcia
/doc/development/database/ @aqualls
/doc/development/database/multiple_databases.md @marcia
/doc/development/db_dump.md @aqualls
/doc/development/developing_with_solargraph.md @aqualls
/doc/development/distributed_tracing.md @ngaskill
@ -538,7 +538,12 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/development/experiment_guide/ @kpaizee
/doc/development/export_csv.md @ngaskill
/doc/development/fe_guide/content_editor.md @aqualls
/doc/development/fe_guide/dark_mode.md @marcia
/doc/development/fe_guide/graphql.md @marcia
/doc/development/fe_guide/source_editor.md @aqualls
/doc/development/feature_categorization/index.md @marcia
/doc/development/feature_flags/controls.md @marcia
/doc/development/feature_flags/index.md @marcia
/doc/development/filtering_by_label.md @msedlakjakubowski
/doc/development/foreign_keys.md @aqualls
/doc/development/geo.md @axil
@ -551,12 +556,15 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/development/i18n/ @ngaskill
/doc/development/image_scaling.md @marcel.amirault
/doc/development/import_export.md @ngaskill
/doc/development/index.md @marcia
/doc/development/insert_into_tables_in_batches.md @aqualls
/doc/development/integrations/jenkins.md @kpaizee
/doc/development/integrations/ @kpaizee
/doc/development/integrations/codesandbox.md @marcia
/doc/development/integrations/jira_connect.md @kpaizee
/doc/development/integrations/secure_partner_integration.md @rdickenson
/doc/development/integrations/secure.md @ngaskill
/doc/development/internal_api/ @aqualls
/doc/development/internal_users.md @marcia
/doc/development/issuable-like-models.md @msedlakjakubowski
/doc/development/issue_types.md @msedlakjakubowski
/doc/development/iterating_tables_in_batches.md @aqualls
@ -565,17 +573,24 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/development/licensed_feature_availability.md @sselhorn
/doc/development/maintenance_mode.md @axil
/doc/development/new_fe_guide/modules/widget_extensions.md @aqualls
/doc/development/new_fe_guide/tips.md @marcia
/doc/development/omnibus.md @axil
/doc/development/ordering_table_columns.md @aqualls
/doc/development/packages.md @ngaskill
/doc/development/permissions.md @eread
/doc/development/policies.md @eread
/doc/development/product_qualified_lead_guide/index.md @kpaizee
/doc/development/query_performance.md @aqualls
/doc/development/real_time.md @msedlakjakubowski
/doc/development/secure_coding_guidelines.md @marcia
/doc/development/serializing_data.md @aqualls
/doc/development/service_ping/ @fneill
/doc/development/snowplow/ @fneill
/doc/development/spam_protection_and_captcha/ @eread
/doc/development/sql.md @aqualls
/doc/development/swapping_tables.md @aqualls
/doc/development/testing_guide/best_practices.md @marcia
/doc/development/testing_guide/end_to_end/best_practices.md @marcia
/doc/development/understanding_explain_plans.md @aqualls
/doc/development/value_stream_analytics.md @fneill
/doc/development/value_stream_analytics/value_stream_analytics_aggregated_backend.md @fneill
@ -583,6 +598,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/development/wikis.md @aqualls
/doc/development/work_items.md @msedlakjakubowski
/doc/development/work_items_widgets.md @msedlakjakubowski
/doc/development/workspace/index.md @marcia
/doc/downgrade_ee_to_ce/index.md @axil
/doc/gitlab-basics/add-file.md @aqualls
/doc/gitlab-basics/command-line-commands.md @aqualls
@ -610,6 +626,8 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/raketasks/generate_sample_prometheus_data.md @ngaskill
/doc/raketasks/migrate_snippets.md @aqualls
/doc/raketasks/spdx.md @rdickenson
/doc/raketasks/user_management.md @axil
/doc/raketasks/web_hooks.md @axil
/doc/raketasks/x509_signatures.md @aqualls
/doc/security/ @eread
/doc/ssh/index.md @eread
@ -632,6 +650,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/user/admin_area/geo_nodes.md @axil
/doc/user/admin_area/labels.md @msedlakjakubowski
/doc/user/admin_area/license.md @kpaizee
/doc/user/admin_area/license_file.md @sselhorn
/doc/user/admin_area/merge_requests_approvals.md @aqualls
/doc/user/admin_area/moderate_users.md @eread
/doc/user/admin_area/monitoring/background_migrations.md @aqualls
@ -657,8 +676,8 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/user/admin_area/settings/rate_limit_on_users_api.md @eread
/doc/user/admin_area/settings/third_party_offers.md @fneill
/doc/user/admin_area/settings/visibility_and_access_controls.md @aqualls
/doc/user/analytics/ci_cd_analytics.md @rdickenson
/doc/user/analytics/ @fneill
/doc/user/analytics/ci_cd_analytics.md @rdickenson
/doc/user/application_security/ @rdickenson
/doc/user/application_security/cluster_image_scanning/index.md @ngaskill
/doc/user/application_security/container_scanning/index.md @ngaskill
@ -676,15 +695,18 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/user/compliance/license_compliance/index.md @rdickenson
/doc/user/crm/index.md @msedlakjakubowski
/doc/user/discussions/index.md @aqualls
/doc/user/feature_flags.md @marcia
/doc/user/group/index.md @eread
/doc/user/group/clusters/index.md @sselhorn
/doc/user/group/contribution_analytics/index.md @fneill
/doc/user/group/custom_project_templates.md @ngaskill
/doc/user/group/devops_adoption/index.md @fneill
/doc/user/group/epics/epic_boards.md @msedlakjakubowski
/doc/user/group/epics/index.md @msedlakjakubowski
/doc/user/group/epics/linked_epics.md @msedlakjakubowski
/doc/user/group/epics/manage_epics.md @msedlakjakubowski
/doc/user/group/import/index.md @ngaskill
/doc/user/group/index.md @eread
/doc/user/group/import/index.md @ngaskill
/doc/user/group/insights/index.md @fneill
/doc/user/group/issues_analytics/index.md @msedlakjakubowski
/doc/user/group/iterations/index.md @msedlakjakubowski
@ -694,6 +716,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/user/group/saml_sso/group_managed_accounts.md @eread
/doc/user/group/saml_sso/index.md @eread
/doc/user/group/saml_sso/scim_setup.md @eread
/doc/user/group/settings/group_access_tokens.md @eread
/doc/user/group/settings/import_export.md @ngaskill
/doc/user/group/subgroups/index.md @eread
/doc/user/group/value_stream_analytics/index.md @fneill
@ -704,11 +727,13 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/user/infrastructure/clusters/manage/management_project_applications/falco.md @ngaskill
/doc/user/infrastructure/clusters/manage/management_project_applications/fluentd.md @ngaskill
/doc/user/infrastructure/iac/ @sselhorn
/doc/user/infrastructure/index.md @ssehorn
/doc/user/infrastructure/index.md @sselhorn
/doc/user/markdown.md @aqualls
/doc/user/packages/ @ngaskill
/doc/user/packages/infrastructure_registry/index.md @sselhorn
/doc/user/packages/terraform_module_registry/index.md @sselhorn
/doc/user/packages/workflows/project_registry.md @ngaskill
/doc/user/packages/workflows/working_with_monorepos.md @ngaskill
/doc/user/permissions.md @eread
/doc/user/profile/ @eread
/doc/user/profile/notifications.md @msedlakjakubowski
@ -734,6 +759,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/user/project/integrations/prometheus.md @ngaskill
/doc/user/project/issue_board.md @msedlakjakubowski
/doc/user/project/issues/ @msedlakjakubowski
/doc/user/project/issues/csv_import.md @ngaskill
/doc/user/project/labels.md @msedlakjakubowski
/doc/user/project/members/index.md @eread
/doc/user/project/members/share_project_with_groups.md @fneill
@ -748,7 +774,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/user/project/merge_requests/test_coverage_visualization.md @eread
/doc/user/project/merge_requests/testing_and_reports_in_merge_requests.md @eread
/doc/user/project/milestones/ @msedlakjakubowski
/doc/user/project/pages/ @rdickenson
/doc/user/project/pages/ @aqualls
/doc/user/project/protected_branches.md @aqualls
/doc/user/project/protected_tags.md @aqualls
/doc/user/project/push_options.md @aqualls
@ -768,6 +794,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/user/project/wiki/group.md @aqualls
/doc/user/project/wiki/index.md @aqualls
/doc/user/project/working_with_projects.md @fneill
/doc/user/public_access.md @fneill
/doc/user/reserved_names.md @fneill
/doc/user/search/advanced_search.md @rdickenson
/doc/user/search/index.md @aqualls

View File

@ -93,9 +93,9 @@ export default {
</a>
</div>
<div
v-safe-html="content"
class="gl-white-space-pre-wrap! gl-text-transparent"
data-testid="content"
v-text="content"
></div>
</div>
</gl-intersection-observer>

View File

@ -26,6 +26,7 @@ class Projects::MilestonesController < Projects::ApplicationController
respond_to do |format|
format.html do
@milestone_states = Milestone.states_count(@project)
# We need to show group milestones in the JSON response
# so that people can filter by and assign group milestones,
# but we don't need to show them on the project milestones page itself.

View File

@ -63,21 +63,6 @@ module TimeboxesHelper
issues.size
end
# Returns count of milestones for different states
# Uses explicit hash keys as the 'opened' state URL params differs from the db value
# and we need to add the total
# rubocop: disable CodeReuse/ActiveRecord
def milestone_counts(milestones)
counts = milestones.reorder(nil).group(:state).count
{
opened: counts['active'] || 0,
closed: counts['closed'] || 0,
all: counts.values.sum || 0
}
end
# rubocop: enable CodeReuse/ActiveRecord
def milestone_progress_tooltip_text(milestone)
has_issues = milestone.total_issues_count > 0

View File

@ -12,16 +12,29 @@
path: '-/milestones/new', label: 'New milestone',
include_groups: true, type: :milestones
.top-area
= render 'shared/milestones_filter', counts: @milestone_states
.nav-controls
= render 'shared/milestones/search_form'
- if @milestone_states.any? { |name, count| count > 0 }
.top-area
= render 'shared/milestones_filter', counts: @milestone_states
.nav-controls
= render 'shared/milestones/search_form'
- if @milestones.blank?
= render 'shared/empty_states/milestones'
- if @milestones.blank?
= render 'shared/empty_states/milestones_tab', active_tab: params[:state] do
- if current_user
.page-title-controls
= render 'shared/new_project_item_select',
path: '-/milestones/new', label: 'New milestone',
include_groups: true, type: :milestones
- else
.milestones
%ul.content-list
- @milestones.each do |milestone|
= render 'milestone', milestone: milestone
= paginate @milestones, theme: 'gitlab'
- else
.milestones
%ul.content-list
- @milestones.each do |milestone|
= render 'milestone', milestone: milestone
= paginate @milestones, theme: 'gitlab'
= render 'shared/empty_states/milestones' do
- if current_user
.page-title-controls
= render 'shared/new_project_item_select',
path: '-/milestones/new', label: 'New milestone',
include_groups: true, type: :milestones

View File

@ -1,23 +1,32 @@
- page_title _("Milestones")
- add_page_specific_style 'page_bundles/milestone'
.top-area
= render 'shared/milestones_filter', counts: @milestone_states
- if @milestone_states.any? { |name, count| count > 0 }
.top-area
= render 'shared/milestones_filter', counts: @milestone_states
.nav-controls
= render 'shared/milestones/search_form'
= render 'shared/milestones_sort_dropdown'
- if can?(current_user, :admin_milestone, @group)
= link_to _('New milestone'), new_group_milestone_path(@group), class: "btn gl-button btn-confirm", data: { qa_selector: "new_group_milestone_link" }
.nav-controls
= render 'shared/milestones/search_form'
= render 'shared/milestones_sort_dropdown'
- if can?(current_user, :admin_milestone, @group)
= link_to _('New milestone'), new_group_milestone_path(@group), class: "btn gl-button btn-confirm", data: { qa_selector: "new_group_milestone_link" }
- if @milestones.blank?
= render 'shared/empty_states/milestones'
- if @milestones.blank?
= render 'shared/empty_states/milestones_tab', learn_more_path: help_page_path('user/group/milestones') do
- if can?(current_user, :admin_milestone, @group)
.text-center
= link_to _('New milestone'), new_group_milestone_path(@group), class: "btn gl-button btn-confirm", data: { qa_selector: "new_group_milestone_link" }
- else
.milestones
%ul.content-list
- @milestones.each do |milestone|
- if milestone.project_milestone?
= render 'projects/milestones/milestone', milestone: milestone
- else
= render 'milestone', milestone: milestone
= paginate @milestones, theme: "gitlab"
- else
.milestones
%ul.content-list
- @milestones.each do |milestone|
- if milestone.project_milestone?
= render 'projects/milestones/milestone', milestone: milestone
- else
= render 'milestone', milestone: milestone
= paginate @milestones, theme: "gitlab"
= render 'shared/empty_states/milestones', learn_more_path: help_page_path('user/group/milestones') do
- if can?(current_user, :admin_milestone, @group)
.text-center
= link_to _('New milestone'), new_group_milestone_path(@group), class: "btn gl-button btn-confirm", data: { qa_selector: "new_group_milestone_link" }

View File

@ -1,24 +1,36 @@
- page_title _('Milestones')
- add_page_specific_style 'page_bundles/milestone'
.top-area
= render 'shared/milestones_filter', counts: milestone_counts(@project.milestones)
- if @milestone_states.any? { |name, count| count > 0 }
.top-area
= render 'shared/milestones_filter', counts: @milestone_states
.nav-controls
= render 'shared/milestones/search_form'
= render 'shared/milestones_sort_dropdown'
- if can?(current_user, :admin_milestone, @project)
= link_to new_project_milestone_path(@project), class: 'gl-button btn btn-confirm', data: { qa_selector: "new_project_milestone_link" }, title: _('New milestone') do
= _('New milestone')
.nav-controls
= render 'shared/milestones/search_form'
= render 'shared/milestones_sort_dropdown'
- if can?(current_user, :admin_milestone, @project)
= link_to new_project_milestone_path(@project), class: 'gl-button btn btn-confirm', data: { qa_selector: "new_project_milestone_link" }, title: _('New milestone') do
= _('New milestone')
- if @milestones.blank?
= render 'shared/empty_states/milestones'
- if @milestones.blank?
= render 'shared/empty_states/milestones_tab' do
- if can?(current_user, :admin_milestone, @project)
.text-center
= link_to new_project_milestone_path(@project), class: 'gl-button btn btn-confirm', data: { qa_selector: "new_project_milestone_link" }, title: _('New milestone') do
= _('New milestone')
- else
.milestones
#js-delete-milestone-modal
#promote-milestone-modal
%ul.content-list
= render @milestones
= paginate @milestones, theme: 'gitlab'
- else
.milestones
#js-delete-milestone-modal
#promote-milestone-modal
%ul.content-list
= render @milestones
= paginate @milestones, theme: 'gitlab'
= render 'shared/empty_states/milestones' do
- if can?(current_user, :admin_milestone, @project)
.text-center
= link_to new_project_milestone_path(@project), class: 'gl-button btn btn-confirm', data: { qa_selector: "new_project_milestone_link" }, title: _('New milestone') do
= _('New milestone')

View File

@ -1,7 +1,13 @@
- learn_more_path = local_assigns.fetch(:learn_more_path, help_page_path('user/project/milestones/index'))
- learn_more_link = link_to _('Learn more.'), learn_more_path
.row.empty-state
.col-12
.svg-content
= image_tag 'illustrations/milestone_burndown_chart.svg'
.col-12
.text-content
%h4.text-center= _('No milestones to show')
%h4= s_('Milestones|Use milestones to track issues and merge requests over a fixed period of time')
%p.state-description
= s_('Milestones|Organize issues and merge requests into a cohesive group, and set an optional start and due dates. %{learn_more_link}').html_safe % { learn_more_link: learn_more_link }
= yield

View File

@ -0,0 +1,17 @@
- learn_more_path = local_assigns.fetch(:learn_more_path, help_page_path('user/project/milestones/index'))
- learn_more_link = link_to _('Learn more.'), learn_more_path
- closed_tab_selected = params[:state] == 'closed'
.row.empty-state
.col-12
.svg-content
= image_tag 'illustrations/milestone_burndown_chart.svg'
.col-12
.text-content
- if closed_tab_selected
%h4.text-center= s_('Milestones|There are no closed milestones')
- else
%h4.text-center= s_('Milestones|There are no open milestones')
%p.state-description
= s_('Milestones|Create a milestone to better track your issues and merge requests. %{learn_more_link}').html_safe % { learn_more_link: learn_more_link }
= yield

View File

@ -61,8 +61,7 @@ To create an Auditor user:
1. On the left sidebar, select **Overview > Users**.
1. Create a new user or edit an existing one, and in the **Access** section
select Auditor.
1. Select **Create user** or **Save changes** if you created a new user or
edited an existing one respectively.
1. If you created a user, select **Create user**. For an existing user, select **Save changes**.
To revoke Auditor permissions from a user, make them a Regular user by
following the previous steps.

View File

@ -619,7 +619,7 @@ Note the following:
environment variable so that the Gitaly certificate is trusted. For example:
```shell
sudo SSL_CERT_DIR=/etc/gitlab/trusted_certs /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml dial-nodes
sudo SSL_CERT_DIR=/etc/gitlab/trusted-certs /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml dial-nodes
```
- You can configure Praefect servers with both an unencrypted listening address

View File

@ -1,6 +1,6 @@
---
stage: Release
group: Release
stage: Create
group: Editor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
description: 'Learn how to administer GitLab Pages.'
---
@ -1393,15 +1393,15 @@ in all of your GitLab Pages instances.
Connections will time out when using a Network Load Balancer with client IP preservation enabled and [the request is looped back to the source server](https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-troubleshooting.html#loopback-timeout).
This can happen to GitLab instances with multiple servers
running both the core GitLab application and GitLab Pages. This can also happen when a single
running both the core GitLab application and GitLab Pages. This can also happen when a single
container is running both the core GitLab application and GitLab Pages.
AWS [recommends using an IP target type](https://aws.amazon.com/premiumsupport/knowledge-center/target-connection-fails-load-balancer/)
to resolve this issue.
Turning off [client IP preservation](https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-target-groups.html#client-ip-preservation)
may resolve this issue when the core GitLab application and GitLab Pages run on the same host or
container.
Turning off [client IP preservation](https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-target-groups.html#client-ip-preservation)
may resolve this issue when the core GitLab application and GitLab Pages run on the same host or
container.
### 500 error with `securecookie: failed to generate random iv` and `Failed to save the session`

View File

@ -1,6 +1,6 @@
---
stage: Release
group: Release
stage: Create
group: Editor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -21,7 +21,7 @@ The readiness probe checks whether the Sidekiq workers are ready to process jobs
GET /readiness
```
Assuming you set up Sidekiq's address and port to be `localhost` and `8092` respectively,
If you set Sidekiq's address as `localhost` and port as `8092`,
here's an example request:
```shell
@ -44,7 +44,7 @@ Checks whether the Sidekiq cluster is running.
GET /liveness
```
Assuming you set up Sidekiq's address and port to be `localhost` and `8092` respectively,
If you set Sidekiq's address as `localhost` and port as `8092`,
here's an example request:
```shell

View File

@ -20,7 +20,7 @@ GET groups/:id/access_tokens
| Attribute | Type | required | Description |
|-----------|---------|----------|---------------------|
| `id` | integer or string | yes | The ID or [URL-encoded path of the group](index.md#namespaced-path-encoding) |
| `id` | integer or string | yes | ID or [URL-encoded path of the group](index.md#namespaced-path-encoding) |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/<group_id>/access_tokens"
@ -44,6 +44,41 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a
]
```
## Get a group access token
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/82714) in GitLab 14.10.
Get a [group access token](../user/group/settings/group_access_tokens.md) by ID.
```plaintext
GET groups/:id/access_tokens/:token_id
```
| Attribute | Type | required | Description |
|-----------|---------|----------|---------------------|
| `id` | integer or string | yes | ID or [URL-encoded path of the group](index.md#namespaced-path-encoding) |
| `token_id` | integer or string | yes | ID of the group access token |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/<group_id>/access_tokens/<token_id>"
```
```json
{
"user_id" : 141,
"scopes" : [
"api"
],
"name" : "token",
"expires_at" : "2021-01-31",
"id" : 42,
"active" : true,
"created_at" : "2021-01-20T22:11:48.151Z",
"revoked" : false,
"access_level": 40
}
```
## Create a group access token
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/77236) in GitLab 14.7.
@ -56,11 +91,11 @@ POST groups/:id/access_tokens
| Attribute | Type | required | Description |
|-----------|---------|----------|---------------------|
| `id` | integer or string | yes | The ID or [URL-encoded path of the group](index.md#namespaced-path-encoding) |
| `name` | String | yes | The name of the group access token |
| `id` | integer or string | yes | ID or [URL-encoded path of the group](index.md#namespaced-path-encoding) |
| `name` | String | yes | Name of the group access token |
| `scopes` | `Array[String]` | yes | [List of scopes](../user/group/settings/group_access_tokens.md#scopes-for-a-group-access-token) |
| `access_level` | Integer | no | A valid access level. Default value is 40 (Maintainer). Other allowed values are 10 (Guest), 20 (Reporter), and 30 (Developer). |
| `expires_at` | Date | no | The token expires at midnight UTC on that date |
| `expires_at` | Date | no | Token expires at midnight UTC on that date |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
@ -99,8 +134,8 @@ DELETE groups/:id/access_tokens/:token_id
| Attribute | Type | required | Description |
|-----------|---------|----------|---------------------|
| `id` | integer or string | yes | The ID or [URL-encoded path of the group](index.md#namespaced-path-encoding) |
| `token_id` | integer or string | yes | The ID of the group access token |
| `id` | integer or string | yes | ID or [URL-encoded path of the group](index.md#namespaced-path-encoding) |
| `token_id` | integer or string | yes | ID of the group access token |
```shell
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/<group_id>/access_tokens/<token_id>"

View File

@ -1,6 +1,6 @@
---
stage: Release
group: Release
stage: Create
group: Editor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,6 +1,6 @@
---
stage: Release
group: Release
stage: Create
group: Editor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -20,7 +20,7 @@ GET projects/:id/access_tokens
| Attribute | Type | required | Description |
|-----------|---------|----------|---------------------|
| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) |
| `id` | integer or string | yes | ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/<project_id>/access_tokens"
@ -44,6 +44,42 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a
]
```
## Get a project access token
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/82714) in GitLab 14.10.
Get a [project access token](../user/project/settings/project_access_tokens.md) by ID.
```plaintext
GET projects/:id/access_tokens/:token_id
```
| Attribute | Type | required | Description |
|-----------|---------|----------|---------------------|
| `id` | integer or string | yes | ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) |
| `token_id` | integer or string | yes | ID of the project access token |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/<project_id>/access_tokens/<token_id>"
```
```json
{
"user_id" : 141,
"scopes" : [
"api"
],
"name" : "token",
"expires_at" : "2021-01-31",
"id" : 42,
"active" : true,
"created_at" : "2021-01-20T22:11:48.151Z",
"revoked" : false,
"access_level": 40,
"last_used_at": "2022-03-15T11:05:42.437Z"
}
```
## Create a project access token
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55408) in GitLab 13.10.
@ -56,11 +92,11 @@ POST projects/:id/access_tokens
| Attribute | Type | required | Description |
|-----------|---------|----------|---------------------|
| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) |
| `name` | String | yes | The name of the project access token |
| `id` | integer or string | yes | ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) |
| `name` | String | yes | Name of the project access token |
| `scopes` | `Array[String]` | yes | [List of scopes](../user/project/settings/project_access_tokens.md#scopes-for-a-project-access-token) |
| `access_level` | Integer | no | A valid access level. Default value is 40 (Maintainer). Other allowed values are 10 (Guest), 20 (Reporter), and 30 (Developer). |
| `expires_at` | Date | no | The token expires at midnight UTC on that date |
| `expires_at` | Date | no | Token expires at midnight UTC on that date |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
@ -99,8 +135,8 @@ DELETE projects/:id/access_tokens/:token_id
| Attribute | Type | required | Description |
|-----------|---------|----------|---------------------|
| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) |
| `token_id` | integer or string | yes | The ID of the project access token |
| `id` | integer or string | yes | ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) |
| `token_id` | integer or string | yes | ID of the project access token |
```shell
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/<project_id>/access_tokens/<token_id>"

View File

@ -15,7 +15,7 @@ This feature is in a [Beta](../../policy/alpha-beta-support.md#beta-features) st
It may be useful to require additional approvals before deploying to certain protected environments (for example, production). This pre-deployment approval requirement is useful to accommodate testing, security, or compliance processes that must happen before each deployment.
When a protected environment requires one or more approvals, all deployments to that environment become blocked and wait for the required approvals before running.
When a protected environment requires one or more approvals, all deployments to that environment become blocked and wait for the required approvals from the `Allowed to Deploy` list before running.
NOTE:
See the [epic](https://gitlab.com/groups/gitlab-org/-/epics/6832) for planned features.

View File

@ -729,6 +729,19 @@ Do not use **Reporter permissions**. A user who is assigned the Reporter role ha
Use title case for **Repository Mirroring**.
## respectively
Avoid **respectively** and be more precise instead.
Use:
- To create a user, select **Create user**. For an existing user, select **Save changes**.
Instead of:
- Select **Create user** or **Save changes** if you created a new user or
edited an existing one respectively.
## roles
Do not use **roles** and [**permissions**](#permissions) interchangeably. Each user is assigned a role. Each role includes a set of permissions.

View File

@ -730,6 +730,11 @@ Refer to the documentation for your SAML Identity Provider for information on ho
The [Generated passwords for users created through integrated authentication](../security/passwords_for_integrated_authentication_methods.md) guide provides an overview of how GitLab generates and sets passwords for users created via SAML.
## Link SAML identity for an existing user
A user can manually link their SAML identity to an existing GitLab account by following the steps in
[Enable OmniAuth for an existing user](omniauth.md#enable-omniauth-for-an-existing-user).
## Configuring Group SAML on a self-managed GitLab instance **(PREMIUM SELF)**
For information on the GitLab.com implementation, please see the [SAML SSO for GitLab.com groups page](../user/group/saml_sso).

View File

@ -1,7 +1,7 @@
---
type: concepts
stage: Release
group: Release
stage: Create
group: Editor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,7 +1,7 @@
---
disqus_identifier: 'https://docs.gitlab.com/ee/user/project/pages/getting_started_part_three.html'
stage: Release
group: Release
stage: Create
group: Editor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,8 +1,8 @@
---
type: reference
description: "Automatic Let's Encrypt SSL certificates for GitLab Pages."
stage: Release
group: Release
stage: Create
group: Editor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,7 +1,7 @@
---
type: concepts
stage: Release
group: Release
stage: Create
group: Editor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,7 +1,7 @@
---
type: reference, howto
stage: Release
group: Release
stage: Create
group: Editor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,7 +1,7 @@
---
type: reference, howto
stage: Release
group: Release
stage: Create
group: Editor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,6 +1,6 @@
---
stage: Release
group: Release
stage: Create
group: Editor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,6 +1,6 @@
---
stage: Release
group: Release
stage: Create
group: Editor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,6 +1,6 @@
---
stage: Release
group: Release
stage: Create
group: Editor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,7 +1,7 @@
---
description: 'Learn how to use GitLab Pages to deploy a static website at no additional cost.'
stage: Release
group: Release
stage: Create
group: Editor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,6 +1,6 @@
---
stage: Release
group: Release
stage: Create
group: Editor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,6 +1,6 @@
---
stage: Release
group: Release
stage: Create
group: Editor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -1,6 +1,6 @@
---
stage: Release
group: Release
stage: Create
group: Editor
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---

View File

@ -27,6 +27,28 @@ module API
present paginate(tokens), with: Entities::ResourceAccessToken, resource: resource
end
desc 'Get an access token for the specified resource by ID' do
detail 'This feature was introduced in GitLab 14.10.'
end
params do
requires :id, type: String, desc: "The #{source_type} ID"
requires :token_id, type: String, desc: "The ID of the token"
end
get ":id/access_tokens/:token_id" do
resource = find_source(source_type, params[:id])
next unauthorized! unless current_user.can?(:read_resource_access_tokens, resource)
token = find_token(resource, params[:token_id])
if token.nil?
next not_found!("Could not find #{source_type} access token with token_id: #{params[:token_id]}")
end
resource.members.load
present token, with: Entities::ResourceAccessToken, resource: resource
end
desc 'Revoke a resource access token' do
detail 'This feature was introduced in GitLab 13.9.'
end

View File

@ -17,6 +17,10 @@ module Gitlab
Runner.new(direction: :down, migrations: migrations_for_down, result_dir: BASE_RESULT_DIR.join('down'))
end
def background_migrations
TestBackgroundRunner.new(result_dir: BASE_RESULT_DIR.join('background_migrations'))
end
def migration_context
@migration_context ||= ApplicationRecord.connection.migration_context
end

View File

@ -4,12 +4,10 @@ module Gitlab
module Database
module Migrations
class TestBackgroundRunner
# TODO - build a rake task to call this method, and support it in the gitlab-com-database-testing project.
# Until then, we will inject a migration with a very high timestamp during database testing
# that calls this class to run jobs
# See https://gitlab.com/gitlab-org/database-team/gitlab-com-database-testing/-/issues/41 for details
attr_reader :result_dir
def initialize
def initialize(result_dir:)
@result_dir = result_dir
@job_coordinator = Gitlab::BackgroundMigration.coordinator_for_database(Gitlab::Database::MAIN_DATABASE_NAME)
end
@ -24,18 +22,30 @@ module Gitlab
# without .to_f, we do integer division
# For example, 3.minutes / 2 == 1.minute whereas 3.minutes / 2.to_f == (1.minute + 30.seconds)
duration_per_migration_type = for_duration / jobs_to_run.count.to_f
jobs_to_run.each do |_migration_name, jobs|
jobs_to_run.each do |migration_name, jobs|
run_until = duration_per_migration_type.from_now
jobs.shuffle.each do |j|
break if run_until <= Time.current
run_job(j)
end
run_jobs_for_migration(migration_name: migration_name, jobs: jobs, run_until: run_until)
end
end
private
def run_jobs_for_migration(migration_name:, jobs:, run_until:)
per_background_migration_result_dir = File.join(@result_dir, migration_name)
instrumentation = Instrumentation.new(result_dir: per_background_migration_result_dir)
batch_names = (1..).each.lazy.map { |i| "batch_#{i}"}
jobs.shuffle.each do |j|
break if run_until <= Time.current
instrumentation.observe(version: nil, name: batch_names.next, connection: ActiveRecord::Migration.connection) do
run_job(j)
end
end
end
def run_job(job)
Gitlab::BackgroundMigration.perform(job.args[0], job.args[1])
end

View File

@ -307,6 +307,13 @@ namespace :gitlab do
task down: :environment do
Gitlab::Database::Migrations::Runner.down.run
end
desc 'Sample traditional background migrations with instrumentation'
task :sample_background_migrations, [:duration_s] => [:environment] do |_t, args|
duration = args[:duration_s]&.to_i&.seconds || 30.minutes # Default of 30 minutes
Gitlab::Database::Migrations::Runner.background_migrations.run_jobs(for_duration: duration)
end
end
desc 'Run all pending batched migrations'

View File

@ -24091,6 +24091,9 @@ msgstr ""
msgid "Milestones|Completed Issues (closed)"
msgstr ""
msgid "Milestones|Create a milestone to better track your issues and merge requests. %{learn_more_link}"
msgstr ""
msgid "Milestones|Delete milestone"
msgstr ""
@ -24109,6 +24112,9 @@ msgstr ""
msgid "Milestones|Ongoing Issues (open and assigned)"
msgstr ""
msgid "Milestones|Organize issues and merge requests into a cohesive group, and set an optional start and due dates. %{learn_more_link}"
msgstr ""
msgid "Milestones|Project Milestone"
msgstr ""
@ -24127,12 +24133,21 @@ msgstr ""
msgid "Milestones|Reopen Milestone"
msgstr ""
msgid "Milestones|There are no closed milestones"
msgstr ""
msgid "Milestones|There are no open milestones"
msgstr ""
msgid "Milestones|This action cannot be reversed."
msgstr ""
msgid "Milestones|Unstarted Issues (open and unassigned)"
msgstr ""
msgid "Milestones|Use milestones to track issues and merge requests over a fixed period of time"
msgstr ""
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@ -25208,9 +25223,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
msgid "No milestones to show"
msgstr ""
msgid "No namespace"
msgstr ""

View File

@ -66,7 +66,7 @@ RSpec.describe 'Group milestones' do
context 'when no milestones' do
it 'renders no milestones text' do
visit group_milestones_path(group)
expect(page).to have_content('No milestones to show')
expect(page).to have_content('Use milestones to track issues and merge requests')
end
end

View File

@ -21,7 +21,7 @@ RSpec.describe "User deletes milestone", :js do
click_button("Delete")
click_button("Delete milestone")
expect(page).to have_content("No milestones to show")
expect(page).to have_content("Use milestones to track issues and merge requests over a fixed period of time")
visit(activity_project_path(project))

View File

@ -0,0 +1,31 @@
{
"type": "object",
"required": [
"id",
"name",
"user_id",
"active",
"created_at",
"expires_at",
"revoked",
"access_level",
"scopes",
"last_used_at"
],
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" },
"user_id": { "type": "integer" },
"active": { "type": "boolean" },
"created_at": { "type": "string", "format": "date-time" },
"expires_at": { "type": ["string", "null"], "format": "date" },
"revoked": { "type": "boolean" },
"access_level": { "type": "integer" },
"scopes": {
"type": "array",
"items": { "type": "string" }
},
"last_used_at": { "type": ["string", "null"], "format": "date-time" }
},
"additionalProperties": false
}

View File

@ -0,0 +1,4 @@
{
"type": "array",
"items": { "$ref": "resource_access_token.json" }
}

View File

@ -24,34 +24,6 @@ RSpec.describe TimeboxesHelper do
end
end
describe '#milestone_counts' do
let(:project) { create(:project) }
let(:counts) { helper.milestone_counts(project.milestones) }
context 'when there are milestones' do
it 'returns the correct counts' do
create_list(:active_milestone, 2, project: project)
create(:closed_milestone, project: project)
expect(counts).to eq(opened: 2, closed: 1, all: 3)
end
end
context 'when there are only milestones of one type' do
it 'returns the correct counts' do
create_list(:active_milestone, 2, project: project)
expect(counts).to eq(opened: 2, closed: 0, all: 2)
end
end
context 'when there are no milestones' do
it 'returns the correct counts' do
expect(counts).to eq(opened: 0, closed: 0, all: 0)
end
end
end
describe "#group_milestone_route" do
let(:group) { build_stubbed(:group) }
let(:subgroup) { build_stubbed(:group, parent: group, name: "Test Subgrp") }

View File

@ -124,4 +124,16 @@ RSpec.describe Gitlab::Database::Migrations::Runner do
expect(metadata).to match('version' => described_class::SCHEMA_VERSION)
end
end
describe '.background_migrations' do
it 'is a TestBackgroundRunner' do
expect(described_class.background_migrations).to be_a(Gitlab::Database::Migrations::TestBackgroundRunner)
end
it 'is configured with a result dir of /background_migrations' do
runner = described_class.background_migrations
expect(runner.result_dir).to eq(described_class::BASE_RESULT_DIR.join( 'background_migrations'))
end
end
end

View File

@ -11,11 +11,17 @@ RSpec.describe Gitlab::Database::Migrations::TestBackgroundRunner, :redis do
Sidekiq::Testing.disable! { ex.run }
end
let(:result_dir) { Dir.mktmpdir }
after do
FileUtils.rm_rf(result_dir)
end
context 'without jobs to run' do
it 'returns immediately' do
runner = described_class.new
runner = described_class.new(result_dir: result_dir)
expect(runner).not_to receive(:run_job)
described_class.new.run_jobs(for_duration: 1.second)
described_class.new(result_dir: result_dir).run_jobs(for_duration: 1.second)
end
end
@ -30,7 +36,7 @@ RSpec.describe Gitlab::Database::Migrations::TestBackgroundRunner, :redis do
context 'finding pending background jobs' do
it 'finds all the migrations' do
expect(described_class.new.traditional_background_migrations.to_a.size).to eq(5)
expect(described_class.new(result_dir: result_dir).traditional_background_migrations.to_a.size).to eq(5)
end
end
@ -53,12 +59,28 @@ RSpec.describe Gitlab::Database::Migrations::TestBackgroundRunner, :redis do
end
end
def expect_recorded_migration_runs(migrations_to_runs)
migrations_to_runs.each do |migration, runs|
path = File.join(result_dir, migration.name.demodulize)
num_subdirs = Pathname(path).children.count(&:directory?)
expect(num_subdirs).to eq(runs)
end
end
def expect_migration_runs(migrations_to_run_counts)
expect_migration_call_counts(migrations_to_run_counts)
yield
expect_recorded_migration_runs(migrations_to_run_counts)
end
it 'runs the migration class correctly' do
calls = []
define_background_migration(migration_name) do |i|
calls << i
end
described_class.new.run_jobs(for_duration: 1.second) # Any time would work here as we do not advance time
described_class.new(result_dir: result_dir).run_jobs(for_duration: 1.second) # Any time would work here as we do not advance time
expect(calls).to contain_exactly(1, 2, 3, 4, 5)
end
@ -67,9 +89,9 @@ RSpec.describe Gitlab::Database::Migrations::TestBackgroundRunner, :redis do
travel(1.minute)
end
expect_migration_call_counts(migration => 3)
described_class.new.run_jobs(for_duration: 3.minutes)
expect_migration_runs(migration => 3) do
described_class.new(result_dir: result_dir).run_jobs(for_duration: 3.minutes)
end
end
context 'with multiple migrations to run' do
@ -90,12 +112,12 @@ RSpec.describe Gitlab::Database::Migrations::TestBackgroundRunner, :redis do
travel(2.minutes)
end
expect_migration_call_counts(
expect_migration_runs(
migration => 2, # 1 minute jobs for 90 seconds, can finish the first and start the second
other_migration => 1 # 2 minute jobs for 90 seconds, past deadline after a single job
)
described_class.new.run_jobs(for_duration: 3.minutes)
) do
described_class.new(result_dir: result_dir).run_jobs(for_duration: 3.minutes)
end
end
it 'does not give leftover time to extra migrations' do
@ -107,12 +129,13 @@ RSpec.describe Gitlab::Database::Migrations::TestBackgroundRunner, :redis do
other_migration = define_background_migration(other_migration_name) do
travel(1.minute)
end
expect_migration_call_counts(
expect_migration_runs(
migration => 5,
other_migration => 2
)
described_class.new.run_jobs(for_duration: 3.minutes)
) do
described_class.new(result_dir: result_dir).run_jobs(for_duration: 3.minutes)
end
end
end
end

View File

@ -29,6 +29,8 @@ RSpec.describe API::ResourceAccessTokens do
token_ids = json_response.map { |token| token['id'] }
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(response).to match_response_schema('public_api/v4/resource_access_tokens')
expect(token_ids).to match_array(access_tokens.pluck(:id))
end
@ -131,6 +133,103 @@ RSpec.describe API::ResourceAccessTokens do
end
end
context "GET #{source_type}s/:id/access_tokens/:token_id" do
subject(:get_token) { get api("/#{source_type}s/#{resource_id}/access_tokens/#{token_id}", user) }
let_it_be(:project_bot) { create(:user, :project_bot) }
let_it_be(:token) { create(:personal_access_token, user: project_bot) }
let_it_be(:resource_id) { resource.id }
let_it_be(:token_id) { token.id }
before do
if source_type == 'project'
resource.add_maintainer(project_bot)
else
resource.add_owner(project_bot)
end
end
context "when the user has valid permissions" do
it "gets the #{source_type} access token from the #{source_type}" do
get_token
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('public_api/v4/resource_access_token')
expect(json_response["name"]).to eq(token.name)
expect(json_response["scopes"]).to eq(token.scopes)
if source_type == 'project'
expect(json_response["access_level"]).to eq(resource.team.max_member_access(token.user.id))
else
expect(json_response["access_level"]).to eq(resource.max_member_access_for_user(token.user))
end
expect(json_response["expires_at"]).to eq(token.expires_at.to_date.iso8601)
end
context "when using #{source_type} access token to GET other #{source_type} access token" do
let_it_be(:other_project_bot) { create(:user, :project_bot) }
let_it_be(:other_token) { create(:personal_access_token, user: other_project_bot) }
let_it_be(:token_id) { other_token.id }
before do
resource.add_maintainer(other_project_bot)
end
it "gets the #{source_type} access token from the #{source_type}" do
get_token
expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('public_api/v4/resource_access_token')
expect(json_response["name"]).to eq(other_token.name)
expect(json_response["scopes"]).to eq(other_token.scopes)
if source_type == 'project'
expect(json_response["access_level"]).to eq(resource.team.max_member_access(other_token.user.id))
else
expect(json_response["access_level"]).to eq(resource.max_member_access_for_user(other_token.user))
end
expect(json_response["expires_at"]).to eq(other_token.expires_at.to_date.iso8601)
end
end
context "when attempting to get a non-existent #{source_type} access token" do
let_it_be(:token_id) { non_existing_record_id }
it "does not get the token, and returns 404" do
get_token
expect(response).to have_gitlab_http_status(:not_found)
expect(response.body).to include("Could not find #{source_type} access token with token_id: #{token_id}")
end
end
context "when attempting to get a token that does not belong to the specified #{source_type}" do
let_it_be(:resource_id) { other_resource.id }
it "does not get the token, and returns 404" do
get_token
expect(response).to have_gitlab_http_status(:not_found)
expect(response.body).to include("Could not find #{source_type} access token with token_id: #{token_id}")
end
end
end
context "when the user does not have valid permissions" do
let_it_be(:user) { user_non_priviledged }
it "returns 401" do
get_token
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
end
context "DELETE #{source_type}s/:id/access_tokens/:token_id", :sidekiq_inline do
subject(:delete_token) { delete api("/#{source_type}s/#{resource_id}/access_tokens/#{token_id}", user) }

15
spec/support/fips.rb Normal file
View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
# rubocop: disable RSpec/EnvAssignment
RSpec.configure do |config|
config.around(:each, :fips_mode) do |example|
prior_value = ENV["FIPS_MODE"]
ENV["FIPS_MODE"] = "true"
example.run
ENV["FIPS_MODE"] = prior_value
end
end
# rubocop: enable RSpec/EnvAssignment

View File

@ -0,0 +1,78 @@
# frozen_string_literal: true
RSpec.shared_examples 'milestone empty states' do
include Devise::Test::ControllerHelpers
let_it_be(:user) { build(:user) }
let(:empty_state) { 'Use milestones to track issues and merge requests over a fixed period of time' }
before do
assign(:projects, [])
allow(view).to receive(:current_user).and_return(user)
end
context 'with no milestones' do
before do
assign(:milestones, [])
assign(:milestone_states, { opened: 0, closed: 0, all: 0 })
render
end
it 'shows empty state' do
expect(rendered).to have_content(empty_state)
end
it 'does not show tabs or searchbar' do
expect(rendered).not_to have_link('Open')
expect(rendered).not_to have_link('Closed')
expect(rendered).not_to have_link('All')
end
end
context 'with no open milestones' do
before do
allow(view).to receive(:milestone_path).and_return("/milestones/1")
assign(:milestones, [])
assign(:milestone_states, { opened: 0, closed: 1, all: 1 })
end
it 'shows tabs and searchbar', :aggregate_failures do
render
expect(rendered).not_to have_content(empty_state)
expect(rendered).to have_link('Open')
expect(rendered).to have_link('Closed')
expect(rendered).to have_link('All')
end
it 'shows empty state' do
render
expect(rendered).to have_content('There are no open milestones')
end
end
context 'with no closed milestones' do
before do
allow(view).to receive(:milestone_path).and_return("/milestones/1")
allow(view).to receive(:params).and_return(state: 'closed')
assign(:milestones, [])
assign(:milestone_states, { opened: 1, closed: 0, all: 1 })
end
it 'shows tabs and searchbar', :aggregate_failures do
render
expect(rendered).not_to have_content(empty_state)
expect(rendered).to have_link('Open')
expect(rendered).to have_link('Closed')
expect(rendered).to have_link('All')
end
it 'shows empty state on closed milestones' do
render
expect(rendered).to have_content('There are no closed milestones')
end
end
end

View File

@ -538,6 +538,20 @@ RSpec.describe 'gitlab:db namespace rake task', :silence_stdout do
subject
end
end
describe '#sample_background_migrations' do
it 'delegates to the migration runner with a default sample duration' do
expect(::Gitlab::Database::Migrations::Runner).to receive_message_chain(:background_migrations, :run_jobs).with(for_duration: 30.minutes)
run_rake_task('gitlab:db:migration_testing:sample_background_migrations')
end
it 'delegates to the migration runner with a configured sample duration' do
expect(::Gitlab::Database::Migrations::Runner).to receive_message_chain(:background_migrations, :run_jobs).with(for_duration: 100.seconds)
run_rake_task('gitlab:db:migration_testing:sample_background_migrations', '[100]')
end
end
end
describe '#execute_batched_migrations' do

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'dashboard/milestones/index.html.haml' do
it_behaves_like 'milestone empty states'
end

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'groups/milestones/index.html.haml' do
it_behaves_like 'milestone empty states'
end

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'projects/milestones/index.html.haml' do
it_behaves_like 'milestone empty states'
end