Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
1b6de87b5c
commit
5316a9bca9
53 changed files with 681 additions and 199 deletions
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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
|
||||
|
|
17
app/views/shared/empty_states/_milestones_tab.html.haml
Normal file
17
app/views/shared/empty_states/_milestones_tab.html.haml
Normal 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
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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`
|
||||
|
||||
|
|
|
@ -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
|
||||
---
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>"
|
||||
|
|
|
@ -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
|
||||
---
|
||||
|
||||
|
|
|
@ -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
|
||||
---
|
||||
|
||||
|
|
|
@ -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>"
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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
|
||||
---
|
||||
|
||||
|
|
|
@ -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
|
||||
---
|
||||
|
||||
|
|
|
@ -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
|
||||
---
|
||||
|
||||
|
|
|
@ -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
|
||||
---
|
||||
|
||||
|
|
|
@ -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
|
||||
---
|
||||
|
||||
|
|
|
@ -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
|
||||
---
|
||||
|
||||
|
|
|
@ -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
|
||||
---
|
||||
|
||||
|
|
|
@ -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
|
||||
---
|
||||
|
||||
|
|
|
@ -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
|
||||
---
|
||||
|
||||
|
|
|
@ -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
|
||||
---
|
||||
|
||||
|
|
|
@ -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
|
||||
---
|
||||
|
||||
|
|
|
@ -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
|
||||
---
|
||||
|
||||
|
|
|
@ -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
|
||||
---
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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 ""
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
31
spec/fixtures/api/schemas/public_api/v4/resource_access_token.json
vendored
Normal file
31
spec/fixtures/api/schemas/public_api/v4/resource_access_token.json
vendored
Normal 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
|
||||
}
|
4
spec/fixtures/api/schemas/public_api/v4/resource_access_tokens.json
vendored
Normal file
4
spec/fixtures/api/schemas/public_api/v4/resource_access_tokens.json
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"type": "array",
|
||||
"items": { "$ref": "resource_access_token.json" }
|
||||
}
|
|
@ -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") }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
15
spec/support/fips.rb
Normal 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
|
|
@ -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
|
|
@ -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
|
||||
|
|
7
spec/views/dashboard/milestones/index.html.haml_spec.rb
Normal file
7
spec/views/dashboard/milestones/index.html.haml_spec.rb
Normal 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
|
7
spec/views/groups/milestones/index.html.haml_spec.rb
Normal file
7
spec/views/groups/milestones/index.html.haml_spec.rb
Normal 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
|
7
spec/views/projects/milestones/index.html.haml_spec.rb
Normal file
7
spec/views/projects/milestones/index.html.haml_spec.rb
Normal 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
|
Loading…
Reference in a new issue