Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-11-20 01:11:55 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2019-11-20 01:11:55 +0300
commit5a8431feceba47fd8e1804d9aa1b1730606b71d5 (patch)
treee5df8e0ceee60f4af8093f5c4c2f934b8abced05 /doc
parent4d477238500c347c6553d335d920bedfc5a46869 (diff)
Add latest changes from gitlab-org/gitlab@12-5-stable-ee
Diffstat (limited to 'doc')
-rw-r--r--doc/README.md33
-rw-r--r--doc/administration/audit_events.md4
-rw-r--r--doc/administration/auth/ldap.md34
-rw-r--r--doc/administration/geo/disaster_recovery/background_verification.md5
-rw-r--r--doc/administration/geo/replication/configuration.md12
-rw-r--r--doc/administration/geo/replication/database.md5
-rw-r--r--doc/administration/geo/replication/object_storage.md2
-rw-r--r--doc/administration/geo/replication/troubleshooting.md143
-rw-r--r--doc/administration/geo/replication/using_a_geo_server.md8
-rw-r--r--doc/administration/geo/replication/version_specific_updates.md18
-rw-r--r--doc/administration/git_annex.md242
-rw-r--r--doc/administration/gitaly/index.md56
-rw-r--r--doc/administration/gitaly/praefect.md171
-rw-r--r--doc/administration/high_availability/README.md224
-rw-r--r--doc/administration/high_availability/consul.md17
-rw-r--r--doc/administration/high_availability/database.md87
-rw-r--r--doc/administration/high_availability/pgbouncer.md49
-rw-r--r--doc/administration/high_availability/redis.md2
-rw-r--r--doc/administration/incoming_email.md4
-rw-r--r--doc/administration/index.md20
-rw-r--r--doc/administration/integration/plantuml.md2
-rw-r--r--doc/administration/job_logs.md25
-rw-r--r--doc/administration/lfs/img/git-annex-branches.png (renamed from doc/workflow/lfs/images/git-annex-branches.png)bin32164 -> 32164 bytes
-rw-r--r--doc/administration/lfs/img/lfs-icon.png (renamed from doc/workflow/lfs/img/lfs-icon.png)bin4317 -> 4317 bytes
-rw-r--r--doc/administration/lfs/lfs_administration.md273
-rw-r--r--doc/administration/lfs/manage_large_binaries_with_git_lfs.md266
-rw-r--r--doc/administration/lfs/migrate_from_git_annex_to_git_lfs.md254
-rw-r--r--doc/administration/logs.md42
-rw-r--r--doc/administration/monitoring/gitlab_instance_administration_project/index.md3
-rw-r--r--doc/administration/monitoring/performance/img/performance_bar.pngbin33642 -> 71317 bytes
-rw-r--r--doc/administration/monitoring/performance/performance_bar.md13
-rw-r--r--doc/administration/monitoring/prometheus/index.md25
-rw-r--r--doc/administration/operations/index.md3
-rw-r--r--doc/administration/operations/sidekiq_memory_killer.md4
-rw-r--r--doc/administration/packages/container_registry.md8
-rw-r--r--doc/administration/pages/index.md119
-rw-r--r--doc/administration/repository_storage_paths.md4
-rw-r--r--doc/administration/repository_storage_types.md14
-rw-r--r--doc/administration/timezone.md37
-rw-r--r--doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md4
-rw-r--r--doc/administration/uploads.md4
-rw-r--r--doc/api/api_resources.md6
-rw-r--r--doc/api/audit_events.md116
-rw-r--r--doc/api/branches.md2
-rw-r--r--doc/api/commits.md29
-rw-r--r--doc/api/deployments.md29
-rw-r--r--doc/api/epic_links.md32
-rw-r--r--doc/api/epics.md40
-rw-r--r--doc/api/feature_flag_specs.md291
-rw-r--r--doc/api/feature_flags.md308
-rw-r--r--doc/api/geo_nodes.md12
-rw-r--r--doc/api/graphql/index.md5
-rw-r--r--doc/api/graphql/reference/gitlab_schema.graphql5422
-rw-r--r--doc/api/graphql/reference/gitlab_schema.json18749
-rw-r--r--doc/api/graphql/reference/index.md490
-rw-r--r--doc/api/group_clusters.md34
-rw-r--r--doc/api/groups.md4
-rw-r--r--doc/api/issues.md21
-rw-r--r--doc/api/license.md5
-rw-r--r--doc/api/merge_requests.md24
-rw-r--r--doc/api/packages.md45
-rw-r--r--doc/api/pages_domains.md71
-rw-r--r--doc/api/project_clusters.md39
-rw-r--r--doc/api/projects.md20
-rw-r--r--doc/api/releases/index.md2
-rw-r--r--doc/api/scim.md5
-rw-r--r--doc/api/search.md22
-rw-r--r--doc/api/services.md5
-rw-r--r--doc/api/settings.md16
-rw-r--r--doc/api/sidekiq_metrics.md6
-rw-r--r--doc/api/tags.md2
-rw-r--r--doc/api/users.md4
-rw-r--r--doc/api/visual_review_discussions.md40
-rw-r--r--doc/api/vulnerabilities.md114
-rw-r--r--doc/api/vulnerability_findings.md128
-rw-r--r--doc/ci/README.md2
-rw-r--r--doc/ci/chatops/README.md5
-rw-r--r--doc/ci/ci_cd_for_external_repos/bitbucket_integration.md2
-rw-r--r--doc/ci/ci_cd_for_external_repos/github_integration.md4
-rw-r--r--doc/ci/ci_cd_for_external_repos/index.md4
-rw-r--r--doc/ci/docker/using_docker_build.md25
-rw-r--r--doc/ci/environments.md6
-rw-r--r--doc/ci/examples/deployment/README.md4
-rw-r--r--doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/index.md4
-rw-r--r--doc/ci/examples/laravel_with_gitlab_and_envoy/index.md2
-rw-r--r--doc/ci/img/pipelines_junit_test_report_ui_v12_5.pngbin0 -> 15957 bytes
-rw-r--r--doc/ci/interactive_web_terminal/index.md2
-rw-r--r--doc/ci/introduction/index.md14
-rw-r--r--doc/ci/junit_test_reports.md24
-rw-r--r--doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md4
-rw-r--r--doc/ci/multi_project_pipelines.md7
-rw-r--r--doc/ci/pipelines.md34
-rw-r--r--doc/ci/quick_start/README.md4
-rw-r--r--doc/ci/variables/README.md33
-rw-r--r--doc/ci/variables/deprecated_variables.md12
-rw-r--r--doc/ci/variables/img/inherited_group_variables_v12_5.pngbin0 -> 73965 bytes
-rw-r--r--doc/ci/variables/predefined_variables.md210
-rw-r--r--doc/ci/yaml/README.md229
-rw-r--r--doc/development/README.md3
-rw-r--r--doc/development/api_graphql_styleguide.md94
-rw-r--r--doc/development/architecture.md2
-rw-r--r--doc/development/changelog.md5
-rw-r--r--doc/development/chatops_on_gitlabcom.md2
-rw-r--r--doc/development/code_review.md6
-rw-r--r--doc/development/contributing/index.md4
-rw-r--r--doc/development/contributing/issue_workflow.md2
-rw-r--r--doc/development/contributing/merge_request_workflow.md6
-rw-r--r--doc/development/creating_enums.md15
-rw-r--r--doc/development/database_debugging.md2
-rw-r--r--doc/development/database_review.md7
-rw-r--r--doc/development/documentation/index.md4
-rw-r--r--doc/development/documentation/site_architecture/index.md145
-rw-r--r--doc/development/documentation/site_architecture/release_process.md241
-rw-r--r--doc/development/documentation/styleguide.md19
-rw-r--r--doc/development/documentation/workflow.md2
-rw-r--r--doc/development/ee_features.md40
-rw-r--r--doc/development/event_tracking/index.md4
-rw-r--r--doc/development/fe_guide/development_process.md2
-rw-r--r--doc/development/fe_guide/graphql.md8
-rw-r--r--doc/development/fe_guide/style_guide_js.md12
-rw-r--r--doc/development/fe_guide/style_guide_scss.md2
-rw-r--r--doc/development/feature_flags/controls.md8
-rw-r--r--doc/development/feature_flags/development.md19
-rw-r--r--doc/development/geo.md29
-rw-r--r--doc/development/git_object_deduplication.md2
-rw-r--r--doc/development/gitaly.md7
-rw-r--r--doc/development/gotchas.md70
-rw-r--r--doc/development/i18n/externalization.md5
-rw-r--r--doc/development/i18n/merging_translations.md30
-rw-r--r--doc/development/i18n/translation.md2
-rw-r--r--doc/development/kubernetes.md51
-rw-r--r--doc/development/lfs.md2
-rw-r--r--doc/development/merge_request_performance_guidelines.md179
-rw-r--r--doc/development/migration_style_guide.md2
-rw-r--r--doc/development/packages.md108
-rw-r--r--doc/development/pipelines.md71
-rw-r--r--doc/development/policies.md15
-rw-r--r--doc/development/profiling.md4
-rw-r--r--doc/development/rake_tasks.md20
-rw-r--r--doc/development/repository_mirroring.md2
-rw-r--r--doc/development/sidekiq_style_guide.md228
-rw-r--r--doc/development/testing_guide/best_practices.md29
-rw-r--r--doc/development/testing_guide/end_to_end/best_practices.md28
-rw-r--r--doc/development/testing_guide/end_to_end/feature_flags.md27
-rw-r--r--doc/development/testing_guide/end_to_end/flows.md56
-rw-r--r--doc/development/testing_guide/end_to_end/index.md2
-rw-r--r--doc/development/testing_guide/end_to_end/page_objects.md59
-rw-r--r--doc/development/testing_guide/flaky_tests.md1
-rw-r--r--doc/development/testing_guide/frontend_testing.md77
-rw-r--r--doc/development/testing_guide/review_apps.md8
-rw-r--r--doc/development/understanding_explain_plans.md37
-rw-r--r--doc/development/utilities.md114
-rw-r--r--doc/gitlab-basics/README.md3
-rw-r--r--doc/gitlab-basics/feature_branch_workflow.md35
-rw-r--r--doc/gitlab-basics/fork-project.md2
-rw-r--r--doc/gitlab-basics/start-using-git.md2
-rw-r--r--doc/install/README.md2
-rw-r--r--doc/install/aws/index.md2
-rw-r--r--doc/install/installation.md28
-rw-r--r--doc/install/openshift_and_gitlab/index.md2
-rw-r--r--doc/install/requirements.md2
-rw-r--r--doc/integration/README.md96
-rw-r--r--doc/integration/bitbucket.md7
-rw-r--r--doc/integration/elasticsearch.md9
-rw-r--r--doc/integration/img/sourcegraph_admin_v12_5.pngbin0 -> 61520 bytes
-rw-r--r--doc/integration/img/sourcegraph_demo_v12_5.pngbin0 -> 97025 bytes
-rw-r--r--doc/integration/img/sourcegraph_popover_v12_5.pngbin0 -> 27925 bytes
-rw-r--r--doc/integration/img/sourcegraph_user_preferences_v12_5.pngbin0 -> 37710 bytes
-rw-r--r--doc/integration/saml.md2
-rw-r--r--doc/integration/slash_commands.md1
-rw-r--r--doc/integration/sourcegraph.md128
-rw-r--r--doc/integration/ultra_auth.md2
-rw-r--r--doc/intro/README.md4
-rw-r--r--doc/policy/maintenance.md67
-rw-r--r--doc/raketasks/backup_restore.md2
-rw-r--r--doc/raketasks/cleanup.md2
-rw-r--r--doc/security/webhooks.md19
-rw-r--r--doc/ssh/README.md2
-rw-r--r--doc/topics/autodevops/index.md271
-rw-r--r--doc/topics/autodevops/quick_start_guide.md6
-rw-r--r--doc/topics/git/index.md8
-rw-r--r--doc/topics/git/migrate_to_git_lfs/index.md6
-rw-r--r--doc/topics/git/partial_clone.md20
-rw-r--r--doc/topics/gitlab_flow.md330
-rw-r--r--doc/topics/img/gitlab_flow.png (renamed from doc/workflow/img/gitlab_flow.png)bin47430 -> 47430 bytes
-rw-r--r--doc/topics/img/gitlab_flow_ci_mr.png (renamed from doc/workflow/img/ci_mr.png)bin12024 -> 12024 bytes
-rw-r--r--doc/topics/img/gitlab_flow_close_issue_mr.png (renamed from doc/workflow/img/close_issue_mr.png)bin42108 -> 42108 bytes
-rw-r--r--doc/topics/img/gitlab_flow_environment_branches.png (renamed from doc/workflow/img/environment_branches.png)bin12354 -> 12354 bytes
-rw-r--r--doc/topics/img/gitlab_flow_four_stages.png (renamed from doc/workflow/img/four_stages.png)bin7124 -> 7124 bytes
-rw-r--r--doc/topics/img/gitlab_flow_git_pull.png (renamed from doc/workflow/img/git_pull.png)bin28701 -> 28701 bytes
-rw-r--r--doc/topics/img/gitlab_flow_gitdashflow.png (renamed from doc/workflow/img/gitdashflow.png)bin68177 -> 68177 bytes
-rw-r--r--doc/topics/img/gitlab_flow_github_flow.png (renamed from doc/workflow/img/github_flow.png)bin6173 -> 6173 bytes
-rw-r--r--doc/topics/img/gitlab_flow_good_commit.png (renamed from doc/workflow/img/good_commit.png)bin8740 -> 8740 bytes
-rw-r--r--doc/topics/img/gitlab_flow_merge_commits.png (renamed from doc/workflow/img/merge_commits.png)bin7564 -> 7564 bytes
-rw-r--r--doc/topics/img/gitlab_flow_merge_request.png (renamed from doc/workflow/img/merge_request.png)bin47225 -> 47225 bytes
-rw-r--r--doc/topics/img/gitlab_flow_messy_flow.png (renamed from doc/workflow/img/messy_flow.png)bin11663 -> 11663 bytes
-rw-r--r--doc/topics/img/gitlab_flow_mr_inline_comments.png (renamed from doc/workflow/img/mr_inline_comments.png)bin52503 -> 52503 bytes
-rw-r--r--doc/topics/img/gitlab_flow_production_branch.png (renamed from doc/workflow/img/production_branch.png)bin7262 -> 7262 bytes
-rw-r--r--doc/topics/img/gitlab_flow_rebase.png (renamed from doc/workflow/img/rebase.png)bin28939 -> 28939 bytes
-rw-r--r--doc/topics/img/gitlab_flow_release_branches.png (renamed from doc/workflow/img/release_branches.png)bin12736 -> 12736 bytes
-rw-r--r--doc/topics/img/gitlab_flow_remove_checkbox.png (renamed from doc/workflow/img/remove_checkbox.png)bin6904 -> 6904 bytes
-rw-r--r--doc/topics/index.md1
-rw-r--r--doc/university/README.md2
-rw-r--r--doc/university/support/README.md2
-rw-r--r--doc/university/training/gitlab_flow.md2
-rw-r--r--doc/update/README.md8
-rw-r--r--doc/user/admin_area/activating_deactivating_users.md66
-rw-r--r--doc/user/admin_area/blocking_unblocking_users.md48
-rw-r--r--doc/user/admin_area/diff_limits.md2
-rw-r--r--doc/user/admin_area/index.md4
-rw-r--r--doc/user/admin_area/monitoring/health_check.md63
-rw-r--r--doc/user/admin_area/settings/account_and_limit_settings.md2
-rw-r--r--doc/user/admin_area/settings/continuous_integration.md13
-rw-r--r--doc/user/admin_area/settings/email.md2
-rw-r--r--doc/user/admin_area/settings/img/two_factor_grace_period.pngbin0 -> 17591 bytes
-rw-r--r--doc/user/admin_area/settings/index.md1
-rw-r--r--doc/user/admin_area/settings/sign_in_restrictions.md56
-rw-r--r--doc/user/admin_area/settings/usage_statistics.md4
-rw-r--r--doc/user/admin_area/settings/visibility_and_access_controls.md2
-rw-r--r--doc/user/analytics/cycle_analytics.md54
-rw-r--r--doc/user/analytics/productivity_analytics.md11
-rw-r--r--doc/user/application_security/container_scanning/index.md71
-rw-r--r--doc/user/application_security/dast/index.md30
-rw-r--r--doc/user/application_security/dependency_list/img/dependency_list_v12_4.pngbin0 -> 137591 bytes
-rw-r--r--doc/user/application_security/dependency_list/index.md2
-rw-r--r--doc/user/application_security/dependency_scanning/index.md71
-rw-r--r--doc/user/application_security/index.md38
-rw-r--r--doc/user/application_security/license_compliance/index.md16
-rw-r--r--doc/user/application_security/sast/analyzers.md5
-rw-r--r--doc/user/application_security/sast/index.md44
-rw-r--r--doc/user/application_security/security_dashboard/img/group_security_dashboard_v12_3.pngbin61667 -> 0 bytes
-rw-r--r--doc/user/application_security/security_dashboard/img/group_security_dashboard_v12_4.pngbin0 -> 62965 bytes
-rw-r--r--doc/user/application_security/security_dashboard/index.md4
-rw-r--r--doc/user/clusters/applications.md195
-rw-r--r--doc/user/clusters/crossplane.md292
-rw-r--r--doc/user/clusters/img/advanced-settings-cluster-management-project-v12_5.pngbin0 -> 66251 bytes
-rw-r--r--doc/user/clusters/management_project.md46
-rw-r--r--doc/user/group/clusters/index.md17
-rw-r--r--[-rwxr-xr-x]doc/user/group/epics/img/epic_view_roadmap_v12.3.pngbin50491 -> 50491 bytes
-rw-r--r--[-rwxr-xr-x]doc/user/group/epics/img/epic_view_v12.3.pngbin61402 -> 61402 bytes
-rwxr-xr-xdoc/user/group/epics/img/epics_list_view_v12.3.pngbin39450 -> 0 bytes
-rw-r--r--doc/user/group/epics/img/epics_list_view_v12.5.pngbin0 -> 442541 bytes
-rw-r--r--doc/user/group/epics/index.md44
-rw-r--r--doc/user/group/index.md21
-rw-r--r--doc/user/group/roadmap/index.md2
-rw-r--r--doc/user/group/saml_sso/index.md57
-rw-r--r--doc/user/group/saml_sso/scim_setup.md31
-rw-r--r--doc/user/group/subgroups/index.md2
-rw-r--r--doc/user/img/todos_add_todo_sidebar.png (renamed from doc/workflow/img/todos_add_todo_sidebar.png)bin17524 -> 17524 bytes
-rw-r--r--doc/user/img/todos_icon.png (renamed from doc/workflow/img/todos_icon.png)bin4910 -> 4910 bytes
-rw-r--r--doc/user/img/todos_index.png (renamed from doc/workflow/img/todos_index.png)bin98239 -> 98239 bytes
-rw-r--r--doc/user/img/todos_mark_done_sidebar.png (renamed from doc/workflow/img/todos_mark_done_sidebar.png)bin17619 -> 17619 bytes
-rw-r--r--doc/user/img/todos_todo_list_item.png (renamed from doc/workflow/img/todo_list_item.png)bin18776 -> 18776 bytes
-rw-r--r--doc/user/incident_management/img/incident_management_settings.pngbin0 -> 45533 bytes
-rw-r--r--doc/user/incident_management/index.md131
-rw-r--r--doc/user/index.md19
-rw-r--r--doc/user/markdown.md8
-rw-r--r--doc/user/operations_dashboard/img/index_operations_dashboard_top_bar_icon.pngbin3922 -> 0 bytes
-rw-r--r--doc/user/operations_dashboard/index.md9
-rw-r--r--doc/user/packages/conan_repository/index.md2
-rw-r--r--doc/user/packages/dependency_proxy/index.md2
-rw-r--r--doc/user/packages/npm_registry/index.md18
-rw-r--r--doc/user/permissions.md10
-rw-r--r--doc/user/profile/account/delete_account.md57
-rw-r--r--doc/user/profile/img/notification_global_settings.png (renamed from doc/workflow/img/notification_global_settings.png)bin67652 -> 67652 bytes
-rw-r--r--doc/user/profile/img/notification_group_settings.png (renamed from doc/workflow/img/notification_group_settings.png)bin54362 -> 54362 bytes
-rw-r--r--doc/user/profile/img/notification_project_settings.png (renamed from doc/workflow/img/notification_project_settings.png)bin58864 -> 58864 bytes
-rw-r--r--doc/user/profile/index.md2
-rw-r--r--doc/user/profile/notifications.md231
-rw-r--r--doc/user/profile/preferences.md15
-rw-r--r--doc/user/project/clusters/add_remove_clusters.md730
-rw-r--r--doc/user/project/clusters/eks_and_gitlab/img/create_dns.pngbin23923 -> 0 bytes
-rw-r--r--doc/user/project/clusters/eks_and_gitlab/img/create_project.pngbin30568 -> 0 bytes
-rw-r--r--doc/user/project/clusters/eks_and_gitlab/img/deploy_apps.pngbin82157 -> 0 bytes
-rw-r--r--doc/user/project/clusters/eks_and_gitlab/index.md281
-rw-r--r--doc/user/project/clusters/img/add_cluster.png (renamed from doc/user/project/clusters/eks_and_gitlab/img/add_cluster.png)bin59516 -> 59516 bytes
-rw-r--r--doc/user/project/clusters/img/environment.png (renamed from doc/user/project/clusters/eks_and_gitlab/img/environment.png)bin20339 -> 20339 bytes
-rw-r--r--doc/user/project/clusters/img/kubernetes_pod_logs_v12_4.pngbin393690 -> 0 bytes
-rw-r--r--doc/user/project/clusters/img/kubernetes_pod_logs_v12_5.pngbin0 -> 183707 bytes
-rw-r--r--doc/user/project/clusters/img/pipeline.png (renamed from doc/user/project/clusters/eks_and_gitlab/img/pipeline.png)bin15288 -> 15288 bytes
-rw-r--r--doc/user/project/clusters/img/rbac.png (renamed from doc/user/project/clusters/eks_and_gitlab/img/rbac.png)bin15960 -> 15960 bytes
-rw-r--r--doc/user/project/clusters/img/sidebar_menu_pod_logs_v12_5.pngbin0 -> 13681 bytes
-rw-r--r--doc/user/project/clusters/index.md442
-rw-r--r--doc/user/project/clusters/kubernetes_pod_logs.md32
-rw-r--r--doc/user/project/clusters/runbooks/index.md4
-rw-r--r--doc/user/project/clusters/serverless/index.md140
-rw-r--r--[-rwxr-xr-x]doc/user/project/img/code_owners_approval_new_protected_branch_v12_4.pngbin141341 -> 141341 bytes
-rw-r--r--[-rwxr-xr-x]doc/user/project/img/code_owners_approval_protected_branch_v12_4.pngbin16195 -> 16195 bytes
-rw-r--r--doc/user/project/img/time_tracking_example_v12_2.png (renamed from doc/workflow/time_tracking/img/time_tracking_example_v12_2.png)bin16362 -> 16362 bytes
-rw-r--r--doc/user/project/img/time_tracking_sidebar_v8_16.png (renamed from doc/workflow/time_tracking/img/time_tracking_sidebar_v8_16.png)bin9068 -> 9068 bytes
-rw-r--r--doc/user/project/import/gitea.md2
-rw-r--r--doc/user/project/import/github.md2
-rw-r--r--doc/user/project/index.md3
-rw-r--r--doc/user/project/integrations/generic_alerts.md8
-rw-r--r--doc/user/project/integrations/gitlab_slack_application.md3
-rw-r--r--doc/user/project/integrations/img/embed_metrics_issue_template.pngbin0 -> 146220 bytes
-rw-r--r--doc/user/project/integrations/img/grafana_panel_v12_5.pngbin0 -> 44193 bytes
-rw-r--r--doc/user/project/integrations/img/grafana_sharing_dialog_v12_5.pngbin0 -> 41203 bytes
-rw-r--r--doc/user/project/integrations/img/heatmap_panel_type.pngbin0 -> 8272 bytes
-rw-r--r--doc/user/project/integrations/img/http_proxy_access_v12_5.pngbin0 -> 47813 bytes
-rw-r--r--doc/user/project/integrations/img/prometheus_dashboard_anomaly_panel_type.pngbin0 -> 41015 bytes
-rw-r--r--doc/user/project/integrations/img/rendered_grafana_embed_v12_5.pngbin0 -> 61194 bytes
-rw-r--r--doc/user/project/integrations/img/select_query_variables_v12_5.pngbin0 -> 7368 bytes
-rw-r--r--doc/user/project/integrations/jira.md3
-rw-r--r--doc/user/project/integrations/project_services.md2
-rw-r--r--doc/user/project/integrations/prometheus.md156
-rw-r--r--doc/user/project/integrations/prometheus_library/nginx_ingress.md2
-rw-r--r--doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md2
-rw-r--r--doc/user/project/issue_board.md2
-rw-r--r--doc/user/project/issues/associate_zoom_meeting.md42
-rw-r--r--doc/user/project/issues/csv_export.md4
-rw-r--r--doc/user/project/issues/design_management.md22
-rw-r--r--doc/user/project/issues/due_dates.md2
-rw-r--r--doc/user/project/issues/img/issue_weight.png (renamed from doc/workflow/issue_weight/issue.png)bin69564 -> 69564 bytes
-rw-r--r--doc/user/project/issues/img/select_all_designs_v12_4.pngbin1325569 -> 0 bytes
-rw-r--r--doc/user/project/issues/img/zoom-quickaction-button.pngbin117097 -> 53418 bytes
-rw-r--r--doc/user/project/issues/issue_data_and_actions.md16
-rw-r--r--doc/user/project/issues/issue_weight.md25
-rw-r--r--doc/user/project/labels.md4
-rw-r--r--doc/user/project/merge_requests/code_quality.md14
-rw-r--r--doc/user/project/merge_requests/creating_merge_requests.md156
-rw-r--r--doc/user/project/merge_requests/img/approvals_premium_project_edit_v12_3.pngbin21908 -> 0 bytes
-rw-r--r--doc/user/project/merge_requests/img/approvals_premium_project_edit_v12_5.pngbin0 -> 21293 bytes
-rw-r--r--[-rwxr-xr-x]doc/user/project/merge_requests/img/mr_approvals_by_code_owners_v12_4.pngbin26902 -> 26902 bytes
-rw-r--r--doc/user/project/merge_requests/index.md688
-rw-r--r--doc/user/project/merge_requests/merge_request_approvals.md6
-rw-r--r--doc/user/project/merge_requests/merge_when_pipeline_succeeds.md5
-rw-r--r--doc/user/project/merge_requests/reviewing_and_managing_merge_requests.md251
-rw-r--r--doc/user/project/merge_requests/versions.md11
-rw-r--r--doc/user/project/milestones/index.md61
-rw-r--r--doc/user/project/operations/error_tracking.md19
-rw-r--r--doc/user/project/operations/feature_flags.md31
-rw-r--r--doc/user/project/operations/img/error_details_v12_5.pngbin0 -> 522760 bytes
-rw-r--r--doc/user/project/operations/img/error_tracking_list.pngbin60762 -> 760603 bytes
-rw-r--r--doc/user/project/pages/custom_domains_ssl_tls_certification/index.md16
-rw-r--r--doc/user/project/pages/custom_domains_ssl_tls_certification/lets_encrypt_integration.md19
-rw-r--r--doc/user/project/pages/getting_started/fork_sample_project.md61
-rw-r--r--doc/user/project/pages/getting_started/new_or_existing_website.md45
-rw-r--r--doc/user/project/pages/getting_started/pages_bundled_template.md29
-rw-r--r--doc/user/project/pages/getting_started_part_one.md53
-rw-r--r--doc/user/project/pages/getting_started_part_two.md171
-rw-r--r--doc/user/project/pages/img/new_project_for_pages_v12_5.pngbin0 -> 71618 bytes
-rw-r--r--doc/user/project/pages/img/pages_workflow_v12_5.pngbin0 -> 29541 bytes
-rw-r--r--doc/user/project/pages/index.md85
-rw-r--r--doc/user/project/pages/introduction.md35
-rw-r--r--doc/user/project/pages/lets_encrypt_for_gitlab_pages.md4
-rw-r--r--doc/user/project/pages/pages_access_control.md48
-rw-r--r--doc/user/project/protected_branches.md11
-rw-r--r--doc/user/project/push_options.md30
-rw-r--r--doc/user/project/releases/img/edit_release_page_v12_5.pngbin0 -> 150927 bytes
-rw-r--r--doc/user/project/releases/img/milestone_list_with_releases_v12_5.pngbin0 -> 45454 bytes
-rw-r--r--doc/user/project/releases/img/milestone_with_releases_v12_5.pngbin0 -> 67529 bytes
-rw-r--r--doc/user/project/releases/img/new_tag_12_5.png (renamed from doc/workflow/releases/new_tag.png)bin42439 -> 42439 bytes
-rw-r--r--doc/user/project/releases/img/release_edit_button_v12_5.pngbin0 -> 87472 bytes
-rw-r--r--doc/user/project/releases/img/release_with_milestone_v12_5.pngbin0 -> 20197 bytes
-rw-r--r--doc/user/project/releases/img/tags_12_5.png (renamed from doc/workflow/releases/tags.png)bin44666 -> 44666 bytes
-rw-r--r--doc/user/project/releases/index.md131
-rw-r--r--doc/user/project/repository/file_finder.md45
-rw-r--r--doc/user/project/repository/forking_workflow.md55
-rw-r--r--doc/user/project/repository/img/file_finder_find_button.png (renamed from doc/workflow/img/file_finder_find_button.png)bin14565 -> 14565 bytes
-rw-r--r--doc/user/project/repository/img/file_finder_find_file.png (renamed from doc/workflow/img/file_finder_find_file.png)bin19478 -> 19478 bytes
-rw-r--r--doc/user/project/repository/img/forking_workflow_branch_select.png (renamed from doc/workflow/forking/branch_select.png)bin18042 -> 18042 bytes
-rw-r--r--doc/user/project/repository/img/forking_workflow_choose_namespace.png (renamed from doc/workflow/img/forking_workflow_choose_namespace.png)bin35084 -> 35084 bytes
-rw-r--r--doc/user/project/repository/img/forking_workflow_fork_button.png (renamed from doc/workflow/img/forking_workflow_fork_button.png)bin25754 -> 25754 bytes
-rw-r--r--doc/user/project/repository/img/forking_workflow_merge_request.png (renamed from doc/workflow/forking/merge_request.png)bin24625 -> 24625 bytes
-rw-r--r--doc/user/project/repository/img/forking_workflow_path_taken_error.png (renamed from doc/workflow/img/forking_workflow_path_taken_error.png)bin21497 -> 21497 bytes
-rw-r--r--doc/user/project/repository/img/repository_mirroring_copy_ssh_public_key_button.png (renamed from doc/workflow/img/copy_ssh_public_key_button.png)bin11225 -> 11225 bytes
-rw-r--r--doc/user/project/repository/img/repository_mirroring_force_update.png (renamed from doc/workflow/img/repository_mirroring_force_update.png)bin13586 -> 13586 bytes
-rw-r--r--doc/user/project/repository/img/repository_mirroring_pull_settings_lower.png (renamed from doc/workflow/img/repository_mirroring_pull_settings_lower.png)bin58056 -> 58056 bytes
-rw-r--r--doc/user/project/repository/img/repository_mirroring_pull_settings_upper.png (renamed from doc/workflow/img/repository_mirroring_pull_settings_upper.png)bin50084 -> 50084 bytes
-rw-r--r--doc/user/project/repository/img/repository_mirroring_push_settings.png (renamed from doc/workflow/img/repository_mirroring_push_settings.png)bin72515 -> 72515 bytes
-rw-r--r--doc/user/project/repository/index.md5
-rw-r--r--doc/user/project/repository/repository_mirroring.md430
-rw-r--r--doc/user/project/settings/index.md7
-rw-r--r--doc/user/project/time_tracking.md92
-rw-r--r--doc/user/search/advanced_search_syntax.md2
-rw-r--r--doc/user/search/img/issue_search_filter_v12_5.pngbin0 -> 504590 bytes
-rw-r--r--doc/user/search/index.md11
-rw-r--r--doc/user/shortcuts.md135
-rw-r--r--doc/user/todos.md142
-rw-r--r--doc/workflow/README.md55
-rw-r--r--doc/workflow/file_finder.md44
-rw-r--r--doc/workflow/forking_workflow.md54
-rw-r--r--doc/workflow/git_annex.md239
-rw-r--r--doc/workflow/git_lfs.md4
-rw-r--r--doc/workflow/gitlab_flow.md329
-rw-r--r--doc/workflow/issue_weight.md24
-rw-r--r--doc/workflow/lfs/lfs_administration.md272
-rw-r--r--doc/workflow/lfs/manage_large_binaries_with_git_lfs.md265
-rw-r--r--doc/workflow/lfs/migrate_from_git_annex_to_git_lfs.md255
-rw-r--r--doc/workflow/notifications.md175
-rw-r--r--doc/workflow/releases.md25
-rw-r--r--doc/workflow/repository_mirroring.md427
-rw-r--r--doc/workflow/shortcuts.md133
-rw-r--r--doc/workflow/time_tracking.md90
-rw-r--r--doc/workflow/timezone.md40
-rw-r--r--doc/workflow/todos.md141
-rw-r--r--doc/workflow/workflow.md34
398 files changed, 35347 insertions, 5911 deletions
diff --git a/doc/README.md b/doc/README.md
index 61265f94004..af573a3eb34 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -119,8 +119,8 @@ The following documentation relates to the DevOps **Plan** stage:
| [Related Issues](user/project/issues/related_issues.md) **(STARTER)** | Create a relationship between issues. |
| [Roadmap](user/group/roadmap/index.md) **(ULTIMATE)** | Visualize epic timelines. |
| [Service Desk](user/project/service_desk.md) **(PREMIUM)** | A simple way to allow people to create issues in your GitLab instance without needing their own user account. |
-| [Time Tracking](workflow/time_tracking.md) | Track time spent on issues and merge requests. |
-| [Todos](workflow/todos.md) | Keep track of work requiring attention with a chronological list displayed on a simple dashboard. |
+| [Time Tracking](user/project/time_tracking.md) | Track time spent on issues and merge requests. |
+| [Todos](user/todos.md) | Keep track of work requiring attention with a chronological list displayed on a simple dashboard. |
<div align="right">
<a type="button" class="btn btn-default" href="#overview">
@@ -177,7 +177,7 @@ The following documentation relates to the DevOps **Create** stage:
| [Protected branches](user/project/protected_branches.md) | Use protected branches. |
| [Push rules](push_rules/push_rules.md) **(STARTER)** | Additional control over pushes to your projects. |
| [Repositories](user/project/repository/index.md) | Manage source code repositories in GitLab's user interface. |
-| [Repository mirroring](workflow/repository_mirroring.md) **(STARTER)** | Push to or pull from repositories outside of GitLab |
+| [Repository mirroring](user/project/repository/repository_mirroring.md) **(STARTER)** | Push to or pull from repositories outside of GitLab |
| [Start a merge request](user/project/repository/web_editor.md#tips) | Start merge request when committing via GitLab's user interface. |
<div align="right">
@@ -188,13 +188,13 @@ The following documentation relates to the DevOps **Create** stage:
#### Merge Requests
-| Create Topics - Merge Requests | Description |
-|:------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------|
-| [Checking out merge requests locally](user/project/merge_requests/index.md#checkout-merge-requests-locally) | Tips for working with merge requests locally. |
-| [Cherry-picking](user/project/merge_requests/cherry_pick_changes.md) | Use GitLab for cherry-picking changes. |
-| [Merge request thread resolution](user/discussions/index.md#moving-a-single-thread-to-a-new-issue) | Resolve threads, move threads in a merge request to an issue, and only allow merge requests to be merged if all threads are resolved. |
-| [Merge requests](user/project/merge_requests/index.md) | Merge request management. |
-| [Work In Progress "WIP" merge requests](user/project/merge_requests/work_in_progress_merge_requests.md) | Prevent merges of work-in-progress merge requests. |
+| Create Topics - Merge Requests | Description |
+|:--------------------------------------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------|
+| [Checking out merge requests locally](user/project/merge_requests/reviewing_and_managing_merge_requests.md#checkout-merge-requests-locally) | Tips for working with merge requests locally. |
+| [Cherry-picking](user/project/merge_requests/cherry_pick_changes.md) | Use GitLab for cherry-picking changes. |
+| [Merge request thread resolution](user/discussions/index.md#moving-a-single-thread-to-a-new-issue) | Resolve threads, move threads in a merge request to an issue, and only allow merge requests to be merged if all threads are resolved. |
+| [Merge requests](user/project/merge_requests/index.md) | Merge request management. |
+| [Work In Progress "WIP" merge requests](user/project/merge_requests/work_in_progress_merge_requests.md) | Prevent merges of work-in-progress merge requests. |
<div align="right">
<a type="button" class="btn btn-default" href="#overview">
@@ -305,7 +305,7 @@ The following documentation relates to the DevOps **Configure** stage:
| Configure Topics | Description |
|:-----------------------------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------------------------|
| [Auto DevOps](topics/autodevops/index.md) | Automatically employ a complete DevOps lifecycle. |
-| [Create Kubernetes clusters on GKE](user/project/clusters/index.md#add-new-gke-cluster) | Use Google Kubernetes Engine and GitLab. |
+| [Create Kubernetes clusters](user/project/clusters/add_remove_clusters.md#add-new-cluster) | Use Kubernetes and GitLab. |
| [Executable Runbooks](user/project/clusters/runbooks/index.md) | Documented procedures that explain how to carry out particular processes. |
| [GitLab ChatOps](ci/chatops/README.md) | Interact with CI/CD jobs through chat services. |
| [Installing Applications](user/project/clusters/index.md#installing-applications) | Deploy Helm, Ingress, and Prometheus on Kubernetes. |
@@ -336,7 +336,8 @@ The following documentation relates to the DevOps **Monitor** stage:
| [GitLab Prometheus](administration/monitoring/prometheus/index.md) **(CORE ONLY)** | Configure the bundled Prometheus to collect various metrics from your GitLab instance. |
| [Health check](user/admin_area/monitoring/health_check.md) | GitLab provides liveness and readiness probes to indicate service health and reachability to required services. |
| [Prometheus project integration](user/project/integrations/prometheus.md) | Configure the Prometheus integration per project and monitor your CI/CD environments. |
-| [Prometheus metrics](user/project/integrations/prometheus_library/index.md) | Let Prometheus collect metrics from various services, like Kubernetes, NGINX, NGINX ingress controller, HAProxy, and Amazon Cloud Watch. |
+| [Prometheus metrics](user/project/integrations/prometheus_library/index.md) | Let Prometheus collect metrics from various services, like Kubernetes, NGINX, NGINX Ingress controller, HAProxy, and Amazon Cloud Watch. |
+| [Incident management](user/incident_management/index.md) | Use GitLab to help you better respond to incidents that may occur in your systems. |
<div align="right">
<a type="button" class="btn btn-default" href="#overview">
@@ -375,7 +376,7 @@ We have the following documentation to rapidly uplift your GitLab knowledge:
| Topic | Description |
|:-----------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------|
| [GitLab basics guides](gitlab-basics/README.md) | Start working on the command line and with GitLab. |
-| [GitLab Workflow](workflow/README.md) and [overview](https://about.gitlab.com/2016/10/25/gitlab-workflow-an-overview/) | Enhance your workflow with the best of GitLab Workflow. |
+| [GitLab workflow overview](https://about.gitlab.com/2016/10/25/gitlab-workflow-an-overview/) | Enhance your workflow with the best of GitLab Workflow. |
| [Get started with GitLab CI/CD](ci/quick_start/README.md) | Quickly implement GitLab CI/CD. |
| [Auto DevOps](topics/autodevops/index.md) | Learn more about GitLab's Auto DevOps. |
| [GitLab Markdown](user/markdown.md) | GitLab's advanced formatting system (GitLab Flavored Markdown) |
@@ -393,7 +394,7 @@ Learn more about GitLab account management:
| Topic | Description |
|:-----------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------|
| [User account](user/profile/index.md) | Manage your account. |
-| [Authentication](topics/authentication/index.md) | Account security with two-factor authentication, set up your ssh keys, and deploy keys for secure access to your projects. |
+| [Authentication](topics/authentication/index.md) | Account security with two-factor authentication, set up your SSH keys, and deploy keys for secure access to your projects. |
| [Profile settings](user/profile/index.md#profile-settings) | Manage your profile settings, two factor authentication, and more. |
| [User permissions](user/permissions.md) | Learn what each role in a project can do. |
@@ -411,7 +412,7 @@ Learn more about using Git, and using Git with GitLab:
|:----------------------------------------------------------------------------|:---------------------------------------------------------------------------|
| [Git](topics/git/index.md) | Getting started with Git, branching strategies, Git LFS, and advanced use. |
| [Git cheatsheet](https://about.gitlab.com/images/press/git-cheat-sheet.pdf) | Download a PDF describing the most used Git operations. |
-| [GitLab Flow](workflow/gitlab_flow.md) | Explore the best of Git with the GitLab Flow strategy. |
+| [GitLab Flow](topics/gitlab_flow.md) | Explore the best of Git with the GitLab Flow strategy. |
<div align="right">
<a type="button" class="btn btn-default" href="#overview">
@@ -426,7 +427,7 @@ If you are coming to GitLab from another platform, you'll find the following inf
| Topic | Description |
|:---------------------------------------------------------------|:---------------------------------------------------------------------------------------|
| [Importing to GitLab](user/project/import/index.md) | Import your projects from GitHub, Bitbucket, GitLab.com, FogBugz, and SVN into GitLab. |
-| [Migrating from SVN](workflow/importing/migrating_from_svn.md) | Convert a SVN repository to Git and GitLab. |
+| [Migrating from SVN](user/project/import/svn.md) | Convert a SVN repository to Git and GitLab. |
<div align="right">
<a type="button" class="btn btn-default" href="#overview">
diff --git a/doc/administration/audit_events.md b/doc/administration/audit_events.md
index 61ea673071e..ccb4ccbd525 100644
--- a/doc/administration/audit_events.md
+++ b/doc/administration/audit_events.md
@@ -59,6 +59,8 @@ From there, you can see the following actions:
- 2FA enforcement/grace period changed
- Roles allowed to create project changed
+Group events can also be accessed via the [Group Audit Events API](../api/audit_events.md#group-audit-events-starter)
+
### Project events **(STARTER)**
NOTE: **Note:**
@@ -107,6 +109,8 @@ the filter drop-down. You can further filter by specific group, project or user
![audit log](img/audit_log.png)
+Instance events can also be accessed via the [Instance Audit Events API](../api/audit_events.md#instance-audit-events-premium-only)
+
### Missing events
Some events are not being tracked in Audit Events. Please see the following
diff --git a/doc/administration/auth/ldap.md b/doc/administration/auth/ldap.md
index e02ce1c0a21..d449a5a72af 100644
--- a/doc/administration/auth/ldap.md
+++ b/doc/administration/auth/ldap.md
@@ -118,6 +118,7 @@ LDAP users must have an email address set, regardless of whether it is used to l
```ruby
gitlab_rails['ldap_enabled'] = true
+gitlab_rails['prevent_ldap_sign_in'] = false
gitlab_rails['ldap_servers'] = YAML.load <<-EOS # remember to close this block with 'EOS' below
##
## 'main' is the GitLab 'provider ID' of this LDAP server
@@ -357,6 +358,7 @@ production:
# snip...
ldap:
enabled: false
+ prevent_ldap_sign_in: false
servers:
##
## 'main' is the GitLab 'provider ID' of this LDAP server
@@ -493,6 +495,38 @@ the configuration option `lowercase_usernames`. By default, this configuration o
1. [Restart GitLab](../restart_gitlab.md#installations-from-source) for the changes to take effect.
+## Disable LDAP web sign in
+
+It can be be useful to prevent using LDAP credentials through the web UI when
+an alternative such as SAML is preferred. This allows LDAP to be used for group
+sync, while also allowing your SAML identity provider to handle additional
+checks like custom 2FA.
+
+When LDAP web sign in is disabled, users will not see a **LDAP** tab on the sign in page.
+This does not disable [using LDAP credentials for Git access](#git-password-authentication).
+
+**Omnibus configuration**
+
+1. Edit `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ gitlab_rails['prevent_ldap_sign_in'] = true
+ ```
+
+1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
+
+**Source configuration**
+
+1. Edit `config/gitlab.yaml`:
+
+ ```yaml
+ production:
+ ldap:
+ prevent_ldap_sign_in: true
+ ```
+
+1. [Restart GitLab](../restart_gitlab.md#installations-from-source) for the changes to take effect.
+
## Encryption
### TLS Server Authentication
diff --git a/doc/administration/geo/disaster_recovery/background_verification.md b/doc/administration/geo/disaster_recovery/background_verification.md
index 34c668b5fb5..5caf1d53a2c 100644
--- a/doc/administration/geo/disaster_recovery/background_verification.md
+++ b/doc/administration/geo/disaster_recovery/background_verification.md
@@ -11,9 +11,8 @@ calculated checksum. If the checksum of the data on the **primary** node matches
data on the **secondary** node, the data transferred successfully. Following a planned failover,
any corrupted data may be **lost**, depending on the extent of the corruption.
-If verification fails on the **primary** node, this indicates that Geo is
-successfully replicating a corrupted object; restore it from backup or remove it
-it from the **primary** node to resolve the issue.
+If verification fails on the **primary** node, this indicates Geo is replicating a corrupted object.
+You can restore it from backup or remove it from the **primary** node to resolve the issue.
If verification succeeds on the **primary** node but fails on the **secondary** node,
this indicates that the object was corrupted during the replication process.
diff --git a/doc/administration/geo/replication/configuration.md b/doc/administration/geo/replication/configuration.md
index f09d9f20dab..44baab40153 100644
--- a/doc/administration/geo/replication/configuration.md
+++ b/doc/administration/geo/replication/configuration.md
@@ -187,14 +187,18 @@ keys must be manually replicated to the **secondary** node.
1. Visit the **primary** node's **Admin Area > Geo**
(`/admin/geo/nodes`) in your browser.
1. Click the **New node** button.
-1. Add the **secondary** node. Use the **exact** name you inputed for `gitlab_rails['geo_node_name']` as the Name and the full URL as the URL. **Do NOT** check the
- **This is a primary node** checkbox.
-
![Add secondary node](img/adding_a_secondary_node.png)
+1. Fill in **Name** with the `gitlab_rails['geo_node_name']` in
+ `/etc/gitlab/gitlab.rb`. These values must always match *exactly*, character
+ for character.
+1. Fill in **URL** with the `external_url` in `/etc/gitlab/gitlab.rb`. These
+ values must always match, but it doesn't matter if one ends with a `/` and
+ the other doesn't.
+1. **Do NOT** check the **This is a primary node** checkbox.
1. Optionally, choose which groups or storage shards should be replicated by the
**secondary** node. Leave blank to replicate all. Read more in
[selective synchronization](#selective-synchronization).
-1. Click the **Add node** button.
+1. Click the **Add node** button to add the **secondary** node.
1. SSH into your GitLab **secondary** server and restart the services:
```sh
diff --git a/doc/administration/geo/replication/database.md b/doc/administration/geo/replication/database.md
index fa1b0f0e1d7..f7da4e14e9d 100644
--- a/doc/administration/geo/replication/database.md
+++ b/doc/administration/geo/replication/database.md
@@ -425,6 +425,9 @@ data before running `pg_basebackup`.
--host=<primary_node_ip>
```
+ NOTE: **Note:**
+ Replication slot names must only contain lowercase letters, numbers, and the underscore character.
+
When prompted, enter the _plaintext_ password you set up for the `gitlab_replicator`
user in the first step.
@@ -454,7 +457,7 @@ The replication process is now complete.
## PgBouncer support (optional)
-[PgBouncer](http://pgbouncer.github.io/) may be used with GitLab Geo to pool
+[PgBouncer](https://www.pgbouncer.org/) may be used with GitLab Geo to pool
PostgreSQL connections. We recommend using PgBouncer if you use GitLab in a
high-availability configuration with a cluster of nodes supporting a Geo
**primary** node and another cluster of nodes supporting a Geo **secondary** node. For more
diff --git a/doc/administration/geo/replication/object_storage.md b/doc/administration/geo/replication/object_storage.md
index a9087abcbd9..3251a673e4e 100644
--- a/doc/administration/geo/replication/object_storage.md
+++ b/doc/administration/geo/replication/object_storage.md
@@ -30,7 +30,7 @@ To enable GitLab replication, you must:
checkbox.
For LFS, follow the documentation to
-[set up LFS object storage](../../../workflow/lfs/lfs_administration.md#storing-lfs-objects-in-remote-object-storage).
+[set up LFS object storage](../../lfs/lfs_administration.md#storing-lfs-objects-in-remote-object-storage).
For CI job artifacts, there is similar documentation to configure
[jobs artifact object storage](../../job_artifacts.md#using-object-storage)
diff --git a/doc/administration/geo/replication/troubleshooting.md b/doc/administration/geo/replication/troubleshooting.md
index 4d64941411a..d2fe02abbab 100644
--- a/doc/administration/geo/replication/troubleshooting.md
+++ b/doc/administration/geo/replication/troubleshooting.md
@@ -115,11 +115,19 @@ Any **secondary** nodes should point only to read-only instances.
#### Can Geo detect the current node correctly?
-Geo uses the defined node from the **Admin Area > Geo** screen, and tries to match
-it with the value defined in the `/etc/gitlab/gitlab.rb` configuration file.
-The relevant line looks like: `external_url "http://gitlab.example.com"`.
+Geo finds the current machine's name in `/etc/gitlab/gitlab.rb` by first looking
+for `gitlab_rails['geo_node_name']`. If it is not defined, then it defaults to
+the external URL defined in e.g. `external_url "http://gitlab.example.com"`. To
+get a machine's name, run:
-To check if the node on the current machine is correctly detected type:
+```sh
+sudo gitlab-rails runner "puts GeoNode.current_node_name"
+```
+
+This name is used to look up the node with the same **Name** in
+**Admin Area > Geo**.
+
+To check if current machine is correctly finding its node:
```sh
sudo gitlab-rails runner "puts Gitlab::Geo.current_node.inspect"
@@ -134,6 +142,106 @@ and expect something like:
By running the command above, `primary` should be `true` when executed in
the **primary** node, and `false` on any **secondary** node.
+## Fixing errors found when running the Geo check rake task
+
+When running this rake task, you may see errors if the nodes are not properly configured:
+
+```sh
+sudo gitlab-rake gitlab:geo:check
+```
+
+1. Rails did not provide a password when connecting to the database
+
+ ```text
+ Checking Geo ...
+
+ GitLab Geo is available ... Exception: fe_sendauth: no password supplied
+ GitLab Geo is enabled ... Exception: fe_sendauth: no password supplied
+ ...
+ Checking Geo ... Finished
+ ```
+
+ - Ensure that you have the `gitlab_rails['db_password']` set to the plain text-password used when creating the hash for `postgresql['sql_user_password']`.
+
+1. Rails is unable to connect to the database
+
+ ```text
+ Checking Geo ...
+
+ GitLab Geo is available ... Exception: FATAL: no pg_hba.conf entry for host "1.1.1.1", user "gitlab", database "gitlabhq_production", SSL on
+ FATAL: no pg_hba.conf entry for host "1.1.1.1", user "gitlab", database "gitlabhq_production", SSL off
+ GitLab Geo is enabled ... Exception: FATAL: no pg_hba.conf entry for host "1.1.1.1", user "gitlab", database "gitlabhq_production", SSL on
+ FATAL: no pg_hba.conf entry for host "1.1.1.1", user "gitlab", database "gitlabhq_production", SSL off
+ ...
+ Checking Geo ... Finished
+ ```
+
+ - Ensure that you have the IP address of the rails node included in `postgresql['md5_auth_cidr_addresses']`.
+ - Ensure that you have included the subnet mask on the IP address: `postgresql['md5_auth_cidr_addresses'] = ['1.1.1.1/32']`.
+
+1. Rails has supplied the incorrect password
+
+ ```text
+ Checking Geo ...
+ GitLab Geo is available ... Exception: FATAL: password authentication failed for user "gitlab"
+ FATAL: password authentication failed for user "gitlab"
+ GitLab Geo is enabled ... Exception: FATAL: password authentication failed for user "gitlab"
+ FATAL: password authentication failed for user "gitlab"
+ ...
+ Checking Geo ... Finished
+ ```
+
+ - Verify the correct password is set for `gitlab_rails['db_password']` that was used when creating the hash in `postgresql['sql_user_password']` by running `gitlab-ctl pg-password-md5 gitlab` and entering the password.
+
+1. Check returns not a secondary node
+
+ ```text
+ Checking Geo ...
+
+ GitLab Geo is available ... yes
+ GitLab Geo is enabled ... yes
+ GitLab Geo secondary database is correctly configured ... not a secondary node
+ Database replication enabled? ... not a secondary node
+ ...
+ Checking Geo ... Finished
+ ```
+
+ - Ensure that you have added the secondary node in the admin area of the primary node.
+ - Ensure that you entered the `external_url` or `gitlab_rails['geo_node_name']` when adding the secondary node in the admin are of the primary node.
+ - Prior to GitLab 12.4, edit the secondary node in the admin area of the primary node and ensure that there is a trailing `/` in the `Name` field.
+
+1. Check returns Exception: PG::UndefinedTable: ERROR: relation "geo_nodes" does not exist
+
+ ```text
+ Checking Geo ...
+
+ GitLab Geo is available ... no
+ Try fixing it:
+ Upload a new license that includes the GitLab Geo feature
+ For more information see:
+ https://about.gitlab.com/features/gitlab-geo/
+ GitLab Geo is enabled ... Exception: PG::UndefinedTable: ERROR: relation "geo_nodes" does not exist
+ LINE 8: WHERE a.attrelid = '"geo_nodes"'::regclass
+ ^
+ : SELECT a.attname, format_type(a.atttypid, a.atttypmod),
+ pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
+ c.collname, col_description(a.attrelid, a.attnum) AS comment
+ FROM pg_attribute a
+ LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
+ LEFT JOIN pg_type t ON a.atttypid = t.oid
+ LEFT JOIN pg_collation c ON a.attcollation = c.oid AND a.attcollation <> t.typcollation
+ WHERE a.attrelid = '"geo_nodes"'::regclass
+ AND a.attnum > 0 AND NOT a.attisdropped
+ ORDER BY a.attnum
+ ...
+ Checking Geo ... Finished
+ ```
+
+ When performing a Postgres major version (9 > 10) update this is expected. Follow:
+
+ - [initiate-the-replication-process](https://docs.gitlab.com/ee/administration/geo/replication/database.html#step-3-initiate-the-replication-process)
+ - [Geo database has an outdated FDW remote schema](https://docs.gitlab.com/ee/administration/geo/replication/troubleshooting.html#geo-database-has-an-outdated-fdw-remote-schema-error)
+
## Fixing replication errors
The following sections outline troubleshooting steps for fixing replication
@@ -258,7 +366,7 @@ to start again from scratch, there are a few steps that can help you:
gitlab-ctl tail sidekiq
```
-1. Rename repository storage folders and create new ones
+1. Rename repository storage folders and create new ones. If you are not concerned about possible orphaned directories and files, then you can simply skip this step.
```sh
mv /var/opt/gitlab/git-data/repositories /var/opt/gitlab/git-data/repositories.old
@@ -305,7 +413,9 @@ to start again from scratch, there are a few steps that can help you:
1. Reset the Tracking Database
```sh
- gitlab-rake geo:db:reset
+ gitlab-rake geo:db:drop
+ gitlab-ctl reconfigure
+ gitlab-rake geo:db:setup
```
1. Restart previously stopped services
@@ -511,6 +621,20 @@ to [cleanup orphan artifact files](../../../raketasks/cleanup.md#remove-orphan-a
On a Geo **secondary** node, this command will also clean up all Geo
registry record related to the orphan files on disk.
+## Fixing sign in errors
+
+### Message: The redirect URI included is not valid
+
+If you are able to log in to the **primary** node, but you receive this error
+when attempting to log into a **secondary**, you should check that the Geo
+node's URL matches its external URL.
+
+1. On the primary, visit **Admin Area > Geo**.
+1. Find the affected **secondary** and click **Edit**.
+1. Ensure the **URL** field matches the value found in `/etc/gitlab/gitlab.rb`
+ in `external_url "https://gitlab.example.com"` on the frontend server(s) of
+ the **secondary** node.
+
## Fixing common errors
This section documents common errors reported in the Admin UI and how to fix them.
@@ -531,13 +655,6 @@ Geo cannot reuse an existing tracking database.
It is safest to use a fresh secondary, or reset the whole secondary by following
[Resetting Geo secondary node replication](#resetting-geo-secondary-node-replication).
-If you are not concerned about possible orphaned directories and files, then you
-can simply reset the existing tracking database with:
-
-```sh
-sudo gitlab-rake geo:db:reset
-```
-
### Geo node has a database that is writable which is an indication it is not configured for replication with the primary node
This error refers to a problem with the database replica on a **secondary** node,
diff --git a/doc/administration/geo/replication/using_a_geo_server.md b/doc/administration/geo/replication/using_a_geo_server.md
index 55c7e78da92..37982f2756c 100644
--- a/doc/administration/geo/replication/using_a_geo_server.md
+++ b/doc/administration/geo/replication/using_a_geo_server.md
@@ -10,8 +10,12 @@ Example of the output you will see when pushing to a **secondary** node:
```bash
$ git push
-> GitLab: You're pushing to a Geo secondary.
-> GitLab: We'll help you by proxying this request to the primary: ssh://git@primary.geo/user/repo.git
+remote:
+remote: You're pushing to a Geo secondary. We'll help you by proxying this
+remote: request to the primary:
+remote:
+remote: ssh://git@primary.geo/user/repo.git
+remote:
Everything up-to-date
```
diff --git a/doc/administration/geo/replication/version_specific_updates.md b/doc/administration/geo/replication/version_specific_updates.md
index 6d550a49df4..5288cc6e186 100644
--- a/doc/administration/geo/replication/version_specific_updates.md
+++ b/doc/administration/geo/replication/version_specific_updates.md
@@ -4,6 +4,24 @@ Check this document if it includes instructions for the version you are updating
These steps go together with the [general steps](updating_the_geo_nodes.md#general-update-steps)
for updating Geo nodes.
+## Updating to GitLab 12.2
+
+GitLab 12.2 includes the following minor PostgreSQL updates:
+
+- To version `9.6.14` if you run PostgreSQL 9.6.
+- To version `10.9` if you run PostgreSQL 10.
+
+This update will occur even if major PostgreSQL updates are disabled.
+
+Before [refreshing Foreign Data Wrapper during a Geo HA upgrade](https://docs.gitlab.com/omnibus/update/README.html#run-post-deployment-migrations-and-checks),
+restart the Geo tracking database:
+
+```sh
+sudo gitlab-ctl restart geo-postgresql
+```
+
+The restart avoids a version mismatch when PostgreSQL tries to load the FDW extension.
+
## Updating to GitLab 12.1
By default, GitLab 12.1 will attempt to automatically update the
diff --git a/doc/administration/git_annex.md b/doc/administration/git_annex.md
new file mode 100644
index 00000000000..52d848efa27
--- /dev/null
+++ b/doc/administration/git_annex.md
@@ -0,0 +1,242 @@
+---
+disqus_identifier: 'https://docs.gitlab.com/ee/workflow/git_annex.html'
+---
+
+# Git annex
+
+> **Warning:** GitLab has [completely
+removed][deprecate-annex-issue] in GitLab 9.0 (2017/03/22).
+Read through the [migration guide from git-annex to Git LFS][guide].
+
+The biggest limitation of Git, compared to some older centralized version
+control systems, has been the maximum size of the repositories.
+
+The general recommendation is to not have Git repositories larger than 1GB to
+preserve performance. Although GitLab has no limit (some repositories in GitLab
+are over 50GB!), we subscribe to the advice to keep repositories as small as
+you can.
+
+Not being able to version control large binaries is a big problem for many
+larger organizations.
+Videos, photos, audio, compiled binaries and many other types of files are too
+large. As a workaround, people keep artwork-in-progress in a Dropbox folder and
+only check in the final result. This results in using outdated files, not
+having a complete history and increases the risk of losing work.
+
+This problem is solved in GitLab Enterprise Edition by integrating the
+[git-annex] application.
+
+`git-annex` allows managing large binaries with Git without checking the
+contents into Git.
+You check-in only a symlink that contains the SHA-1 of the large binary. If you
+need the large binary, you can sync it from the GitLab server over `rsync`, a
+very fast file copying tool.
+
+## GitLab git-annex Configuration
+
+`git-annex` is disabled by default in GitLab. Below you will find the
+configuration options required to enable it.
+
+### Requirements
+
+`git-annex` needs to be installed both on the server and the client side.
+
+For Debian-like systems (e.g., Debian, Ubuntu) this can be achieved by running:
+
+```
+sudo apt-get update && sudo apt-get install git-annex
+```
+
+For RedHat-like systems (e.g., CentOS, RHEL) this can be achieved by running:
+
+```
+sudo yum install epel-release && sudo yum install git-annex
+```
+
+### Configuration for Omnibus packages
+
+For Omnibus GitLab packages, only one configuration setting is needed.
+The Omnibus package will internally set the correct options in all locations.
+
+1. In `/etc/gitlab/gitlab.rb` add the following line:
+
+ ```ruby
+ gitlab_shell['git_annex_enabled'] = true
+ ```
+
+1. Save the file and [reconfigure GitLab][] for the changes to take effect.
+
+### Configuration for installations from source
+
+There are 2 settings to enable git-annex on your GitLab server.
+
+One is located in `config/gitlab.yml` of the GitLab repository and the other
+one is located in `config.yml` of GitLab Shell.
+
+1. In `config/gitlab.yml` add or edit the following lines:
+
+ ```yaml
+ gitlab_shell:
+ git_annex_enabled: true
+ ```
+
+1. In `config.yml` of GitLab Shell add or edit the following lines:
+
+ ```yaml
+ git_annex_enabled: true
+ ```
+
+1. Save the files and [restart GitLab][] for the changes to take effect.
+
+## Using GitLab git-annex
+
+> **Note:**
+> Your Git remotes must be using the SSH protocol, not HTTP(S).
+
+Here is an example workflow of uploading a very large file and then checking it
+into your Git repository:
+
+```bash
+git clone git@example.com:group/project.git
+
+git annex init 'My Laptop' # initialize the annex project and give an optional description
+cp ~/tmp/debian.iso ./ # copy a large file into the current directory
+git annex add debian.iso # add the large file to git annex
+git commit -am "Add Debian iso" # commit the file metadata
+git annex sync --content # sync the Git repo and large file to the GitLab server
+```
+
+The output should look like this:
+
+```
+commit
+On branch master
+Your branch is ahead of 'origin/master' by 1 commit.
+ (use "git push" to publish your local commits)
+nothing to commit, working tree clean
+ok
+pull origin
+remote: Counting objects: 5, done.
+remote: Compressing objects: 100% (4/4), done.
+remote: Total 5 (delta 2), reused 0 (delta 0)
+Unpacking objects: 100% (5/5), done.
+From example.com:group/project
+ 497842b..5162f80 git-annex -> origin/git-annex
+ok
+(merging origin/git-annex into git-annex...)
+(recording state in git...)
+copy debian.iso (checking origin...) (to origin...)
+SHA256E-s26214400--8092b3d482fb1b7a5cf28c43bc1425c8f2d380e86869c0686c49aa7b0f086ab2.iso
+ 26,214,400 100% 638.88kB/s 0:00:40 (xfr#1, to-chk=0/1)
+ok
+pull origin
+ok
+(recording state in git...)
+push origin
+Counting objects: 15, done.
+Delta compression using up to 4 threads.
+Compressing objects: 100% (13/13), done.
+Writing objects: 100% (15/15), 1.64 KiB | 0 bytes/s, done.
+Total 15 (delta 1), reused 0 (delta 0)
+To example.com:group/project.git
+ * [new branch] git-annex -> synced/git-annex
+ * [new branch] master -> synced/master
+ok
+```
+
+Your files can be found in the `master` branch, but you'll notice that there
+are more branches created by the `annex sync` command.
+
+Git Annex will also create a new directory at `.git/annex/` and will record the
+tracked files in the `.git/config` file. The files you assign to be tracked
+with `git-annex` will not affect the existing `.git/config` records. The files
+are turned into symbolic links that point to data in `.git/annex/objects/`.
+
+The `debian.iso` file in the example will contain the symbolic link:
+
+```
+.git/annex/objects/ZW/1k/SHA256E-s82701--6384039733b5035b559efd5a2e25a493ab6e09aabfd5162cc03f6f0ec238429d.png/SHA256E-s82701--6384039733b5035b559efd5a2e25a493ab6e09aabfd5162cc03f6f0ec238429d.iso
+```
+
+Use `git annex info` to retrieve the information about the local copy of your
+repository.
+
+---
+
+Downloading a single large file is also very simple:
+
+```bash
+git clone git@gitlab.example.com:group/project.git
+
+git annex sync # sync Git branches but not the large file
+git annex get debian.iso # download the large file
+```
+
+To download all files:
+
+```bash
+git clone git@gitlab.example.com:group/project.git
+
+git annex sync --content # sync Git branches and download all the large files
+```
+
+By using `git-annex` without GitLab, anyone that can access the server can also
+access the files of all projects, but GitLab Annex ensures that you can only
+access files of projects you have access to (developer, maintainer, or owner role).
+
+## How it works
+
+Internally GitLab uses [GitLab Shell] to handle SSH access and this was a great
+integration point for `git-annex`.
+There is a setting in GitLab Shell so you can disable GitLab Annex support
+if you want to.
+
+## Troubleshooting tips
+
+Differences in version of `git-annex` on the GitLab server and on local machines
+can cause `git-annex` to raise unpredicted warnings and errors.
+
+Consult the [Annex upgrade page][annex-upgrade] for more information about
+the differences between versions. You can find out which version is installed
+on your server by navigating to <https://pkgs.org/download/git-annex> and
+searching for your distribution.
+
+Although there is no general guide for `git-annex` errors, there are a few tips
+on how to go around the warnings.
+
+### `git-annex-shell: Not a git-annex or gcrypt repository`
+
+This warning can appear on the initial `git annex sync --content` and is caused
+by differences in `git-annex-shell`. You can read more about it
+[in this git-annex issue][issue].
+
+One important thing to note is that despite the warning, the `sync` succeeds
+and the files are pushed to the GitLab repository.
+
+If you get hit by this, you can run the following command inside the repository
+that the warning was raised:
+
+```
+git config remote.origin.annex-ignore false
+```
+
+Consecutive runs of `git annex sync --content` **should not** produce this
+warning and the output should look like this:
+
+```
+commit ok
+pull origin
+ok
+pull origin
+ok
+push origin
+```
+
+[annex-upgrade]: https://git-annex.branchable.com/upgrades/
+[deprecate-annex-issue]: https://gitlab.com/gitlab-org/gitlab/issues/1648
+[git-annex]: https://git-annex.branchable.com/ "git-annex website"
+[gitlab shell]: https://gitlab.com/gitlab-org/gitlab-shell "GitLab Shell repository"
+[guide]: lfs/migrate_from_git_annex_to_git_lfs.html
+[issue]: https://git-annex.branchable.com/forum/Error_from_git-annex-shell_on_creation_of_gcrypt_special_remote/ "git-annex issue"
+[reconfigure GitLab]: restart_gitlab.md#omnibus-gitlab-reconfigure
+[restart GitLab]: restart_gitlab.md#installations-from-source
diff --git a/doc/administration/gitaly/index.md b/doc/administration/gitaly/index.md
index d5749427f6e..82283650070 100644
--- a/doc/administration/gitaly/index.md
+++ b/doc/administration/gitaly/index.md
@@ -89,6 +89,10 @@ your GitLab installation has three repository storages: `default`,
`storage1` and `storage2`. You can use as little as just one server with one
repository storage if desired.
+Note: **Note:** The token referred to throughout the Gitaly documentation is
+just an arbitrary password selected by the administrator. It is unrelated to
+tokens created for the GitLab API or other similar web API tokens.
+
### 1. Installation
First install Gitaly on each Gitaly server using either
@@ -142,11 +146,6 @@ the Gitaly server. The easiest way to accomplish this is to copy `/etc/gitlab/gi
from an existing GitLab server to the Gitaly server. Without this shared secret,
Git operations in GitLab will result in an API error.
-NOTE: **Note:**
-In most or all cases, the storage paths below end in `/repositories` which is
-not the case with `path` in `git_data_dirs` of Omnibus GitLab installations.
-Check the directory layout on your Gitaly server to be sure.
-
**For Omnibus GitLab**
1. Edit `/etc/gitlab/gitlab.rb`:
@@ -193,24 +192,26 @@ Check the directory layout on your Gitaly server to be sure.
On `gitaly1.internal`:
```
- gitaly['storage'] = [
- { 'name' => 'default' },
- { 'name' => 'storage1' },
- ]
+ git_data_dirs({
+ 'default' => {
+ 'path' => '/var/opt/gitlab/git-data'
+ },
+ 'storage1' => {
+ 'path' => '/mnt/gitlab/git-data'
+ },
+ })
```
On `gitaly2.internal`:
```
- gitaly['storage'] = [
- { 'name' => 'storage2' },
- ]
+ git_data_dirs({
+ 'storage2' => {
+ 'path' => '/srv/gitlab/git-data'
+ },
+ })
```
- NOTE: **Note:**
- In some cases, you'll have to set `path` for `gitaly['storage']` in the
- format `'path' => '/mnt/gitlab/<storage name>/repositories'`.
-
1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
**For installations from source**
@@ -222,6 +223,11 @@ Check the directory layout on your Gitaly server to be sure.
[auth]
token = 'abc123secret'
+
+ [logging]
+ format = 'json'
+ level = 'info'
+ dir = '/var/log/gitaly'
```
1. Append the following to `/home/git/gitaly/config.toml` for each respective server:
@@ -231,9 +237,11 @@ Check the directory layout on your Gitaly server to be sure.
```toml
[[storage]]
name = 'default'
+ path = '/var/opt/gitlab/git-data/repositories'
[[storage]]
name = 'storage1'
+ path = '/mnt/gitlab/git-data/repositories'
```
On `gitaly2.internal`:
@@ -241,12 +249,9 @@ Check the directory layout on your Gitaly server to be sure.
```toml
[[storage]]
name = 'storage2'
+ path = '/srv/gitlab/git-data/repositories'
```
- NOTE: **Note:**
- In some cases, you'll have to set `path` for each `[[storage]]` in the
- format `path = '/mnt/gitlab/<storage name>/repositories'`.
-
1. Save the file and [restart GitLab](../restart_gitlab.md#installations-from-source).
### 4. Converting clients to use the Gitaly server
@@ -327,6 +332,8 @@ When you tail the Gitaly logs on your Gitaly server you should see requests
coming in. One sure way to trigger a Gitaly request is to clone a repository
from your GitLab server over HTTP.
+DANGER: **Danger:** If you have [custom server-side Git hooks](../custom_hooks.md#custom-server-side-git-hooks) configured, either per repository or globally, you must move these to the Gitaly node. If you have multiple Gitaly nodes, copy your custom hook(s) to all nodes.
+
### Disabling the Gitaly service in a cluster environment
If you are running Gitaly [as a remote
@@ -404,11 +411,11 @@ To configure Gitaly with TLS:
```
1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) on client node(s).
-1. Create the `/etc/gitlab/ssl` directory and copy your key and certificate there:
+1. On the Gitaly server, create the `/etc/gitlab/ssl` directory and copy your key and certificate there:
```sh
sudo mkdir -p /etc/gitlab/ssl
- sudo chmod 700 /etc/gitlab/ssl
+ sudo chmod 755 /etc/gitlab/ssl
sudo cp key.pem cert.pem /etc/gitlab/ssl/
```
@@ -550,8 +557,11 @@ a few things that you need to do:
to eliminate the need for a shared authorized_keys file.
1. Configure [object storage for job artifacts](../job_artifacts.md#using-object-storage)
including [incremental logging](../job_logs.md#new-incremental-logging-architecture).
-1. Configure [object storage for LFS objects](../../workflow/lfs/lfs_administration.md#storing-lfs-objects-in-remote-object-storage).
+1. Configure [object storage for LFS objects](../lfs/lfs_administration.md#storing-lfs-objects-in-remote-object-storage).
1. Configure [object storage for uploads](../uploads.md#using-object-storage-core-only).
+1. Configure [object storage for Merge Request Diffs](../merge_request_diffs.md#using-object-storage).
+1. Configure [object storage for Packages](../packages/index.md#using-object-storage) (Optional Feature).
+1. Configure [object storage for Dependency Proxy](../packages/dependency_proxy.md#using-object-storage) (Optional Feature).
NOTE: **Note:**
One current feature of GitLab that still requires a shared directory (NFS) is
diff --git a/doc/administration/gitaly/praefect.md b/doc/administration/gitaly/praefect.md
index 9038675a28f..83c9aa3f013 100644
--- a/doc/administration/gitaly/praefect.md
+++ b/doc/administration/gitaly/praefect.md
@@ -26,34 +26,42 @@ For this document, the following network topology is assumed:
graph TB
GitLab --> Gitaly;
GitLab --> Praefect;
- Praefect --> Preafect-Git-1;
- Praefect --> Preafect-Git-2;
- Praefect --> Preafect-Git-3;
+ Praefect --> Praefect-Gitaly-1;
+ Praefect --> Praefect-Gitaly-2;
+ Praefect --> Praefect-Gitaly-3;
```
Where `GitLab` is the collection of clients that can request Git operations.
-`Gitaly` is a Gitaly server before using Praefect. The Praefect node has two
+`Gitaly` is a Gitaly server before using Praefect. The Praefect node has three
storage nodes attached. Praefect itself doesn't store data, but connects to
-three Gitaly nodes, `Praefect-Git-1`, `Praefect-Git-2`, and `Praefect-Git-3`.
-There should be no knowledge other than with Praefect about the existence of
-the `Praefect-Git-X` nodes.
+three Gitaly nodes, `Praefect-Gitaly-1`, `Praefect-Gitaly-2`, and `Praefect-Gitaly-3`.
-### Setup
+Praefect may be enabled on its own node or can be run on the GitLab server.
+In the example below we will use a separate server, but the optimal configuration
+for Praefect is still being determined.
-In this setup guide, the Gitaly node will be added first, then Praefect, and
-lastly we update the GitLab configuration.
+Praefect will handle all Gitaly RPC requests to its child nodes. However, the child nodes
+will still need to communicate with the GitLab server via its internal API for authentication
+purposes.
-#### Gitaly
+### Setup
-In their own machine, configure the Gitaly server as described in the
-[gitaly documentation](index.md#3-gitaly-server-configuration).
+In this setup guide we will start by configuring Praefect, then its child
+Gitaly nodes, and lastly the GitLab server configuration.
#### Praefect
-Next, Praefect has to be enabled on its own node. Disable all other services,
-and add each Gitaly node that will be connected to Praefect. In the example below,
-the Gitaly nodes are named `praefect-git-X`. Note that one node is designated as
-primary, by setting the primary to `true`:
+On the Praefect node we disable all other services, including Gitaly. We list each
+Gitaly node that will be connected to Praefect under `praefect['storage_nodes']`.
+
+In the example below, the Gitaly nodes are named `praefect-gitaly-N`. Note that one
+node is designated as primary by setting the primary to `true`.
+
+`praefect['auth_token']` is the token used to authenticate with the GitLab server,
+just like `gitaly['auth_token']` is used for a standard Gitaly server.
+
+The `token` field under each storage listed in `praefect['storage_nodes']` is used
+to authenticate each child Gitaly node with Praefect.
```ruby
# /etc/gitlab/gitlab.rb
@@ -67,38 +75,111 @@ unicorn['enable'] = false
sidekiq['enable'] = false
gitlab_workhorse['enable'] = false
gitaly['enable'] = false
+```
+
+##### Set up Praefect and its Gitaly nodes
+
+In the example below, the Gitaly nodes are named `praefect-git-X`. Note that one node is designated as
+primary, by setting the primary to `true`:
+
+```ruby
+# /etc/gitlab/gitlab.rb
+
+# Prevent database connections during 'gitlab-ctl reconfigure'
+gitlab_rails['rake_cache_clear'] = false
+gitlab_rails['auto_migrate'] = false
+
+praefect['enable'] = true
+
+# Make Praefect accept connections on all network interfaces. You must use
+# firewalls to restrict access to this address/port.
+praefect['listen_addr'] = '0.0.0.0:2305'
# virtual_storage_name must match the same storage name given to praefect in git_data_dirs
praefect['virtual_storage_name'] = 'praefect'
-praefect['auth_token'] = 'super_secret_abc'
-praefect['enable'] = true
-praefect['storage_nodes'] = [
- {
- 'storage' => 'praefect-git-1',
- 'address' => 'tcp://praefect-git-1.internal',
- 'token' => 'token1',
+
+# Authentication token to ensure only authorized servers can communicate with
+# Praefect server
+praefect['auth_token'] = 'praefect-token'
+praefect['storage_nodes'] = {
+ 'praefect-gitaly-1' => {
+ 'address' => 'tcp://praefect-git-1.internal:8075',
+ 'token' => 'praefect-gitaly-token',
'primary' => true
},
- {
- 'storage' => 'praefect-git-2',
- 'address' => 'tcp://praefect-git-2.internal',
- 'token' => 'token2'
+ 'praefect-gitaly-2' => {
+ 'address' => 'tcp://praefect-git-2.internal:8075',
+ 'token' => 'praefect-gitaly-token'
},
- {
- 'storage' => 'praefect-git-3',
- 'address' => 'tcp://praefect-git-3.internal',
- 'token' => 'token3'
+ 'praefect-gitaly-3' => {
+ 'address' => 'tcp://praefect-git-3.internal:8075',
+ 'token' => 'praefect-gitaly-token'
}
-]
+}
```
Save the file and [reconfigure Praefect](../restart_gitlab.md#omnibus-gitlab-reconfigure).
+#### Gitaly
+
+Next we will configure each Gitaly server assigned to Praefect. Configuration for these
+is the same as a normal standalone Gitaly server, except that we use storage names and
+auth tokens from Praefect instead of GitLab.
+
+Below is an example configuration for `praefect-gitaly-1`, the only difference for the
+other Gitaly nodes is the storage name under `git_data_dirs`.
+
+Note that `gitaly['auth_token']` matches the `token` value listed under `praefect['storage_nodes']`
+on the Praefect node.
+
+```ruby
+# /etc/gitlab/gitlab.rb
+
+# Avoid running unnecessary services on the Gitaly server
+postgresql['enable'] = false
+redis['enable'] = false
+nginx['enable'] = false
+prometheus['enable'] = false
+unicorn['enable'] = false
+sidekiq['enable'] = false
+gitlab_workhorse['enable'] = false
+
+# Prevent database connections during 'gitlab-ctl reconfigure'
+gitlab_rails['rake_cache_clear'] = false
+gitlab_rails['auto_migrate'] = false
+
+# Configure the gitlab-shell API callback URL. Without this, `git push` will
+# fail. This can be your 'front door' GitLab URL or an internal load
+# balancer.
+# Don't forget to copy `/etc/gitlab/gitlab-secrets.json` from web server to Gitaly server.
+gitlab_rails['internal_api_url'] = 'https://gitlab.example.com'
+
+# Authentication token to ensure only authorized servers can communicate with
+# Gitaly server
+gitaly['auth_token'] = 'praefect-gitaly-token'
+
+# Make Gitaly accept connections on all network interfaces. You must use
+# firewalls to restrict access to this address/port.
+# Comment out following line if you only want to support TLS connections
+gitaly['listen_addr'] = "0.0.0.0:8075"
+
+git_data_dirs({
+ "praefect-gitaly-1" => {
+ "path" => "/var/opt/gitlab/git-data"
+ }
+})
+```
+
+Note that just as with a standard Gitaly server, `/etc/gitlab/gitlab-secrets.json` must
+be copied from the GitLab server to the Gitaly node for authentication purposes.
+
+For more information on Gitaly server configuration, see our [gitaly documentation](index.md#3-gitaly-server-configuration).
+
#### GitLab
When Praefect is running, it should be exposed as a storage to GitLab. This
is done through setting the `git_data_dirs`. Assuming the default storage
-configuration is used, there would be two storages available to GitLab:
+is present, there should be two storages available to GitLab:
```ruby
git_data_dirs({
@@ -109,6 +190,28 @@ git_data_dirs({
"gitaly_address" => "tcp://praefect.internal:2305"
}
})
+
+gitlab_rails['gitaly_token'] = 'praefect-token'
```
+Note that the storage name used is the same as the `praefect['virtual_storage_name']` set
+on the Praefect node.
+
+Also, the `gitlab_rails['gitaly_token']` matches the value of `praefect['auth_token']`
+on Praefect.
+
Restart GitLab using `gitlab-ctl restart` on the GitLab node.
+
+### Testing Praefect
+
+To test Praefect, first set it as the default storage node for new projects
+using **Admin Area > Settings > Repository > Repository storage**. Next,
+create a new project and check the "Initialize repository with a README" box.
+
+If you receive a 503 error, check `/var/log/gitlab/gitlab-rails/production.log`.
+A `GRPC::Unavailable (14:failed to connect to all addresses)` error indicates
+that GitLab was unable to connect to Praefect.
+
+If the project is created but the README is not, then ensure that the
+`/etc/gitlab/gitlab-secrets.json` file from the GitLab server has been copied
+to the Gitaly servers.
diff --git a/doc/administration/high_availability/README.md b/doc/administration/high_availability/README.md
index 199944a160c..7f0b4056acc 100644
--- a/doc/administration/high_availability/README.md
+++ b/doc/administration/high_availability/README.md
@@ -38,14 +38,17 @@ The following components need to be considered for a scaled or highly-available
environment. In many cases, components can be combined on the same nodes to reduce
complexity.
-- Unicorn/Workhorse - Web-requests (UI, API, Git over HTTP)
+- GitLab application nodes (Unicorn / Puma, Workhorse) - Web-requests (UI, API, Git over HTTP)
- Sidekiq - Asynchronous/Background jobs
- PostgreSQL - Database
- Consul - Database service discovery and health checks/failover
- PgBouncer - Database pool manager
- Redis - Key/Value store (User sessions, cache, queue for Sidekiq)
- Sentinel - Redis health check/failover manager
-- Gitaly - Provides high-level RPC access to Git repositories
+- Gitaly - Provides high-level storage and RPC access to Git repositories
+- S3 Object Storage service[^3] and / or NFS storage servers[^4] for entities such as Uploads, Artifacts, LFS Objects, etc...
+- Load Balancer[^2] - Main entry point and handles load balancing for the GitLab application nodes.
+- Monitor - Prometheus and Grafana monitoring with auto discovery.
## Scalable Architecture Examples
@@ -67,8 +70,10 @@ larger one.
- 1 PostgreSQL node
- 1 Redis node
-- 1 NFS/Gitaly storage server
-- 2 or more GitLab application nodes (Unicorn, Workhorse, Sidekiq)
+- 1 Gitaly node
+- 1 or more Object Storage services[^3] and / or NFS storage server[^4]
+- 2 or more GitLab application nodes (Unicorn / Puma, Workhorse, Sidekiq)
+- 1 or more Load Balancer nodes[^2]
- 1 Monitoring node (Prometheus, Grafana)
#### Installation Instructions
@@ -77,10 +82,12 @@ Complete the following installation steps in order. A link at the end of each
section will bring you back to the Scalable Architecture Examples section so
you can continue with the next step.
-1. [PostgreSQL](database.md#postgresql-in-a-scaled-environment)
+1. [PostgreSQL](database.md#postgresql-in-a-scaled-environment) with [PGBouncer](https://docs.gitlab.com/ee/administration/high_availability/pgbouncer.html)
1. [Redis](redis.md#redis-in-a-scaled-environment)
-1. [Gitaly](gitaly.md) (recommended) or [NFS](nfs.md)
+1. [Gitaly](gitaly.md) (recommended) and / or [NFS](nfs.md)[^4]
1. [GitLab application nodes](gitlab.md)
+ - With [Object Storage service enabled](../gitaly/index.md#eliminating-nfs-altogether)[^3]
+1. [Load Balancer(s)](load_balancer.md)[^2]
1. [Monitoring node (Prometheus and Grafana)](monitoring_node.md)
### Full Scaling
@@ -91,11 +98,13 @@ is split into separate Sidekiq and Unicorn/Workhorse nodes. One indication that
this architecture is required is if Sidekiq queues begin to periodically increase
in size, indicating that there is contention or there are not enough resources.
-- 1 PostgreSQL node
-- 1 Redis node
-- 2 or more NFS/Gitaly storage servers
+- 1 or more PostgreSQL nodes
+- 1 or more Redis nodes
+- 1 or more Gitaly storage servers
+- 1 or more Object Storage services[^3] and / or NFS storage server[^4]
- 2 or more Sidekiq nodes
-- 2 or more GitLab application nodes (Unicorn, Workhorse)
+- 2 or more GitLab application nodes (Unicorn / Puma, Workhorse, Sidekiq)
+- 1 or more Load Balancer nodes[^2]
- 1 Monitoring node (Prometheus, Grafana)
## High Availability Architecture Examples
@@ -114,10 +123,10 @@ This may lead to the other nodes believing a failure has occurred and initiating
automated failover. Isolating Redis and Consul from the services they monitor
reduces the chances of a false positive that a failure has occurred.
-The examples below do not really address high availability of NFS. Some enterprises
-have access to NFS appliances that manage availability. This is the best case
-scenario. In the future, GitLab may offer a more user-friendly solution to
-[GitLab HA Storage](https://gitlab.com/gitlab-org/omnibus-gitlab/issues/2472).
+The examples below do not address high availability of NFS for objects. We recommend a
+S3 Object Storage service[^3] is used where possible over NFS but it's still required in
+certain cases[^4]. Where NFS is to be used some enterprises have access to NFS appliances
+that manage availability and this would be best case scenario.
There are many options in between each of these examples. Work with GitLab Support
to understand the best starting point for your workload and adapt from there.
@@ -138,8 +147,10 @@ the contention.
- 3 PostgreSQL nodes
- 2 Redis nodes
- 3 Consul/Sentinel nodes
-- 2 or more GitLab application nodes (Unicorn, Workhorse, Sidekiq, PgBouncer)
-- 1 NFS/Gitaly server
+- 2 or more GitLab application nodes (Unicorn / Puma, Workhorse, Sidekiq)
+- 1 Gitaly storage servers
+- 1 Object Storage service[^3] and / or NFS storage server[^4]
+- 1 or more Load Balancer nodes[^2]
- 1 Monitoring node (Prometheus, Grafana)
![Horizontal architecture diagram](img/horizontal.png)
@@ -156,8 +167,10 @@ contention due to certain workloads.
- 2 Redis nodes
- 3 Consul/Sentinel nodes
- 2 or more Sidekiq nodes
-- 2 or more GitLab application nodes (Unicorn, Workhorse)
-- 1 or more NFS/Gitaly servers
+- 2 or more GitLab application nodes (Unicorn / Puma, Workhorse, Sidekiq)
+- 1 Gitaly storage servers
+- 1 Object Storage service[^3] and / or NFS storage server[^4]
+- 1 or more Load Balancer nodes[^2]
- 1 Monitoring node (Prometheus, Grafana)
![Hybrid architecture diagram](img/hybrid.png)
@@ -169,6 +182,7 @@ the basis of the GitLab.com architecture. While this scales well it also comes
with the added complexity of many more nodes to configure, manage, and monitor.
- 3 PostgreSQL nodes
+- 1 or more PgBouncer nodes (with associated internal load balancers)
- 4 or more Redis nodes (2 separate clusters for persistent and cache data)
- 3 Consul nodes
- 3 Sentinel nodes
@@ -177,120 +191,116 @@ with the added complexity of many more nodes to configure, manage, and monitor.
- 2 or more Git nodes (Git over SSH/Git over HTTP)
- 2 or more API nodes (All requests to `/api`)
- 2 or more Web nodes (All other web requests)
-- 2 or more NFS/Gitaly servers
+- 2 or more Gitaly storage servers
+- 1 or more Object Storage services[^3] and / or NFS storage servers[^4]
+- 1 or more Load Balancer nodes[^2]
- 1 Monitoring node (Prometheus, Grafana)
![Fully Distributed architecture diagram](img/fully-distributed.png)
-The following pages outline the steps necessary to configure each component
-separately:
+## Reference Architecture Examples
-1. [Configure the database](database.md)
-1. [Configure Redis](redis.md)
- 1. [Configure Redis for GitLab source installations](redis_source.md)
-1. [Configure NFS](nfs.md)
- 1. [NFS Client and Host setup](nfs_host_client_setup.md)
-1. [Configure the GitLab application servers](gitlab.md)
-1. [Configure the load balancers](load_balancer.md)
-1. [Monitoring node (Prometheus and Grafana)](monitoring_node.md)
+The Support and Quality teams build, performance test, and validate Reference
+Architectures that support set large numbers of users. The specifications below are a
+representation of this work so far and may be adjusted in the future based on
+additional testing and iteration.
-## Reference Architecture Examples
+The architectures have been tested with specific coded workloads. The throughputs
+used for testing are calculated based on sample customer data. We test each endpoint
+type with the following number of requests per second (RPS) per 1000 users:
-These reference architecture examples rely on the general rule that approximately 2 requests per second (RPS) of load is generated for every 100 users.
+- API: 20 RPS
+- Web: 2 RPS
+- Git: 2 RPS
-The specifications here were performance tested against a specific coded
-workload. Your exact needs may be more, depending on your workload. Your
+Note that your exact needs may be more, depending on your workload. Your
workload is influenced by factors such as - but not limited to - how active your
users are, how much automation you use, mirroring, and repo/change size.
### 10,000 User Configuration
- **Supported Users (approximate):** 10,000
-- **RPS:** 200 requests per second
+- **Test RPS Rates:** API: 200 RPS, Web: 20 RPS, Git: 20 RPS
- **Known Issues:** While validating the reference architecture, slow API endpoints
were discovered. For details, see the related issues list in
[this issue](https://gitlab.com/gitlab-org/gitlab-foss/issues/64335).
-The Support and Quality teams built, performance tested, and validated an
-environment that supports about 10,000 users. The specifications below are a
-representation of the work so far. The specifications may be adjusted in the
-future based on additional testing and iteration.
-
-| Service | Configuration | GCP type |
-| ------------------------------|-------------------------|----------------|
-| 3 GitLab Rails <br> - Puma workers on each node set to 90% of available CPUs with 16 threads | 32 vCPU, 28.8GB Memory | n1-highcpu-32 |
-| 3 PostgreSQL | 4 vCPU, 15GB Memory | n1-standard-4 |
-| 1 PgBouncer | 2 vCPU, 1.8GB Memory | n1-highcpu-2 |
-| X Gitaly[^1] <br> - Gitaly Ruby workers on each node set to 90% of available CPUs with 16 threads | 16 vCPU, 60GB Memory | n1-standard-16 |
-| 3 Redis Cache + Sentinel <br> - Cache maxmemory set to 90% of available memory | 4 vCPU, 15GB Memory | n1-standard-4 |
-| 3 Redis Persistent + Sentinel | 4 vCPU, 15GB Memory | n1-standard-4 |
-| 4 Sidekiq | 4 vCPU, 15GB Memory | n1-standard-4 |
-| 3 Consul | 2 vCPU, 1.8GB Memory | n1-highcpu-2 |
-| 1 NFS Server | 16 vCPU, 14.4GB Memory | n1-highcpu-16 |
-| 1 Monitoring node | 4 CPU, 3.6GB Memory | n1-highcpu-4 |
-| 1 Load Balancing node[^2] . | 2 vCPU, 1.8GB Memory | n1-highcpu-2 |
+| Service | Nodes | Configuration | GCP type |
+| ----------------------------|-------|-----------------------|---------------|
+| GitLab Rails <br> - Puma workers on each node set to 90% of available CPUs with 16 threads | 3 | 32 vCPU, 28.8GB Memory | n1-highcpu-32 |
+| PostgreSQL | 3 | 4 vCPU, 15GB Memory | n1-standard-4 |
+| PgBouncer | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 |
+| Gitaly <br> - Gitaly Ruby workers on each node set to 20% of available CPUs | X[^1] . | 16 vCPU, 60GB Memory | n1-standard-16 |
+| Redis Cache + Sentinel <br> - Cache maxmemory set to 90% of available memory | 3 | 4 vCPU, 15GB Memory | n1-standard-4 |
+| Redis Persistent + Sentinel | 3 | 4 vCPU, 15GB Memory | n1-standard-4 |
+| Sidekiq | 4 | 4 vCPU, 15GB Memory | n1-standard-4 |
+| Consul | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 |
+| NFS Server[^4] . | 1 | 4 vCPU, 3.6GB Memory | n1-highcpu-4 |
+| S3 Object Storage[^3] . | - | - | - |
+| Monitoring node | 1 | 4 vCPU, 3.6GB Memory | n1-highcpu-4 |
+| External load balancing node[^2] . | 1 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 |
+| Internal load balancing node[^2] . | 1 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 |
+
+NOTE: **Note:** Memory values are given directly by GCP machine sizes. On different cloud
+vendors a best effort like for like can be used.
### 25,000 User Configuration
- **Supported Users (approximate):** 25,000
-- **RPS:** 500 requests per second
+- **Test RPS Rates:** API: 500 RPS, Web: 50 RPS, Git: 50 RPS
- **Known Issues:** The slow API endpoints that were discovered during testing
the 10,000 user architecture also affect the 25,000 user architecture. For
details, see the related issues list in
[this issue](https://gitlab.com/gitlab-org/gitlab-foss/issues/64335).
-The GitLab Support and Quality teams built, performance tested, and validated an
-environment that supports around 25,000 users. The specifications below are a
-representation of the work so far. The specifications may be adjusted in the
-future based on additional testing and iteration.
-
-NOTE: **Note:** The specifications here were performance tested against a
-specific coded workload. Your exact needs may be more, depending on your
-workload. Your workload is influenced by factors such as - but not limited to -
-how active your users are, how much automation you use, mirroring, and
-repo/change size.
-
-| Service | Configuration | GCP type |
-| ------------------------------|-------------------------|----------------|
-| 7 GitLab Rails <br> - Puma workers on each node set to 90% of available CPUs with 16 threads | 32 vCPU, 28.8GB Memory | n1-highcpu-32 |
-| 3 PostgreSQL | 8 vCPU, 30GB Memory | n1-standard-8 |
-| 1 PgBouncer | 2 vCPU, 1.8GB Memory | n1-highcpu-2 |
-| X Gitaly[^1] <br> - Gitaly Ruby workers on each node set to 90% of available CPUs with 16 threads | 32 vCPU, 120GB Memory | n1-standard-32 |
-| 3 Redis Cache + Sentinel <br> - Cache maxmemory set to 90% of available memory | 4 vCPU, 15GB Memory | n1-standard-4 |
-| 3 Redis Persistent + Sentinel | 4 vCPU, 15GB Memory | n1-standard-4 |
-| 4 Sidekiq | 4 vCPU, 15GB Memory | n1-standard-4 |
-| 3 Consul | 2 vCPU, 1.8GB Memory | n1-highcpu-2 |
-| 1 NFS Server | 16 vCPU, 14.4GB Memory | n1-highcpu-16 |
-| 1 Monitoring node | 4 CPU, 3.6GB Memory | n1-highcpu-4 |
-| 1 Load Balancing node[^2] . | 2 vCPU, 1.8GB Memory | n1-highcpu-2 |
+| Service | Nodes | Configuration | GCP type |
+| ----------------------------|-------|-----------------------|---------------|
+| GitLab Rails <br> - Puma workers on each node set to 90% of available CPUs with 16 threads | 7 | 32 vCPU, 28.8GB Memory | n1-highcpu-32 |
+| PostgreSQL | 3 | 8 vCPU, 30GB Memory | n1-standard-8 |
+| PgBouncer | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 |
+| Gitaly <br> - Gitaly Ruby workers on each node set to 20% of available CPUs | X[^1] . | 32 vCPU, 120GB Memory | n1-standard-32 |
+| Redis Cache + Sentinel <br> - Cache maxmemory set to 90% of available memory | 3 | 4 vCPU, 15GB Memory | n1-standard-4 |
+| Redis Persistent + Sentinel | 3 | 4 vCPU, 15GB Memory | n1-standard-4 |
+| Sidekiq | 4 | 4 vCPU, 15GB Memory | n1-standard-4 |
+| Consul | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 |
+| NFS Server[^4] . | 1 | 4 vCPU, 3.6GB Memory | n1-highcpu-4 |
+| S3 Object Storage[^3] . | - | - | - |
+| Monitoring node | 1 | 4 vCPU, 3.6GB Memory | n1-highcpu-4 |
+| External load balancing node[^2] . | 1 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 |
+| Internal load balancing node[^2] . | 1 | 4 vCPU, 3.6GB Memory | n1-highcpu-4 |
+
+NOTE: **Note:** Memory values are given directly by GCP machine sizes. On different cloud
+vendors a best effort like for like can be used.
### 50,000 User Configuration
- **Supported Users (approximate):** 50,000
-- **RPS:** 1,000 requests per second
+- **Test RPS Rates:** API: 1000 RPS, Web: 100 RPS, Git: 100 RPS
- **Status:** Work-in-progress
- **Related Issue:** See the [related issue](https://gitlab.com/gitlab-org/quality/performance/issues/66) for more information.
-The Support and Quality teams are in the process of building and performance
-testing an environment that will support around 50,000 users. The specifications
-below are a very rough work-in-progress representation of the work so far. The
-Quality team will be certifying this environment in late 2019. The
-specifications may be adjusted prior to certification based on performance
-testing.
-
-| Service | Configuration | GCP type |
-| ------------------------------|-------------------------|----------------|
-| 15 GitLab Rails <br> - Puma workers on each node set to 90% of available CPUs with 16 threads | 32 vCPU, 28.8GB Memory | n1-highcpu-32 |
-| 3 PostgreSQL | 8 vCPU, 30GB Memory | n1-standard-8 |
-| 1 PgBouncer | 2 vCPU, 1.8GB Memory | n1-highcpu-2 |
-| X Gitaly[^1] <br> - Gitaly Ruby workers on each node set to 90% of available CPUs with 16 threads | 64 vCPU, 240GB Memory | n1-standard-64 |
-| 3 Redis Cache + Sentinel <br> - Cache maxmemory set to 90% of available memory | 4 vCPU, 15GB Memory | n1-standard-4 |
-| 3 Redis Persistent + Sentinel | 4 vCPU, 15GB Memory | n1-standard-4 |
-| 4 Sidekiq | 4 vCPU, 15GB Memory | n1-standard-4 |
-| 3 Consul | 2 vCPU, 1.8GB Memory | n1-highcpu-2 |
-| 1 NFS Server | 16 vCPU, 14.4GB Memory | n1-highcpu-16 |
-| 1 Monitoring node | 4 CPU, 3.6GB Memory | n1-highcpu-4 |
-| 1 Load Balancing node[^2] . | 2 vCPU, 1.8GB Memory | n1-highcpu-2 |
+NOTE: **Note:** This architecture is a work-in-progress of the work so far. The
+Quality team will be certifying this environment in late 2019. The specifications
+may be adjusted prior to certification based on performance testing.
+
+| Service | Nodes | Configuration | GCP type |
+| ----------------------------|-------|-----------------------|---------------|
+| GitLab Rails <br> - Puma workers on each node set to 90% of available CPUs with 16 threads | 15 | 32 vCPU, 28.8GB Memory | n1-highcpu-32 |
+| PostgreSQL | 3 | 8 vCPU, 30GB Memory | n1-standard-8 |
+| PgBouncer | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 |
+| Gitaly <br> - Gitaly Ruby workers on each node set to 20% of available CPUs | X[^1] . | 64 vCPU, 240GB Memory | n1-standard-64 |
+| Redis Cache + Sentinel <br> - Cache maxmemory set to 90% of available memory | 3 | 4 vCPU, 15GB Memory | n1-standard-4 |
+| Redis Persistent + Sentinel | 3 | 4 vCPU, 15GB Memory | n1-standard-4 |
+| Sidekiq | 4 | 4 vCPU, 15GB Memory | n1-standard-4 |
+| Consul | 3 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 |
+| NFS Server[^4] . | 1 | 4 vCPU, 3.6GB Memory | n1-highcpu-4 |
+| S3 Object Storage[^3] . | - | - | - |
+| Monitoring node | 1 | 4 vCPU, 3.6GB Memory | n1-highcpu-4 |
+| External load balancing node[^2] . | 1 | 2 vCPU, 1.8GB Memory | n1-highcpu-2 |
+| Internal load balancing node[^2] . | 1 | 8 vCPU, 7.2GB Memory | n1-highcpu-8 |
+
+NOTE: **Note:** Memory values are given directly by GCP machine sizes. On different cloud
+vendors a best effort like for like can be used.
[^1]: Gitaly node requirements are dependent on customer data. We recommend 2
nodes as an absolute minimum for performance at the 10,000 and 25,000 user
@@ -298,5 +308,19 @@ testing.
additional nodes should be considered in conjunction with a review of
project counts and sizes.
-[^2]: HAProxy is the only tested and recommended load balancer. Additional
- options may be supported in the future.
+[^2]: Our architectures have been tested and validated with [HAProxy](https://www.haproxy.org/)
+ as the load balancer. However other reputable load balancers with similar feature sets
+ should also work here but be aware these aren't validated.
+
+[^3]: For data objects such as LFS, Uploads, Artifacts, etc... We recommend a S3 Object Storage
+ where possible over NFS due to better performance and availability. Several types of objects
+ are supported for S3 storage - [Job artifacts](../job_artifacts.md#using-object-storage),
+ [LFS](../lfs/lfs_administration.md#storing-lfs-objects-in-remote-object-storage),
+ [Uploads](../uploads.md#using-object-storage-core-only),
+ [Merge Request Diffs](../merge_request_diffs.md#using-object-storage),
+ [Packages](../packages/index.md#using-object-storage) (Optional Feature),
+ [Dependency Proxy](../packages/dependency_proxy.md#using-object-storage) (Optional Feature).
+
+[^4]: NFS storage server is still required for [GitLab Pages](https://gitlab.com/gitlab-org/gitlab-pages/issues/196)
+ and optionally for CI Job Incremental Logging
+ ([can be switched to use Redis instead](https://docs.gitlab.com/ee/administration/job_logs.html#new-incremental-logging-architecture)).
diff --git a/doc/administration/high_availability/consul.md b/doc/administration/high_availability/consul.md
index b01419200cc..392b9b76c31 100644
--- a/doc/administration/high_availability/consul.md
+++ b/doc/administration/high_availability/consul.md
@@ -102,6 +102,23 @@ To be safe, we recommend you only restart one server agent at a time to ensure t
For larger clusters, it is possible to restart multiple agents at a time. See the [Consul consensus document](https://www.consul.io/docs/internals/consensus.html#deployment-table) for how many failures it can tolerate. This will be the number of simulateneous restarts it can sustain.
+## Upgrades for bundled Consul
+
+Nodes running GitLab-bundled Consul should be:
+
+- Members of a healthy cluster prior to upgrading the GitLab Omnibus package.
+- Upgraded one node at a time.
+
+NOTE: **NOTE:**
+Running `curl http://127.0.0.1:8500/v1/health/state/critical` from any Consul node will identify existing health issues in the cluster. The command will return an empty array if the cluster is healthy.
+
+Consul clusters communicate using the raft protocol. If the current leader goes offline, there needs to be a leader election. A leader node must exist to facilitate synchronization across the cluster. If too many nodes go offline at the same time, the cluster will lose quorum and not elect a leader due to [broken consensus](https://www.consul.io/docs/internals/consensus.html).
+
+Consult the [troubleshooting section](#troubleshooting) if the cluster is not able to recover after the upgrade. The [outage recovery](#outage-recovery) may be of particular interest.
+
+NOTE: **NOTE:**
+GitLab only uses Consul to store transient data that is easily regenerated. If the bundled Consul was not used by any process other than GitLab itself, then [rebuilding the cluster from scratch](#recreate-from-scratch) is fine.
+
## Troubleshooting
### Consul server agents unable to communicate
diff --git a/doc/administration/high_availability/database.md b/doc/administration/high_availability/database.md
index a50cc0cbd03..02684f575d4 100644
--- a/doc/administration/high_availability/database.md
+++ b/doc/administration/high_availability/database.md
@@ -135,7 +135,8 @@ The recommended configuration for a PostgreSQL HA requires:
- `repmgrd` - A service to monitor, and handle failover in case of a failure
- `Consul` agent - Used for service discovery, to alert other nodes when failover occurs
- A minimum of three `Consul` server nodes
-- A minimum of one `pgbouncer` service node
+- A minimum of one `pgbouncer` service node, but it's recommended to have one per database node
+ - An internal load balancer (TCP) is required when there is more than one `pgbouncer` service node
You also need to take into consideration the underlying network topology,
making sure you have redundant connectivity between all Database and GitLab instances,
@@ -155,13 +156,13 @@ Database nodes run two services with PostgreSQL:
On failure, the old master node is automatically evicted from the cluster, and should be rejoined manually once recovered.
- Consul. Monitors the status of each node in the database cluster and tracks its health in a service definition on the Consul cluster.
-Alongside PgBouncer, there is a Consul agent that watches the status of the PostgreSQL service. If that status changes, Consul runs a script which updates the configuration and reloads PgBouncer
+Alongside each PgBouncer, there is a Consul agent that watches the status of the PostgreSQL service. If that status changes, Consul runs a script which updates the configuration and reloads PgBouncer
##### Connection flow
Each service in the package comes with a set of [default ports](https://docs.gitlab.com/omnibus/package-information/defaults.html#ports). You may need to make specific firewall rules for the connections listed below:
-- Application servers connect to [PgBouncer default port](https://docs.gitlab.com/omnibus/package-information/defaults.html#pgbouncer)
+- Application servers connect to either PgBouncer directly via its [default port](https://docs.gitlab.com/omnibus/package-information/defaults.html#pgbouncer) or via a configured Internal Load Balancer (TCP) that serves multiple PgBouncers.
- PgBouncer connects to the primary database servers [PostgreSQL default port](https://docs.gitlab.com/omnibus/package-information/defaults.html#postgresql)
- Repmgr connects to the database servers [PostgreSQL default port](https://docs.gitlab.com/omnibus/package-information/defaults.html#postgresql)
- Postgres secondaries connect to the primary database servers [PostgreSQL default port](https://docs.gitlab.com/omnibus/package-information/defaults.html#postgresql)
@@ -499,7 +500,7 @@ attributes set, but the following need to be set.
# Disable PostgreSQL on the application node
postgresql['enable'] = false
- gitlab_rails['db_host'] = 'PGBOUNCER_NODE'
+ gitlab_rails['db_host'] = 'PGBOUNCER_NODE' or 'INTERNAL_LOAD_BALANCER'
gitlab_rails['db_port'] = 6432
gitlab_rails['db_password'] = 'POSTGRESQL_USER_PASSWORD'
gitlab_rails['auto_migrate'] = false
@@ -533,7 +534,8 @@ Here we'll show you some fully expanded example configurations.
##### Example recommended setup
-This example uses 3 Consul servers, 3 PostgreSQL servers, and 1 application node.
+This example uses 3 Consul servers, 3 PgBouncer servers (with associated internal load balancer),
+3 PostgreSQL servers, and 1 application node.
We start with all servers on the same 10.6.0.0/16 private network range, they
can connect to each freely other on those addresses.
@@ -543,14 +545,16 @@ Here is a list and description of each machine and the assigned IP:
- `10.6.0.11`: Consul 1
- `10.6.0.12`: Consul 2
- `10.6.0.13`: Consul 3
-- `10.6.0.21`: PostgreSQL master
-- `10.6.0.22`: PostgreSQL secondary
-- `10.6.0.23`: PostgreSQL secondary
-- `10.6.0.31`: GitLab application
-
-All passwords are set to `toomanysecrets`, please do not use this password or derived hashes.
+- `10.6.0.20`: Internal Load Balancer
+- `10.6.0.21`: PgBouncer 1
+- `10.6.0.22`: PgBouncer 2
+- `10.6.0.23`: PgBouncer 3
+- `10.6.0.31`: PostgreSQL master
+- `10.6.0.32`: PostgreSQL secondary
+- `10.6.0.33`: PostgreSQL secondary
+- `10.6.0.41`: GitLab application
-The external_url for GitLab is `http://gitlab.example.com`
+All passwords are set to `toomanysecrets`, please do not use this password or derived hashes and the external_url for GitLab is `http://gitlab.example.com`.
Please note that after the initial configuration, if a failover occurs, the PostgresSQL master will change to one of the available secondaries until it is failed back.
@@ -566,10 +570,45 @@ consul['configuration'] = {
server: true,
retry_join: %w(10.6.0.11 10.6.0.12 10.6.0.13)
}
+consul['monitoring_service_discovery'] = true
+```
+
+[Reconfigure Omnibus GitLab][reconfigure GitLab] for the changes to take effect.
+
+##### Example recommended setup for PgBouncer servers
+
+On each server edit `/etc/gitlab/gitlab.rb`:
+
+```ruby
+# Disable all components except Pgbouncer and Consul agent
+roles ['pgbouncer_role']
+
+# Configure PgBouncer
+pgbouncer['admin_users'] = %w(pgbouncer gitlab-consul)
+
+pgbouncer['users'] = {
+ 'gitlab-consul': {
+ password: '5e0e3263571e3704ad655076301d6ebe'
+ },
+ 'pgbouncer': {
+ password: '771a8625958a529132abe6f1a4acb19c'
+ }
+}
+
+consul['watchers'] = %w(postgresql)
+consul['enable'] = true
+consul['configuration'] = {
+ retry_join: %w(10.6.0.11 10.6.0.12 10.6.0.13)
+}
+consul['monitoring_service_discovery'] = true
```
[Reconfigure Omnibus GitLab][reconfigure GitLab] for the changes to take effect.
+##### Internal load balancer setup
+
+An internal load balancer (TCP) is then required to be setup to serve each PgBouncer node (in this example on the IP of `10.6.0.20`). An example of how to do this can be found in the [PgBouncer Configure Internal Load Balancer](pgbouncer.md#configure-the-internal-load-balancer) section.
+
##### Example recommended setup for PostgreSQL servers
###### Primary node
@@ -589,9 +628,6 @@ postgresql['shared_preload_libraries'] = 'repmgr_funcs'
# Disable automatic database migrations
gitlab_rails['auto_migrate'] = false
-# Configure the Consul agent
-consul['services'] = %w(postgresql)
-
postgresql['pgbouncer_user_password'] = '771a8625958a529132abe6f1a4acb19c'
postgresql['sql_user_password'] = '450409b85a0223a214b5fb1484f34d0f'
postgresql['max_wal_senders'] = 4
@@ -599,9 +635,13 @@ postgresql['max_wal_senders'] = 4
postgresql['trust_auth_cidr_addresses'] = %w(10.6.0.0/16)
repmgr['trust_auth_cidr_addresses'] = %w(10.6.0.0/16)
+# Configure the Consul agent
+consul['services'] = %w(postgresql)
+consul['enable'] = true
consul['configuration'] = {
retry_join: %w(10.6.0.11 10.6.0.12 10.6.0.13)
}
+consul['monitoring_service_discovery'] = true
```
[Reconfigure Omnibus GitLab][reconfigure GitLab] for the changes to take effect.
@@ -626,18 +666,15 @@ On the server edit `/etc/gitlab/gitlab.rb`:
```ruby
external_url 'http://gitlab.example.com'
-gitlab_rails['db_host'] = '127.0.0.1'
+gitlab_rails['db_host'] = '10.6.0.20' # Internal Load Balancer for PgBouncer nodes
gitlab_rails['db_port'] = 6432
gitlab_rails['db_password'] = 'toomanysecrets'
gitlab_rails['auto_migrate'] = false
postgresql['enable'] = false
-pgbouncer['enable'] = true
+pgbouncer['enable'] = false
consul['enable'] = true
-# Configure PgBouncer
-pgbouncer['admin_users'] = %w(pgbouncer gitlab-consul)
-
# Configure Consul agent
consul['watchers'] = %w(postgresql)
@@ -661,7 +698,7 @@ consul['configuration'] = {
After deploying the configuration follow these steps:
-1. On `10.6.0.21`, our primary database
+1. On `10.6.0.31`, our primary database
Enable the `pg_trgm` extension
@@ -673,7 +710,7 @@ After deploying the configuration follow these steps:
CREATE EXTENSION pg_trgm;
```
-1. On `10.6.0.22`, our first standby database
+1. On `10.6.0.32`, our first standby database
Make this node a standby of the primary
@@ -681,7 +718,7 @@ After deploying the configuration follow these steps:
gitlab-ctl repmgr standby setup 10.6.0.21
```
-1. On `10.6.0.23`, our second standby database
+1. On `10.6.0.33`, our second standby database
Make this node a standby of the primary
@@ -689,7 +726,7 @@ After deploying the configuration follow these steps:
gitlab-ctl repmgr standby setup 10.6.0.21
```
-1. On `10.6.0.31`, our application server
+1. On `10.6.0.41`, our application server
Set `gitlab-consul` user's PgBouncer password to `toomanysecrets`
@@ -705,7 +742,7 @@ After deploying the configuration follow these steps:
#### Example minimal setup
-This example uses 3 PostgreSQL servers, and 1 application node.
+This example uses 3 PostgreSQL servers, and 1 application node (with PgBouncer setup alongside).
It differs from the [recommended setup](#example-recommended-setup) by moving the Consul servers into the same servers we use for PostgreSQL.
The trade-off is between reducing server counts, against the increased operational complexity of needing to deal with PostgreSQL [failover](#failover-procedure) and [restore](#restore-procedure) procedures in addition to [Consul outage recovery](consul.md#outage-recovery) on the same set of machines.
diff --git a/doc/administration/high_availability/pgbouncer.md b/doc/administration/high_availability/pgbouncer.md
index e7479ad1ecb..09b33c3554a 100644
--- a/doc/administration/high_availability/pgbouncer.md
+++ b/doc/administration/high_availability/pgbouncer.md
@@ -4,13 +4,9 @@ type: reference
# Working with the bundle PgBouncer service
-As part of its High Availability stack, GitLab Premium includes a bundled version of [PgBouncer](https://pgbouncer.github.io/) that can be managed through `/etc/gitlab/gitlab.rb`.
+As part of its High Availability stack, GitLab Premium includes a bundled version of [PgBouncer](https://pgbouncer.github.io/) that can be managed through `/etc/gitlab/gitlab.rb`. PgBouncer is used to seamlessly migrate database connections between servers in a failover scenario. Additionally, it can be used in a non-HA setup to pool connections, speeding up response time while reducing resource usage.
-In a High Availability setup, PgBouncer is used to seamlessly migrate database connections between servers in a failover scenario.
-
-Additionally, it can be used in a non-HA setup to pool connections, speeding up response time while reducing resource usage.
-
-It is recommended to run PgBouncer alongside the `gitlab-rails` service, or on its own dedicated node in a cluster.
+In a HA setup, it's recommended to run a PgBouncer node separately for each database node with an internal load balancer (TCP) serving each accordingly.
## Operations
@@ -18,7 +14,7 @@ It is recommended to run PgBouncer alongside the `gitlab-rails` service, or on i
1. Make sure you collect [`CONSUL_SERVER_NODES`](database.md#consul-information), [`CONSUL_PASSWORD_HASH`](database.md#consul-information), and [`PGBOUNCER_PASSWORD_HASH`](database.md#pgbouncer-information) before executing the next step.
-1. Edit `/etc/gitlab/gitlab.rb` replacing values noted in the `# START user configuration` section:
+1. One each node, edit the `/etc/gitlab/gitlab.rb` config file and replace values noted in the `# START user configuration` section as below:
```ruby
# Disable all components except PgBouncer and Consul agent
@@ -67,7 +63,7 @@ It is recommended to run PgBouncer alongside the `gitlab-rails` service, or on i
#### PgBouncer Checkpoint
-1. Ensure the node is talking to the current master:
+1. Ensure each node is talking to the current master:
```sh
gitlab-ctl pgb-console # You will be prompted for PGBOUNCER_PASSWORD
@@ -100,6 +96,41 @@ It is recommended to run PgBouncer alongside the `gitlab-rails` service, or on i
(2 rows)
```
+#### Configure the internal load balancer
+
+If you're running more than one PgBouncer node as recommended, then at this time you'll need to set up a TCP internal load balancer to serve each correctly. This can be done with any reputable TCP load balancer.
+
+As an example here's how you could do it with [HAProxy](https://www.haproxy.org/):
+
+```
+global
+ log /dev/log local0
+ log localhost local1 notice
+ log stdout format raw local0
+
+defaults
+ log global
+ default-server inter 10s fall 3 rise 2
+ balance leastconn
+
+frontend internal-pgbouncer-tcp-in
+ bind *:6432
+ mode tcp
+ option tcplog
+
+ default_backend pgbouncer
+
+backend pgbouncer
+ mode tcp
+ option tcp-check
+
+ server pgbouncer1 <ip>:6432 check
+ server pgbouncer2 <ip>:6432 check
+ server pgbouncer3 <ip>:6432 check
+```
+
+Refer to your preferred Load Balancer's documentation for further guidance.
+
### Running PgBouncer as part of a non-HA GitLab installation
1. Generate PGBOUNCER_USER_PASSWORD_HASH with the command `gitlab-ctl pg-password-md5 pgbouncer`
@@ -177,7 +208,7 @@ If you enable Monitoring, it must be enabled on **all** PgBouncer servers.
#### Administrative console
-As part of Omnibus GitLab, we provide a command `gitlab-ctl pgb-console` to automatically connect to the PgBouncer administrative console. Please see the [PgBouncer documentation](https://pgbouncer.github.io/usage.html#admin-console) for detailed instructions on how to interact with the console.
+As part of Omnibus GitLab, we provide a command `gitlab-ctl pgb-console` to automatically connect to the PgBouncer administrative console. Please see the [PgBouncer documentation](https://www.pgbouncer.org/usage.html#admin-console) for detailed instructions on how to interact with the console.
To start a session, run
diff --git a/doc/administration/high_availability/redis.md b/doc/administration/high_availability/redis.md
index ba4599e5bcd..72968cfed56 100644
--- a/doc/administration/high_availability/redis.md
+++ b/doc/administration/high_availability/redis.md
@@ -491,7 +491,7 @@ multiple machines with the Sentinel daemon.
1. **You can omit this step if the Sentinels will be hosted in the same node as
the other Redis instances.**
- [Download/install](https://about.gitlab.com/downloads-ee) the
+ [Download/install](https://about.gitlab.com/install/) the
Omnibus GitLab Enterprise Edition package using **steps 1 and 2** from the
GitLab downloads page.
- Make sure you select the correct Omnibus package, with the same version
diff --git a/doc/administration/incoming_email.md b/doc/administration/incoming_email.md
index 88cf702cf0e..a0360f1d252 100644
--- a/doc/administration/incoming_email.md
+++ b/doc/administration/incoming_email.md
@@ -7,7 +7,7 @@ GitLab has several features based on receiving incoming emails:
- [New issue by email](../user/project/issues/managing_issues.md#new-issue-via-email):
allow GitLab users to create a new issue by sending an email to a
user-specific email address.
-- [New merge request by email](../user/project/merge_requests/index.md#create-new-merge-requests-by-email):
+- [New merge request by email](../user/project/merge_requests/creating_merge_requests.md#create-new-merge-requests-by-email):
allow GitLab users to create a new merge request by sending an email to a
user-specific email address.
- [Service Desk](../user/project/service_desk.md): provide e-mail support to
@@ -79,7 +79,7 @@ email address in order to sign up.
If you also host a public-facing GitLab instance at `hooli.com` and set your
incoming email domain to `hooli.com`, an attacker could abuse the "Create new
issue by email" or
-"[Create new merge request by email](../user/project/merge_requests/index.md#create-new-merge-requests-by-email)"
+"[Create new merge request by email](../user/project/merge_requests/creating_merge_requests.md#create-new-merge-requests-by-email)"
features by using a project's unique address as the email when signing up for
Slack, which would send a confirmation email, which would create a new issue or
merge request on the project owned by the attacker, allowing them to click the
diff --git a/doc/administration/index.md b/doc/administration/index.md
index f90b9b2c7d5..bf21347fb99 100644
--- a/doc/administration/index.md
+++ b/doc/administration/index.md
@@ -43,7 +43,7 @@ Learn how to install, configure, update, and maintain your GitLab instance.
### Configuring GitLab
-- [Adjust your instance's timezone](../workflow/timezone.md): Customize the default time zone of GitLab.
+- [Adjust your instance's timezone](timezone.md): Customize the default time zone of GitLab.
- [System hooks](../system_hooks/system_hooks.md): Notifications when users, projects and keys are changed.
- [Security](../security/README.md): Learn what you can do to further secure your GitLab instance.
- [Usage statistics, version check, and usage ping](../user/admin_area/settings/usage_statistics.md): Enable or disable information about your instance to be sent to GitLab, Inc.
@@ -51,7 +51,7 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- [Polling](polling.md): Configure how often the GitLab UI polls for updates.
- [GitLab Pages configuration](pages/index.md): Enable and configure GitLab Pages.
- [GitLab Pages configuration for GitLab source installations](pages/source.md): Enable and configure GitLab Pages on [source installations](../install/installation.md#installation-from-source).
-- [Uploads configuration](uploads.md): Configure GitLab uploads storage.
+- [Uploads administration](uploads.md): Configure GitLab uploads storage.
- [Environment variables](environment_variables.md): Supported environment variables that can be used to override their defaults values in order to configure GitLab.
- [Plugins](plugins.md): With custom plugins, GitLab administrators can introduce custom integrations without modifying GitLab's source code.
- [Enforcing Terms of Service](../user/admin_area/settings/terms.md)
@@ -68,11 +68,10 @@ Learn how to install, configure, update, and maintain your GitLab instance.
#### Customizing GitLab's appearance
-- [Header logo](../customization/branded_page_and_email_header.md): Change the logo on all pages and email headers.
-- [Favicon](../customization/favicon.md): Change the default favicon to your own logo.
-- [Branded login page](../customization/branded_login_page.md): Customize the login page with your own logo, title, and description.
-- [Welcome message](../customization/welcome_message.md): Add a custom welcome message to the sign-in page.
-- ["New Project" page](../customization/new_project_page.md): Customize the text to be displayed on the page that opens whenever your users create a new project.
+- [Header logo](../user/admin_area/appearance.md#navigation-bar): Change the logo on all pages and email headers.
+- [Favicon](../user/admin_area/appearance.md#favicon): Change the default favicon to your own logo.
+- [Branded login page](../user/admin_area/appearance.md#sign-in--sign-up-pages): Customize the login page with your own logo, title, and description.
+- ["New Project" page](../user/admin_area/appearance.md#new-project-pages): Customize the text to be displayed on the page that opens whenever your users create a new project.
- [Additional custom email text](../user/admin_area/settings/email.md#custom-additional-text-premium-only): Add additional custom text to emails sent from GitLab. **(PREMIUM ONLY)**
### Maintaining GitLab
@@ -105,7 +104,7 @@ Learn how to install, configure, update, and maintain your GitLab instance.
## User settings and permissions
- [Creating users](../user/profile/account/create_accounts.md): Create users manually or through authentication integrations.
-- [Libravatar](../customization/libravatar.md): Use Libravatar instead of Gravatar for user avatars.
+- [Libravatar](libravatar.md): Use Libravatar instead of Gravatar for user avatars.
- [Sign-up restrictions](../user/admin_area/settings/sign_up_restrictions.md): block email addresses of specific domains, or whitelist only specific domains.
- [Access restrictions](../user/admin_area/settings/visibility_and_access_controls.md#enabled-git-access-protocols): Define which Git access protocols can be used to talk to GitLab (SSH, HTTP, HTTPS).
- [Authentication and Authorization](auth/README.md): Configure external authentication with LDAP, SAML, CAS and additional providers.
@@ -120,7 +119,7 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- [Auditor users](auditor_users.md): Users with read-only access to all projects, groups, and other resources on the GitLab instance. **(PREMIUM ONLY)**
- [Incoming email](incoming_email.md): Configure incoming emails to allow
users to [reply by email](reply_by_email.md), create [issues by email](../user/project/issues/managing_issues.md#new-issue-via-email) and
- [merge requests by email](../user/project/merge_requests/index.md#create-new-merge-requests-by-email), and to enable [Service Desk](../user/project/service_desk.md).
+ [merge requests by email](../user/project/merge_requests/creating_merge_requests.md#create-new-merge-requests-by-email), and to enable [Service Desk](../user/project/service_desk.md).
- [Postfix for incoming email](reply_by_email_postfix_setup.md): Set up a
basic Postfix mail server with IMAP authentication on Ubuntu for incoming
emails.
@@ -162,9 +161,10 @@ Learn how to install, configure, update, and maintain your GitLab instance.
## Git configuration options
- [Custom Git hooks](custom_hooks.md): Custom Git hooks (on the filesystem) for when webhooks aren't enough.
-- [Git LFS configuration](../workflow/lfs/lfs_administration.md): Learn how to configure LFS for GitLab.
+- [Git LFS configuration](lfs/lfs_administration.md): Learn how to configure LFS for GitLab.
- [Housekeeping](housekeeping.md): Keep your Git repositories tidy and fast.
- [Configuring Git Protocol v2](git_protocol.md): Git protocol version 2 support.
+- [Manage large files with `git-annex` (Deprecated)](git_annex.md)
## Monitoring GitLab
diff --git a/doc/administration/integration/plantuml.md b/doc/administration/integration/plantuml.md
index e595c640aac..23803b82543 100644
--- a/doc/administration/integration/plantuml.md
+++ b/doc/administration/integration/plantuml.md
@@ -96,7 +96,7 @@ To enable the redirection, add the following line in `/etc/gitlab/gitlab.rb`:
nginx['custom_gitlab_server_config'] = "location /-/plantuml/ { \n proxy_cache off; \n proxy_pass http://plantuml:8080/; \n}\n"
# Built from source
-nginx['custom_gitlab_server_config'] = "location /-/plantuml/ { \n proxy_cache off; \n proxy_pass http://127.0.0.1:8080/plantuml/; \n}\n"
+nginx['custom_gitlab_server_config'] = "location /-/plantuml { \n rewrite ^/-/(plantuml.*) /$1 break;\n proxy_cache off; \n proxy_pass http://localhost:8080/plantuml; \n}\n"
```
To activate the changes, run the following command:
diff --git a/doc/administration/job_logs.md b/doc/administration/job_logs.md
index d6d56515ac6..6042786d101 100644
--- a/doc/administration/job_logs.md
+++ b/doc/administration/job_logs.md
@@ -1,8 +1,8 @@
# Job logs
-> [Renamed from Job Traces to Job logs](https://gitlab.com/gitlab-org/gitlab/issues/29121) in 12.4.
+> [Renamed from job traces to job logs](https://gitlab.com/gitlab-org/gitlab/issues/29121) in GitLab 12.5.
-Job logs (traces) are sent by GitLab Runner while it's processing a job. You can see
+Job logs are sent by GitLab Runner while it's processing a job. You can see
logs in job pages, pipelines, email notifications, etc.
## Data flow
@@ -33,9 +33,8 @@ To change the location where the job logs will be stored, follow the steps below
gitlab_ci['builds_directory'] = '/mnt/to/gitlab-ci/builds'
```
-1. Save the file and [reconfigure GitLab][] for the changes to take effect.
-
----
+1. Save the file and [reconfigure GitLab](restart_gitlab.md#omnibus-gitlab-reconfigure) for the
+ changes to take effect.
**In installations from source:**
@@ -48,10 +47,8 @@ To change the location where the job logs will be stored, follow the steps below
builds_path: path/to/builds/
```
-1. Save the file and [restart GitLab][] for the changes to take effect.
-
-[reconfigure gitlab]: restart_gitlab.md#omnibus-gitlab-reconfigure "How to reconfigure Omnibus GitLab"
-[restart gitlab]: restart_gitlab.md#installations-from-source "How to restart GitLab"
+1. Save the file and [restart GitLab](restart_gitlab.md#installations-from-source) for the changes
+ to take effect.
## Uploading logs to object storage
@@ -69,8 +66,8 @@ job output in the UI will be empty.
## New incremental logging architecture
-> [Introduced][ce-18169] in GitLab 10.4.
-> [Announced as General availability][ce-46097] in GitLab 11.0.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/18169) in GitLab 10.4.
+> - [Announced as generally available](https://gitlab.com/gitlab-org/gitlab-foss/issues/46097) in GitLab 11.0.
NOTE: **Note:**
This feature is off by default. See below for how to [enable or disable](#enabling-incremental-logging) it.
@@ -83,7 +80,7 @@ The data flow is the same as described in the [data flow section](#data-flow)
with one change: _the stored path of the first two phases is different_. This incremental
log architecture stores chunks of logs in Redis and a persistent store (object storage or database) instead of
file storage. Redis is used as first-class storage, and it stores up-to 128KB
-of data. Once the full chunk is sent, it is flushed to a persistent store, either object storage(temporary directory) or database.
+of data. Once the full chunk is sent, it is flushed to a persistent store, either object storage (temporary directory) or database.
After a while, the data in Redis and a persitent store will be archived to [object storage](#uploading-logs-to-object-storage).
The data are stored in the following Redis namespace: `Gitlab::Redis::SharedState`.
@@ -163,7 +160,3 @@ instance. If the number of jobs is 1000, 128MB (128KB * 1000) is consumed.
Also, it could pressure the database replication lag. `INSERT`s are generated to
indicate that we have log chunk. `UPDATE`s with 128KB of data is issued once we
receive multiple chunks.
-
-[ce-18169]: https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/18169
-[ce-21193]: https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/21193
-[ce-46097]: https://gitlab.com/gitlab-org/gitlab-foss/issues/46097
diff --git a/doc/workflow/lfs/images/git-annex-branches.png b/doc/administration/lfs/img/git-annex-branches.png
index 3d614f68177..3d614f68177 100644
--- a/doc/workflow/lfs/images/git-annex-branches.png
+++ b/doc/administration/lfs/img/git-annex-branches.png
Binary files differ
diff --git a/doc/workflow/lfs/img/lfs-icon.png b/doc/administration/lfs/img/lfs-icon.png
index eef9a14187a..eef9a14187a 100644
--- a/doc/workflow/lfs/img/lfs-icon.png
+++ b/doc/administration/lfs/img/lfs-icon.png
Binary files differ
diff --git a/doc/administration/lfs/lfs_administration.md b/doc/administration/lfs/lfs_administration.md
new file mode 100644
index 00000000000..f3b8029f487
--- /dev/null
+++ b/doc/administration/lfs/lfs_administration.md
@@ -0,0 +1,273 @@
+---
+disqus_identifier: 'https://docs.gitlab.com/ee/workflow/lfs/lfs_administration.html'
+---
+
+# GitLab Git LFS Administration
+
+Documentation on how to use Git LFS are under [Managing large binary files with Git LFS doc](manage_large_binaries_with_git_lfs.md).
+
+## Requirements
+
+- Git LFS is supported in GitLab starting with version 8.2.
+- Support for object storage, such as AWS S3, was introduced in 10.0.
+- Users need to install [Git LFS client](https://git-lfs.github.com) version 1.0.1 and up.
+
+## Configuration
+
+Git LFS objects can be large in size. By default, they are stored on the server
+GitLab is installed on.
+
+There are various configuration options to help GitLab server administrators:
+
+- Enabling/disabling Git LFS support
+- Changing the location of LFS object storage
+- Setting up object storage supported by [Fog](http://fog.io/about/provider_documentation.html)
+
+### Configuration for Omnibus installations
+
+In `/etc/gitlab/gitlab.rb`:
+
+```ruby
+# Change to true to enable lfs - enabled by default if not defined
+gitlab_rails['lfs_enabled'] = false
+
+# Optionally, change the storage path location. Defaults to
+# `#{gitlab_rails['shared_path']}/lfs-objects`. Which evaluates to
+# `/var/opt/gitlab/gitlab-rails/shared/lfs-objects` by default.
+gitlab_rails['lfs_storage_path'] = "/mnt/storage/lfs-objects"
+```
+
+### Configuration for installations from source
+
+In `config/gitlab.yml`:
+
+```yaml
+# Change to true to enable lfs
+ lfs:
+ enabled: false
+ storage_path: /mnt/storage/lfs-objects
+```
+
+## Storing LFS objects in remote object storage
+
+> [Introduced][ee-2760] in [GitLab Premium][eep] 10.0. Brought to GitLab Core in 10.7.
+
+It is possible to store LFS objects in remote object storage which allows you
+to offload local hard disk R/W operations, and free up disk space significantly.
+GitLab is tightly integrated with `Fog`, so you can refer to its [documentation](http://fog.io/about/provider_documentation.html)
+to check which storage services can be integrated with GitLab.
+You can also use external object storage in a private local network. For example,
+[MinIO](https://min.io/) is a standalone object storage service, is easy to set up, and works well with GitLab instances.
+
+GitLab provides two different options for the uploading mechanism: "Direct upload" and "Background upload".
+
+**Option 1. Direct upload**
+
+1. User pushes an lfs file to the GitLab instance
+1. GitLab-workhorse uploads the file directly to the external object storage
+1. GitLab-workhorse notifies GitLab-rails that the upload process is complete
+
+**Option 2. Background upload**
+
+1. User pushes an lfs file to the GitLab instance
+1. GitLab-rails stores the file in the local file storage
+1. GitLab-rails then uploads the file to the external object storage asynchronously
+
+The following general settings are supported.
+
+| Setting | Description | Default |
+|---------|-------------|---------|
+| `enabled` | Enable/disable object storage | `false` |
+| `remote_directory` | The bucket name where LFS objects will be stored| |
+| `direct_upload` | Set to true to enable direct upload of LFS without the need of local shared storage. Option may be removed once we decide to support only single storage for all files. | `false` |
+| `background_upload` | Set to false to disable automatic upload. Option may be removed once upload is direct to S3 | `true` |
+| `proxy_download` | Set to true to enable proxying all files served. Option allows to reduce egress traffic as this allows clients to download directly from remote storage instead of proxying all data | `false` |
+| `connection` | Various connection options described below | |
+
+The `connection` settings match those provided by [Fog](https://github.com/fog).
+
+Here is a configuration example with S3.
+
+| Setting | Description | example |
+|---------|-------------|---------|
+| `provider` | The provider name | AWS |
+| `aws_access_key_id` | AWS credentials, or compatible | `ABC123DEF456` |
+| `aws_secret_access_key` | AWS credentials, or compatible | `ABC123DEF456ABC123DEF456ABC123DEF456` |
+| `aws_signature_version` | AWS signature version to use. 2 or 4 are valid options. Digital Ocean Spaces and other providers may need 2. | 4 |
+| `enable_signature_v4_streaming` | Set to true to enable HTTP chunked transfers with [AWS v4 signatures](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html). Oracle Cloud S3 needs this to be false | true |
+| `region` | AWS region | us-east-1 |
+| `host` | S3 compatible host for when not using AWS, e.g. `localhost` or `storage.example.com` | s3.amazonaws.com |
+| `endpoint` | Can be used when configuring an S3 compatible service such as [MinIO](https://min.io), by entering a URL such as `http://127.0.0.1:9000` | (optional) |
+| `path_style` | Set to true to use `host/bucket_name/object` style paths instead of `bucket_name.host/object`. Leave as false for AWS S3 | false |
+| `use_iam_profile` | Set to true to use IAM profile instead of access keys | false
+
+Here is a configuration example with GCS.
+
+| Setting | Description | example |
+|---------|-------------|---------|
+| `provider` | The provider name | `Google` |
+| `google_project` | GCP project name | `gcp-project-12345` |
+| `google_client_email` | The email address of the service account | `foo@gcp-project-12345.iam.gserviceaccount.com` |
+| `google_json_key_location` | The json key path | `/path/to/gcp-project-12345-abcde.json` |
+
+NOTE: **Note:**
+The service account must have permission to access the bucket.
+[See more](https://cloud.google.com/storage/docs/authentication)
+
+Here is a configuration example with Rackspace Cloud Files.
+
+| Setting | Description | example |
+|---------|-------------|---------|
+| `provider` | The provider name | `Rackspace` |
+| `rackspace_username` | The username of the Rackspace account with access to the container | `joe.smith` |
+| `rackspace_api_key` | The API key of the Rackspace account with access to the container | `ABC123DEF456ABC123DEF456ABC123DE` |
+| `rackspace_region` | The Rackspace storage region to use, a three letter code from the [list of service access endpoints](https://developer.rackspace.com/docs/cloud-files/v1/general-api-info/service-access/) | `iad` |
+| `rackspace_temp_url_key` | The private key you have set in the Rackspace API for temporary URLs. Read more [here](https://developer.rackspace.com/docs/cloud-files/v1/use-cases/public-access-to-your-cloud-files-account/#tempurl) | `ABC123DEF456ABC123DEF456ABC123DE` |
+
+NOTE: **Note:**
+Regardless of whether the container has public access enabled or disabled, Fog will
+use the TempURL method to grant access to LFS objects. If you see errors in logs referencing
+instantiating storage with a temp-url-key, ensure that you have set they key properly
+on the Rackspace API and in `gitlab.rb`. You can verify the value of the key Rackspace
+has set by sending a GET request with token header to the service access endpoint URL
+and comparing the output of the returned headers.
+
+### Manual uploading to an object storage
+
+There are two ways to manually do the same thing as automatic uploading (described above).
+
+**Option 1: rake task**
+
+```sh
+rake gitlab:lfs:migrate
+```
+
+**Option 2: rails console**
+
+```sh
+$ sudo gitlab-rails console # Login to rails console
+
+> # Upload LFS files manually
+> LfsObject.where(file_store: [nil, 1]).find_each do |lfs_object|
+> lfs_object.file.migrate!(ObjectStorage::Store::REMOTE) if lfs_object.file.file.exists?
+> end
+```
+
+### S3 for Omnibus installations
+
+On Omnibus installations, the settings are prefixed by `lfs_object_store_`:
+
+1. Edit `/etc/gitlab/gitlab.rb` and add the following lines by replacing with
+ the values you want:
+
+ ```ruby
+ gitlab_rails['lfs_object_store_enabled'] = true
+ gitlab_rails['lfs_object_store_remote_directory'] = "lfs-objects"
+ gitlab_rails['lfs_object_store_connection'] = {
+ 'provider' => 'AWS',
+ 'region' => 'eu-central-1',
+ 'aws_access_key_id' => '1ABCD2EFGHI34JKLM567N',
+ 'aws_secret_access_key' => 'abcdefhijklmnopQRSTUVwxyz0123456789ABCDE',
+ # The below options configure an S3 compatible host instead of AWS
+ 'host' => 'localhost',
+ 'endpoint' => 'http://127.0.0.1:9000',
+ 'path_style' => true
+ }
+ ```
+
+1. Save the file and [reconfigure GitLab]s for the changes to take effect.
+1. Migrate any existing local LFS objects to the object storage:
+
+ ```bash
+ gitlab-rake gitlab:lfs:migrate
+ ```
+
+ This will migrate existing LFS objects to object storage. New LFS objects
+ will be forwarded to object storage unless
+ `gitlab_rails['lfs_object_store_background_upload']` is set to false.
+
+### S3 for installations from source
+
+For source installations the settings are nested under `lfs:` and then
+`object_store:`:
+
+1. Edit `/home/git/gitlab/config/gitlab.yml` and add or amend the following
+ lines:
+
+ ```yaml
+ lfs:
+ enabled: true
+ object_store:
+ enabled: false
+ remote_directory: lfs-objects # Bucket name
+ connection:
+ provider: AWS
+ aws_access_key_id: 1ABCD2EFGHI34JKLM567N
+ aws_secret_access_key: abcdefhijklmnopQRSTUVwxyz0123456789ABCDE
+ region: eu-central-1
+ # Use the following options to configure an AWS compatible host such as Minio
+ host: 'localhost'
+ endpoint: 'http://127.0.0.1:9000'
+ path_style: true
+ ```
+
+1. Save the file and [restart GitLab][] for the changes to take effect.
+1. Migrate any existing local LFS objects to the object storage:
+
+ ```bash
+ sudo -u git -H bundle exec rake gitlab:lfs:migrate RAILS_ENV=production
+ ```
+
+ This will migrate existing LFS objects to object storage. New LFS objects
+ will be forwarded to object storage unless `background_upload` is set to
+ false.
+
+### Migrating back to local storage
+
+In order to migrate back to local storage:
+
+1. Set both `direct_upload` and `background_upload` to false under the LFS object storage settings. Don't forget to restart GitLab.
+1. Run `rake gitlab:lfs:migrate_to_local` on your console.
+1. Disable `object_storage` for LFS objects in `gitlab.rb`. Remember to restart GitLab afterwards.
+
+## Storage statistics
+
+You can see the total storage used for LFS objects on groups and projects
+in the administration area, as well as through the [groups](../../api/groups.md)
+and [projects APIs](../../api/projects.md).
+
+## Troubleshooting: `Google::Apis::TransmissionError: execution expired`
+
+If LFS integration is configred with Google Cloud Storage and background uploads (`background_upload: true` and `direct_upload: false`),
+Sidekiq workers may encouter this error. This is because the uploading timed out with very large files.
+LFS files up to 6Gb can be uploaded without any extra steps, otherwise you need to use the following workaround.
+
+```shell
+$ sudo gitlab-rails console # Login to rails console
+
+> # Set up timeouts. 20 minutes is enough to upload 30GB LFS files.
+> # These settings are only in effect for the same session, i.e. they are not effective for sidekiq workers.
+> ::Google::Apis::ClientOptions.default.open_timeout_sec = 1200
+> ::Google::Apis::ClientOptions.default.read_timeout_sec = 1200
+> ::Google::Apis::ClientOptions.default.send_timeout_sec = 1200
+
+> # Upload LFS files manually. This process does not use sidekiq at all.
+> LfsObject.where(file_store: [nil, 1]).find_each do |lfs_object|
+> lfs_object.file.migrate!(ObjectStorage::Store::REMOTE) if lfs_object.file.file.exists?
+> end
+```
+
+See more information in [!19581](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/19581)
+
+## Known limitations
+
+- Support for removing unreferenced LFS objects was added in 8.14 onwards.
+- LFS authentications via SSH was added with GitLab 8.12.
+- Only compatible with the Git LFS client versions 1.1.0 and up, or 1.0.2.
+- The storage statistics currently count each LFS object multiple times for
+ every project linking to it.
+
+[reconfigure gitlab]: ../restart_gitlab.md#omnibus-gitlab-reconfigure "How to reconfigure Omnibus GitLab"
+[restart gitlab]: ../restart_gitlab.md#installations-from-source "How to restart GitLab"
+[eep]: https://about.gitlab.com/pricing/ "GitLab Premium"
+[ee-2760]: https://gitlab.com/gitlab-org/gitlab/merge_requests/2760
diff --git a/doc/administration/lfs/manage_large_binaries_with_git_lfs.md b/doc/administration/lfs/manage_large_binaries_with_git_lfs.md
new file mode 100644
index 00000000000..1fd3077ecb9
--- /dev/null
+++ b/doc/administration/lfs/manage_large_binaries_with_git_lfs.md
@@ -0,0 +1,266 @@
+---
+disqus_identifier: 'https://docs.gitlab.com/ee/workflow/lfs/manage_large_binaries_with_git_lfs.html'
+---
+
+# Git LFS
+
+Managing large files such as audio, video and graphics files has always been one
+of the shortcomings of Git. The general recommendation is to not have Git repositories
+larger than 1GB to preserve performance.
+
+![Git LFS tracking status](img/lfs-icon.png)
+
+An LFS icon is shown on files tracked by Git LFS to denote if a file is stored
+as a blob or as an LFS pointer.
+
+## How it works
+
+Git LFS client talks with the GitLab server over HTTPS. It uses HTTP Basic Authentication
+to authorize client requests. Once the request is authorized, Git LFS client receives
+instructions from where to fetch or where to push the large file.
+
+## GitLab server configuration
+
+Documentation for GitLab instance administrators is under [LFS administration doc](lfs_administration.md).
+
+## Requirements
+
+- Git LFS is supported in GitLab starting with version 8.2
+- Git LFS must be enabled under project settings
+- [Git LFS client](https://git-lfs.github.com) version 1.0.1 and up
+
+## Known limitations
+
+- Git LFS v1 original API is not supported since it was deprecated early in LFS
+ development
+- When SSH is set as a remote, Git LFS objects still go through HTTPS
+- Any Git LFS request will ask for HTTPS credentials to be provided so a good Git
+ credentials store is recommended
+- Git LFS always assumes HTTPS so if you have GitLab server on HTTP you will have
+ to add the URL to Git config manually (see [troubleshooting](#troubleshooting))
+
+NOTE: **Note:**
+With 8.12 GitLab added LFS support to SSH. The Git LFS communication
+still goes over HTTP, but now the SSH client passes the correct credentials
+to the Git LFS client, so no action is required by the user.
+
+## Using Git LFS
+
+Lets take a look at the workflow when you need to check large files into your Git
+repository with Git LFS. For example, if you want to upload a very large file and
+check it into your Git repository:
+
+```bash
+git clone git@gitlab.example.com:group/project.git
+git lfs install # initialize the Git LFS project
+git lfs track "*.iso" # select the file extensions that you want to treat as large files
+```
+
+Once a certain file extension is marked for tracking as a LFS object you can use
+Git as usual without having to redo the command to track a file with the same extension:
+
+```bash
+cp ~/tmp/debian.iso ./ # copy a large file into the current directory
+git add . # add the large file to the project
+git commit -am "Added Debian iso" # commit the file meta data
+git push origin master # sync the git repo and large file to the GitLab server
+```
+
+**Make sure** that `.gitattributes` is tracked by Git. Otherwise Git
+LFS will not be working properly for people cloning the project:
+
+```bash
+git add .gitattributes
+```
+
+Cloning the repository works the same as before. Git automatically detects the
+LFS-tracked files and clones them via HTTP. If you performed the `git clone`
+command with a SSH URL, you have to enter your GitLab credentials for HTTP
+authentication.
+
+```bash
+git clone git@gitlab.example.com:group/project.git
+```
+
+If you already cloned the repository and you want to get the latest LFS object
+that are on the remote repository, eg. for a branch from origin:
+
+```bash
+git lfs fetch origin master
+```
+
+### Migrate an existing repo to Git LFS
+
+Read the documentation on how to [migrate an existing Git repo with Git LFS](../../topics/git/migrate_to_git_lfs/index.md).
+
+## File Locking
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/35856) in GitLab 10.5.
+
+The first thing to do before using File Locking is to tell Git LFS which
+kind of files are lockable. The following command will store PNG files
+in LFS and flag them as lockable:
+
+```bash
+git lfs track "*.png" --lockable
+```
+
+After executing the above command a file named `.gitattributes` will be
+created or updated with the following content:
+
+```bash
+*.png filter=lfs diff=lfs merge=lfs -text lockable
+```
+
+You can also register a file type as lockable without using LFS
+(In order to be able to lock/unlock a file you need a remote server that implements the LFS File Locking API),
+in order to do that you can edit the `.gitattributes` file manually:
+
+```bash
+*.pdf lockable
+```
+
+After a file type has been registered as lockable, Git LFS will make
+them readonly on the file system automatically. This means you will
+need to lock the file before editing it.
+
+### Managing Locked Files
+
+Once you're ready to edit your file you need to lock it first:
+
+```bash
+git lfs lock images/banner.png
+Locked images/banner.png
+```
+
+This will register the file as locked in your name on the server:
+
+```bash
+git lfs locks
+images/banner.png joe ID:123
+```
+
+Once you have pushed your changes, you can unlock the file so others can
+also edit it:
+
+```bash
+git lfs unlock images/banner.png
+```
+
+You can also unlock by id:
+
+```bash
+git lfs unlock --id=123
+```
+
+If for some reason you need to unlock a file that was not locked by you,
+you can use the `--force` flag as long as you have a `maintainer` access on
+the project:
+
+```bash
+git lfs unlock --id=123 --force
+```
+
+## Troubleshooting
+
+### error: Repository or object not found
+
+There are a couple of reasons why this error can occur:
+
+- You don't have permissions to access certain LFS object
+
+Check if you have permissions to push to the project or fetch from the project.
+
+- Project is not allowed to access the LFS object
+
+LFS object you are trying to push to the project or fetch from the project is not
+available to the project anymore. Probably the object was removed from the server.
+
+- Local Git repository is using deprecated LFS API
+
+### Invalid status for `<url>` : 501
+
+Git LFS will log the failures into a log file.
+To view this log file, while in project directory:
+
+```bash
+git lfs logs last
+```
+
+If the status `error 501` is shown, it is because:
+
+- Git LFS is not enabled in project settings. Check your project settings and
+ enable Git LFS.
+
+- Git LFS support is not enabled on the GitLab server. Check with your GitLab
+ administrator why Git LFS is not enabled on the server. See
+ [LFS administration documentation](lfs_administration.md) for instructions
+ on how to enable LFS support.
+
+- Git LFS client version is not supported by GitLab server. Check your Git LFS
+ version with `git lfs version`. Check the Git config of the project for traces
+ of deprecated API with `git lfs -l`. If `batch = false` is set in the config,
+ remove the line and try to update your Git LFS client. Only version 1.0.1 and
+ newer are supported.
+
+### getsockopt: connection refused
+
+If you push a LFS object to a project and you receive an error similar to:
+`Post <URL>/info/lfs/objects/batch: dial tcp IP: getsockopt: connection refused`,
+the LFS client is trying to reach GitLab through HTTPS. However, your GitLab
+instance is being served on HTTP.
+
+This behaviour is caused by Git LFS using HTTPS connections by default when a
+`lfsurl` is not set in the Git config.
+
+To prevent this from happening, set the lfs url in project Git config:
+
+```bash
+git config --add lfs.url "http://gitlab.example.com/group/project.git/info/lfs"
+```
+
+### Credentials are always required when pushing an object
+
+NOTE: **Note:**
+With 8.12 GitLab added LFS support to SSH. The Git LFS communication
+still goes over HTTP, but now the SSH client passes the correct credentials
+to the Git LFS client, so no action is required by the user.
+
+Given that Git LFS uses HTTP Basic Authentication to authenticate the user pushing
+the LFS object on every push for every object, user HTTPS credentials are required.
+
+By default, Git has support for remembering the credentials for each repository
+you use. This is described in [Git credentials man pages](https://git-scm.com/docs/gitcredentials).
+
+For example, you can tell Git to remember the password for a period of time in
+which you expect to push the objects:
+
+```bash
+git config --global credential.helper 'cache --timeout=3600'
+```
+
+This will remember the credentials for an hour after which Git operations will
+require re-authentication.
+
+If you are using OS X you can use `osxkeychain` to store and encrypt your credentials.
+For Windows, you can use `wincred` or Microsoft's [Git Credential Manager for Windows](https://github.com/Microsoft/Git-Credential-Manager-for-Windows/releases).
+
+More details about various methods of storing the user credentials can be found
+on [Git Credential Storage documentation](https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage).
+
+### LFS objects are missing on push
+
+GitLab checks files to detect LFS pointers on push. If LFS pointers are detected, GitLab tries to verify that those files already exist in LFS on GitLab.
+
+Verify that LFS in installed locally and consider a manual push with `git lfs push --all`.
+
+If you are storing LFS files outside of GitLab you can disable LFS on the project by setting `lfs_enabled: false` with the [projects API](../../api/projects.md#edit-project).
+
+### Hosting LFS objects externally
+
+It is possible to host LFS objects externally by setting a custom LFS url with `git config -f .lfsconfig lfs.url https://example.com/<project>.git/info/lfs`.
+
+You might choose to do this if you are using an appliance like a Sonatype Nexus to store LFS data. If you choose to use an external LFS store,
+GitLab will not be able to verify LFS objects which means that pushes will fail if you have GitLab LFS support enabled.
+
+To stop push failure, LFS support can be disabled in the [Project settings](../../user/project/settings/index.md). This means you will lose GitLab LFS value-adds (Verifying LFS objects, UI integration for LFS).
diff --git a/doc/administration/lfs/migrate_from_git_annex_to_git_lfs.md b/doc/administration/lfs/migrate_from_git_annex_to_git_lfs.md
new file mode 100644
index 00000000000..cf798472d62
--- /dev/null
+++ b/doc/administration/lfs/migrate_from_git_annex_to_git_lfs.md
@@ -0,0 +1,254 @@
+# Migration guide from Git Annex to Git LFS
+
+>**Note:**
+Git Annex support [has been removed][issue-remove-annex] in GitLab Enterprise
+Edition 9.0 (2017/03/22).
+
+Both [Git Annex][] and [Git LFS][] are tools to manage large files in Git.
+
+## History
+
+Git Annex [was introduced in GitLab Enterprise Edition 7.8][post-3], at a time
+where Git LFS didn't yet exist. A few months later, GitLab brought support for
+Git LFS in [GitLab 8.2][post-2] and is available for both Community and
+Enterprise editions.
+
+## Differences between Git Annex and Git LFS
+
+Some items below are general differences between the two protocols and some are
+ones that GitLab developed.
+
+- Git Annex works only through SSH, whereas Git LFS works both with SSH and HTTPS
+ (SSH support was added in GitLab 8.12).
+- Annex files are stored in a sub-directory of the normal repositories, whereas
+ LFS files are stored outside of the repositories in a place you can define.
+- Git Annex requires a more complex setup, but has much more options than Git
+ LFS. You can compare the commands each one offers by running `man git-annex`
+ and `man git-lfs`.
+- Annex files cannot be browsed directly in GitLab's interface, whereas LFS
+ files can.
+
+## Migration steps
+
+>**Note:**
+Since Git Annex files are stored in a sub-directory of the normal repositories
+(`.git/annex/objects`) and LFS files are stored outside of the repositories,
+they are not compatible as they are using a different scheme. Therefore, the
+migration has to be done manually per repository.
+
+There are basically two steps you need to take in order to migrate from Git
+Annex to Git LFS.
+
+### TL; DR
+
+If you know what you are doing and want to skip the reading, this is what you
+need to do (we assume you have [git-annex enabled](../git_annex.md#using-gitlab-git-annex) in your
+repository and that you have made backups in case something goes wrong).
+Fire up a terminal, navigate to your Git repository and:
+
+1. Disable `git-annex`:
+
+ ```bash
+ git annex sync --content
+ git annex direct
+ git annex uninit
+ git annex indirect
+ ```
+
+1. Enable `git-lfs`:
+
+ ```
+ git lfs install
+ git lfs track <files>
+ git add .
+ git commit -m "commit message"
+ git push
+ ```
+
+### Disabling Git Annex in your repo
+
+Before changing anything, make sure you have a backup of your repository first.
+There are a couple of ways to do that, but you can simply clone it to another
+local path and maybe push it to GitLab if you want a remote backup as well.
+Here you'll find a guide on
+[how to back up a **git-annex** repository to an external hard drive][bkp-ext-drive].
+
+Since Annex files are stored as objects with symlinks and cannot be directly
+modified, we need to first remove those symlinks.
+
+NOTE: **Note:**
+Make sure the you read about the [`direct` mode][annex-direct] as it contains
+useful information that may fit in your use case. Note that `annex direct` is
+deprecated in Git Annex version 6, so you may need to upgrade your repository
+if the server also has Git Annex 6 installed. Read more in the
+[Git Annex troubleshooting tips](../git_annex.md#troubleshooting-tips) section.
+
+1. Backup your repository
+
+ ```bash
+ cd repository
+ git annex sync --content
+ cd ..
+ git clone repository repository-backup
+ cd repository-backup
+ git annex get
+ cd ..
+ ```
+
+1. Use `annex direct`:
+
+ ```bash
+ cd repository
+ git annex direct
+ ```
+
+ The output should be similar to this:
+
+ ```bash
+ commit
+ On branch master
+ Your branch is up-to-date with 'origin/master'.
+ nothing to commit, working tree clean
+ ok
+ direct debian.iso ok
+ direct ok
+ ```
+
+1. Disable Git Annex with [`annex uninit`][uninit]:
+
+ ```bash
+ git annex uninit
+ ```
+
+ The output should be similar to this:
+
+ ```bash
+ unannex debian.iso ok
+ Deleted branch git-annex (was 2534d2c).
+ ```
+
+ This will `unannex` every file in the repository, leaving the original files.
+
+1. Switch back to `indirect` mode:
+
+ ```bash
+ git annex indirect
+ ```
+
+ The output should be similar to this:
+
+ ```bash
+ (merging origin/git-annex into git-annex...)
+ (recording state in git...)
+ commit (recording state in git...)
+
+ ok
+ (recording state in git...)
+ [master fac3194] commit before switching to indirect mode
+ 1 file changed, 1 deletion(-)
+ delete mode 120000 alpine-virt-3.4.4-x86_64.iso
+ ok
+ indirect ok
+ ok
+ ```
+
+---
+
+At this point, you have two options. Either add, commit and push the files
+directly back to GitLab or switch to Git LFS. We will tackle the LFS switch in
+the next section.
+
+### Enabling Git LFS in your repo
+
+Git LFS is enabled by default on all GitLab products (GitLab CE, GitLab EE,
+GitLab.com), therefore, you don't need to do anything server-side.
+
+1. First, make sure you have `git-lfs` installed locally:
+
+ ```bash
+ git lfs help
+ ```
+
+ If the terminal doesn't prompt you with a full response on `git-lfs` commands,
+ [install the Git LFS client][install-lfs] first.
+
+1. Inside the repo, run the following command to initiate LFS:
+
+ ```bash
+ git lfs install
+ ```
+
+1. Enable `git-lfs` for the group of files you want to track. You
+ can track specific files, all files containing the same extension, or an
+ entire directory:
+
+ ```bash
+ git lfs track images/01.png # per file
+ git lfs track **/*.png # per extension
+ git lfs track images/ # per directory
+ ```
+
+ Once you do that, run `git status` and you'll see `.gitattributes` added
+ to your repo. It collects all file patterns that you chose to track via
+ `git-lfs`.
+
+1. Add the files, commit and push them to GitLab:
+
+ ```bash
+ git add .
+ git commit -m "commit message"
+ git push
+ ```
+
+ If your remote is set up with HTTP, you will be asked to enter your login
+ credentials. If you have [2FA enabled](../../user/profile/account/two_factor_authentication.md), make sure to use a
+ [personal access token](../../user/profile/account/two_factor_authentication.md#personal-access-tokens)
+ instead of your password.
+
+## Removing the Git Annex branches
+
+After the migration finishes successfully, you can remove all `git-annex`
+related branches from your repository.
+
+On GitLab, navigate to your project's **Repository ➔ Branches** and delete all
+branches created by Git Annex: `git-annex`, and all under `synced/`.
+
+![repository branches](img/git-annex-branches.png)
+
+You can also do this on the command line with:
+
+```bash
+git branch -d synced/master
+git branch -d synced/git-annex
+git push origin :synced/master
+git push origin :synced/git-annex
+git push origin :git-annex
+git remote prune origin
+```
+
+If there are still some Annex objects inside your repository (`.git/annex/`)
+or references inside `.git/config`, run `annex uninit` again:
+
+```bash
+git annex uninit
+```
+
+## Further Reading
+
+- (Blog Post) [Getting Started with Git FLS][post-1]
+- (Blog Post) [Announcing LFS Support in GitLab][post-2]
+- (Blog Post) [GitLab Annex Solves the Problem of Versioning Large Binaries with Git][post-3]
+- (GitLab Docs) [Git Annex](../git_annex.md)
+- (GitLab Docs) [Git LFS](manage_large_binaries_with_git_lfs.md)
+
+[annex-direct]: https://git-annex.branchable.com/direct_mode/
+[bkp-ext-drive]: https://www.thomas-krenn.com/en/wiki/Git-annex_Repository_on_an_External_Hard_Drive
+[Git Annex]: http://git-annex.branchable.com/
+[Git LFS]: https://git-lfs.github.com/
+[install-lfs]: https://git-lfs.github.com/
+[issue-remove-annex]: https://gitlab.com/gitlab-org/gitlab/issues/1648
+[lfs-track]: https://about.gitlab.com/blog/2017/01/30/getting-started-with-git-lfs-tutorial/#tracking-files-with-lfs
+[post-1]: https://about.gitlab.com/blog/2017/01/30/getting-started-with-git-lfs-tutorial/
+[post-2]: https://about.gitlab.com/blog/2015/11/23/announcing-git-lfs-support-in-gitlab/
+[post-3]: https://about.gitlab.com/blog/2015/02/17/gitlab-annex-solves-the-problem-of-versioning-large-binaries-with-git/
+[uninit]: https://git-annex.branchable.com/git-annex-uninit/
diff --git a/doc/administration/logs.md b/doc/administration/logs.md
index dae0dae8395..aa10cdd220c 100644
--- a/doc/administration/logs.md
+++ b/doc/administration/logs.md
@@ -42,6 +42,48 @@ User clone/fetch activity using http transport appears in this log as `action: g
In addition, the log contains the IP address from which the request originated
(`remote_ip`) as well as the user's ID (`user_id`), and username (`username`).
+NOTE: **Note:** Starting with GitLab 12.5, if an error occurs, an
+`exception` field is included with `class`, `message`, and
+`backtrace`. Previous versions included an `error` field instead of
+`exception.class` and `exception.message`. For example:
+
+```json
+{
+ "method": "GET",
+ "path": "/admin",
+ "format": "html",
+ "controller": "Admin::DashboardController",
+ "action": "index",
+ "status": 500,
+ "duration": 2584.11,
+ "view": 0,
+ "db": 9.21,
+ "time": "2019-11-14T13:12:46.156Z",
+ "params": [],
+ "remote_ip": "127.0.0.1",
+ "user_id": 1,
+ "username": "root",
+ "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:70.0) Gecko/20100101 Firefox/70.0",
+ "queue_duration": 274.35,
+ "correlation_id": "KjDVUhNvvV3",
+ "cpu_s": 2.837645135999999,
+ "exception": {
+ "class": "NameError",
+ "message": "undefined local variable or method `adsf' for #<Admin::DashboardController:0x00007ff3c9648588>",
+ "backtrace": [
+ "app/controllers/admin/dashboard_controller.rb:11:in `index'",
+ "ee/app/controllers/ee/admin/dashboard_controller.rb:14:in `index'",
+ "ee/lib/gitlab/ip_address_state.rb:10:in `with'",
+ "ee/app/controllers/ee/application_controller.rb:43:in `set_current_ip_address'",
+ "lib/gitlab/session.rb:11:in `with_session'",
+ "app/controllers/application_controller.rb:450:in `set_session_storage'",
+ "app/controllers/application_controller.rb:444:in `set_locale'",
+ "ee/lib/gitlab/jira/middleware.rb:19:in `call'"
+ ]
+ }
+}
+```
+
## `production.log`
This file lives in `/var/log/gitlab/gitlab-rails/production.log` for
diff --git a/doc/administration/monitoring/gitlab_instance_administration_project/index.md b/doc/administration/monitoring/gitlab_instance_administration_project/index.md
index bb76ad59e3b..b07bbafaf7d 100644
--- a/doc/administration/monitoring/gitlab_instance_administration_project/index.md
+++ b/doc/administration/monitoring/gitlab_instance_administration_project/index.md
@@ -1,6 +1,7 @@
# GitLab instance administration project
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/56883) in GitLab 12.2.
+NOTE: **Note:**
+This feature is not yet available and is [planned for 12.6](https://gitlab.com/gitlab-org/gitlab/issues/32351).
GitLab has been adding the ability for administrators to see insights into the health of
their GitLab instance. In order to surface this experience in a native way, similar to how
diff --git a/doc/administration/monitoring/performance/img/performance_bar.png b/doc/administration/monitoring/performance/img/performance_bar.png
index d1187fd879a..acad60f863e 100644
--- a/doc/administration/monitoring/performance/img/performance_bar.png
+++ b/doc/administration/monitoring/performance/img/performance_bar.png
Binary files differ
diff --git a/doc/administration/monitoring/performance/performance_bar.md b/doc/administration/monitoring/performance/performance_bar.md
index 53c08e32cb2..a52b6227e14 100644
--- a/doc/administration/monitoring/performance/performance_bar.md
+++ b/doc/administration/monitoring/performance/performance_bar.md
@@ -8,14 +8,17 @@ activated, it looks as follows:
It allows you to see (from left to right):
- the current host serving the page
-- time taken and number of DB queries, click through for details of these queries
+- time taken and number of DB queries; click through for details of these queries
![SQL profiling using the Performance Bar](img/performance_bar_sql_queries.png)
-- time taken and number of [Gitaly] calls, click through for details of these calls
+- time taken and number of [Gitaly] calls; click through for details of these calls
![Gitaly profiling using the Performance Bar](img/performance_bar_gitaly_calls.png)
-- time taken and number of [Rugged] calls, click through for details of these calls
+- time taken and number of [Rugged] calls; click through for details of these calls
![Rugged profiling using the Performance Bar](img/performance_bar_rugged_calls.png)
-- time taken and number of Redis calls, click through for details of these calls
+- time taken and number of Redis calls; click through for details of these calls
![Redis profiling using the Performance Bar](img/performance_bar_redis_calls.png)
+- a link to add a request's details to the performance bar; the request can be
+ added by its full URL (authenticated as the current user), or by the value of
+ its `X-Request-Id` header
On the far right is a request selector that allows you to view the same metrics
(excluding the page timing and line profiler) for any requests made while the
@@ -51,7 +54,7 @@ Make sure _Enable the Performance Bar_ is checked and hit
**Save** to save the changes.
Once the Performance Bar is enabled, you will need to press the [<kbd>p</kbd> +
-<kbd>b</kbd> keyboard shortcut](../../../workflow/shortcuts.md) to actually
+<kbd>b</kbd> keyboard shortcut](../../../user/shortcuts.md) to actually
display it.
You can toggle the Bar using the same shortcut.
diff --git a/doc/administration/monitoring/prometheus/index.md b/doc/administration/monitoring/prometheus/index.md
index c35d6f505be..c0b563bd76e 100644
--- a/doc/administration/monitoring/prometheus/index.md
+++ b/doc/administration/monitoring/prometheus/index.md
@@ -78,6 +78,31 @@ To change the address/port that Prometheus listens on:
1. Save the file and [reconfigure GitLab][reconfigure] for the changes to
take effect
+### Adding custom scrape configs
+
+You can configure additional scrape targets for the GitLab Omnibus-bundled
+Prometheus by editing `prometheus['scrape_configs']` in `/etc/gitlab/gitlab.rb`
+using the [Prometheus scrape target configuration](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#%3Cscrape_config%3E)
+syntax.
+
+Here is an example configuration to scrape `http://1.1.1.1:8060/probe?param_a=test&param_b=additional_test`:
+
+```ruby
+prometheus['scrape_configs'] = [
+ {
+ 'job_name': 'custom-scrape',
+ 'metrics_path': '/probe',
+ 'params' => {
+ 'param_a' => ['test'],
+ 'param_b' => ['additional_test']
+ },
+ 'static_configs' => [
+ 'targets' => ['1.1.1.1:8060'],
+ ],
+ },
+]
+```
+
### Using an external Prometheus server
NOTE: **Note:**
diff --git a/doc/administration/operations/index.md b/doc/administration/operations/index.md
index df208b3f427..1d80e23eecf 100644
--- a/doc/administration/operations/index.md
+++ b/doc/administration/operations/index.md
@@ -21,3 +21,6 @@ Keep your GitLab instance up and running smoothly.
performance can have a big impact on GitLab performance, especially for actions
that read or write Git repositories. This information will help benchmark
filesystem performance against known good and bad real-world systems.
+- [ChatOps Scripts](https://gitlab.com/gitlab-com/chatops): The GitLab.com Infrastructure team uses this repository to house
+ common ChatOps scripts they use to troubleshoot and maintain the production instance of GitLab.com.
+ These scripts are likely useful to administrators of GitLab instances of all sizes.
diff --git a/doc/administration/operations/sidekiq_memory_killer.md b/doc/administration/operations/sidekiq_memory_killer.md
index 79e9fb778b6..6438dbb9dab 100644
--- a/doc/administration/operations/sidekiq_memory_killer.md
+++ b/doc/administration/operations/sidekiq_memory_killer.md
@@ -34,7 +34,7 @@ The MemoryKiller is controlled using environment variables.
In _daemon_ mode, the MemoryKiller checks the Sidekiq process RSS every 3 seconds
(defined by `SIDEKIQ_MEMORY_KILLER_CHECK_INTERVAL`).
-- `SIDEKIQ_MEMORY_KILLER_MAX_RSS`: if this variable is set, and its value is greater
+- `SIDEKIQ_MEMORY_KILLER_MAX_RSS` (KB): if this variable is set, and its value is greater
than 0, the MemoryKiller is enabled. Otherwise the MemoryKiller is disabled.
`SIDEKIQ_MEMORY_KILLER_MAX_RSS` defines the Sidekiq process allowed RSS.
@@ -52,7 +52,7 @@ The MemoryKiller is controlled using environment variables.
[in the Omnibus GitLab
repository](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/files/gitlab-cookbooks/gitlab/attributes/default.rb).
-- `SIDEKIQ_MEMORY_KILLER_HARD_LIMIT_RSS`: is used by _daemon_ mode. If the Sidekiq
+- `SIDEKIQ_MEMORY_KILLER_HARD_LIMIT_RSS` (KB): is used by _daemon_ mode. If the Sidekiq
process RSS (expressed in kilobytes) exceeds `SIDEKIQ_MEMORY_KILLER_HARD_LIMIT_RSS`,
an immediate graceful restart of Sidekiq is triggered.
diff --git a/doc/administration/packages/container_registry.md b/doc/administration/packages/container_registry.md
index bf86a549fda..a62e3ab603d 100644
--- a/doc/administration/packages/container_registry.md
+++ b/doc/administration/packages/container_registry.md
@@ -18,7 +18,9 @@ You can read more about the Docker Registry at
**Omnibus GitLab installations**
-All you have to do is configure the domain name under which the Container
+If you are using the Omnibus GitLab built in [Let's Encrypt integration](https://docs.gitlab.com/omnibus/settings/ssl.html#lets-encrypt-integration), as of GitLab 12.5, the Container Registry will be automatically enabled on port 5050 of the default domain.
+
+If you would like to use a separate domain, all you have to do is configure the domain name under which the Container
Registry will listen to. Read
[#container-registry-domain-configuration](#container-registry-domain-configuration)
and pick one of the two options that fits your case.
@@ -353,7 +355,7 @@ configuration.
NOTE: **Note:** Enabling a storage driver other than `filesystem` would mean
that your Docker client needs to be able to access the storage backend directly.
-In that case, you must use an address that resolves and is accessible outside GitLab server.
+In that case, you must use an address that resolves and is accessible outside GitLab server. The Docker client will continue to authenticate via GitLab but data transfer will be direct to and from the storage backend.
The different supported drivers are:
@@ -877,6 +879,6 @@ The above image shows:
- The HEAD request to the AWS bucket reported a 403 Unauthorized.
What does this mean? This strongly suggests that the S3 user does not have the right
-[permissions to perform a HEAD request](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectHEAD.html).
+[permissions to perform a HEAD request](https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadObject.html).
The solution: check the [IAM permissions again](https://docs.docker.com/registry/storage-drivers/s3/).
Once the right permissions were set, the error will go away.
diff --git a/doc/administration/pages/index.md b/doc/administration/pages/index.md
index cacfb73451c..f51c375860b 100644
--- a/doc/administration/pages/index.md
+++ b/doc/administration/pages/index.md
@@ -120,7 +120,7 @@ The Pages daemon doesn't listen to the outside world.
1. Set the external URL for GitLab Pages in `/etc/gitlab/gitlab.rb`:
- ```shell
+ ```ruby
pages_external_url 'http://example.io'
```
@@ -145,7 +145,7 @@ outside world.
1. Place the certificate and key inside `/etc/gitlab/ssl`
1. In `/etc/gitlab/gitlab.rb` specify the following configuration:
- ```shell
+ ```ruby
pages_external_url 'https://example.io'
pages_nginx['redirect_http_to_https'] = true
@@ -167,7 +167,7 @@ behavior:
1. Edit `/etc/gitlab/gitlab.rb`.
1. Set the `inplace_chroot` to `true` for GitLab Pages:
- ```shell
+ ```ruby
gitlab_pages['inplace_chroot'] = true
```
@@ -202,7 +202,7 @@ world. Custom domains are supported, but no TLS.
1. Edit `/etc/gitlab/gitlab.rb`:
- ```shell
+ ```ruby
pages_external_url "http://example.io"
nginx['listen_addresses'] = ['192.0.2.1']
pages_nginx['enable'] = false
@@ -233,7 +233,7 @@ world. Custom domains and TLS are supported.
1. Edit `/etc/gitlab/gitlab.rb`:
- ```shell
+ ```ruby
pages_external_url "https://example.io"
nginx['listen_addresses'] = ['192.0.2.1']
pages_nginx['enable'] = false
@@ -271,7 +271,7 @@ sites served under a custom domain.
To enable it, you'll need to:
-1. Choose an email on which you will recieve notifications about expiring domains.
+1. Choose an email on which you will receive notifications about expiring domains.
1. Navigate to your instance's **Admin Area > Settings > Preferences** and expand **Pages** settings.
1. Enter the email for receiving notifications and accept Let's Encrypt's Terms of Service as shown below.
1. Click **Save changes**.
@@ -332,7 +332,7 @@ Follow the steps below to configure verbose logging of GitLab Pages daemon.
If you wish to make it log events with level `DEBUG` you must configure this in
`/etc/gitlab/gitlab.rb`:
- ```shell
+ ```ruby
gitlab_pages['log_verbose'] = true
```
@@ -347,7 +347,7 @@ are stored.
If you wish to store them in another location you must set it up in
`/etc/gitlab/gitlab.rb`:
- ```shell
+ ```ruby
gitlab_rails['pages_path'] = "/mnt/storage/pages"
```
@@ -363,14 +363,14 @@ Omnibus GitLab 11.1.
If you wish to disable it you must configure this in
`/etc/gitlab/gitlab.rb`:
- ```shell
+ ```ruby
gitlab_pages['listen_proxy'] = nil
```
If you wish to make it listen on a different port you must configure this also in
`/etc/gitlab/gitlab.rb`:
- ```shell
+ ```ruby
gitlab_pages['listen_proxy'] = "localhost:10080"
```
@@ -382,21 +382,26 @@ The maximum size of the unpacked archive per project can be configured in the
Admin area under the Application settings in the **Maximum size of pages (MB)**.
The default is 100MB.
-## Running GitLab Pages in a separate server
+## Running GitLab Pages on a separate server
-You may want to run GitLab Pages daemon on a separate server in order to decrease the load on your main application server.
-Follow the steps below to configure GitLab Pages in a separate server.
+You can run the GitLab Pages daemon on a separate server in order to decrease the load on your main application server.
-1. Suppose you have the main GitLab application server named `app1`. Prepare
- new Linux server (let's call it `app2`), create NFS share there and configure access to
- this share from `app1`. Let's use the default GitLab Pages folder `/var/opt/gitlab/gitlab-rails/shared/pages`
- as the shared folder on `app2` and mount it to `/mnt/pages` on `app1`.
+To configure GitLab Pages on a separate server:
-1. On `app2` install GitLab omnibus and modify `/etc/gitlab/gitlab.rb` this way:
+1. Set up a new server. This will become the **Pages server**.
- ```shell
+1. Create an NFS share on the new server and configure this share to
+ allow access from your main **GitLab server**. For this example, we use the
+ default GitLab Pages folder `/var/opt/gitlab/gitlab-rails/shared/pages`
+ as the shared folder on the new server and we will mount it to `/mnt/pages`
+ on the **GitLab server**.
+
+1. On the **Pages server**, install Omnibus GitLab and modify `/etc/gitlab/gitlab.rb`
+ to include:
+
+ ```ruby
external_url 'http://<ip-address-of-the-server>'
- pages_external_url "http://<your-pages-domain>"
+ pages_external_url "http://<your-pages-server-URL>"
postgresql['enable'] = false
redis['enable'] = false
prometheus['enable'] = false
@@ -409,20 +414,82 @@ Follow the steps below to configure GitLab Pages in a separate server.
gitlab_rails['auto_migrate'] = false
```
-1. Run `sudo gitlab-ctl reconfigure`.
-1. On `app1` apply the following changes to `/etc/gitlab/gitlab.rb`:
+1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
- ```shell
+1. On the **GitLab server**, make the following changes to `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
gitlab_pages['enable'] = false
- pages_external_url "http://<your-pages-domain>"
+ pages_external_url "http://<your-pages-server-URL>"
gitlab_rails['pages_path'] = "/mnt/pages"
```
-1. Run `sudo gitlab-ctl reconfigure`.
+1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
+
+It is possible to run GitLab Pages on multiple servers if you wish to distribute
+the load. You can do this through standard load balancing practices such as
+configuring your DNS server to return multiple IPs for your Pages server,
+configuring a load balancer to work at the IP level, and so on. If you wish to
+set up GitLab Pages on multiple servers, perform the above procedure for each
+Pages server.
+
+### Access control when running GitLab Pages on a separate server
+
+If you are [running GitLab Pages on a separate server](#running-gitlab-pages-on-a-separate-server),
+then you must use the following procedure to configure [access control](#access-control):
+
+1. On the **GitLab server**, add the following to `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ gitlab_pages['enable'] = true
+ gitlab_pages['access_control'] = true
+ ```
+
+1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the
+ changes to take effect. The `gitlab-secrets.json` file is now updated with the
+ new configuration.
+
+ DANGER: **Danger:**
+ The `gitlab-secrets.json` file contains secrets that control database encryption.
+ Do not edit or replace this file on the **GitLab server** or you might
+ experience permanent data loss. Make a backup copy of this file before proceeding,
+ as explained in the following steps.
+
+1. Create a backup of the secrets file on the **GitLab server**:
+
+ ```shell
+ cp /etc/gitlab/gitlab-secrets.json /etc/gitlab/gitlab-secrets.json.bak
+ ```
+
+1. Create a backup of the secrets file on the **Pages server**:
+
+ ```shell
+ cp /etc/gitlab/gitlab-secrets.json /etc/gitlab/gitlab-secrets.json.bak
+ ```
+
+1. Disable Pages on the **GitLab server** by setting the following in
+ `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ gitlab_pages['enable'] = false
+ ```
+
+1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
+
+1. Copy the `/etc/gitlab/gitlab-secrets.json` file from the **GitLab server**
+ to the **Pages server**.
+
+1. On your **Pages server**, add the following to `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ gitlab_pages['gitlab_server'] = "https://<your-gitlab-server-URL>"
+ ```
+
+1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
## Backup
-Pages are part of the [regular backup][backup] so there is nothing to configure.
+GitLab Pages are part of the [regular backup][backup], so there is no separate backup to configure.
## Security
diff --git a/doc/administration/repository_storage_paths.md b/doc/administration/repository_storage_paths.md
index 7d3e36e9796..86998280b93 100644
--- a/doc/administration/repository_storage_paths.md
+++ b/doc/administration/repository_storage_paths.md
@@ -2,8 +2,8 @@
> [Introduced][ce-4578] in GitLab 8.10.
-GitLab allows you to define multiple repository storage paths to distribute the
-storage load between several mount points.
+GitLab allows you to define multiple repository storage paths (sometimes called
+storage shards) to distribute the storage load between several mount points.
> **Notes:**
>
diff --git a/doc/administration/repository_storage_types.md b/doc/administration/repository_storage_types.md
index 227d6928baf..9c7b5bc6b87 100644
--- a/doc/administration/repository_storage_types.md
+++ b/doc/administration/repository_storage_types.md
@@ -5,8 +5,8 @@
Two different storage layouts can be used
to store the repositories on disk and their characteristics.
-GitLab can be configured to use one or multiple repository shard locations
-that can be:
+GitLab can be configured to use one or multiple repository storage paths/shard
+locations that can be:
- Mounted to the local disk
- Exposed as an NFS shared volume
@@ -34,8 +34,8 @@ easy for Administrators to find where the repository is stored.
On the other hand this has some drawbacks:
Storage location will concentrate huge amount of top-level namespaces. The
-impact can be reduced by the introduction of [multiple storage
-paths][storage-paths].
+impact can be reduced by the introduction of
+[multiple storage paths](repository_storage_paths.md).
Because backups are a snapshot of the same URL mapping, if you try to recover a
very old backup, you need to verify whether any project has taken the place of
@@ -183,7 +183,8 @@ CI Artifacts are S3 compatible since **9.4** (GitLab Premium), and available in
##### LFS Objects
-LFS Objects implements a similar storage pattern using 2 chars, 2 level folders, following Git own implementation:
+[LFS Objects in GitLab](lfs/manage_large_binaries_with_git_lfs.md) implement a similar
+storage pattern using 2 chars, 2 level folders, following Git's own implementation:
```ruby
"shared/lfs-objects/#{oid[0..1}/#{oid[2..3]}/#{oid[4..-1]}"
@@ -192,10 +193,9 @@ LFS Objects implements a similar storage pattern using 2 chars, 2 level folders,
"shared/lfs-objects/89/09/029eb962194cfb326259411b22ae3f4a814b5be4f80651735aeef9f3229c"
```
-They are also S3 compatible since **10.0** (GitLab Premium), and available in GitLab Core since **10.7**.
+LFS objects are also [S3 compatible](lfs/lfs_administration.md#storing-lfs-objects-in-remote-object-storage).
[ce-2821]: https://gitlab.com/gitlab-com/infrastructure/issues/2821
[ce-28283]: https://gitlab.com/gitlab-org/gitlab-foss/issues/28283
[rake/migrate-to-hashed]: raketasks/storage.md#migrate-existing-projects-to-hashed-storage
-[storage-paths]: repository_storage_types.md
[gitaly]: gitaly/index.md
diff --git a/doc/administration/timezone.md b/doc/administration/timezone.md
new file mode 100644
index 00000000000..3594ba19181
--- /dev/null
+++ b/doc/administration/timezone.md
@@ -0,0 +1,37 @@
+# Changing your time zone
+
+The global time zone configuration parameter can be changed in `config/gitlab.yml`:
+
+```text
+# time_zone: 'UTC'
+```
+
+Uncomment and customize if you want to change the default time zone of the GitLab application.
+
+## Viewing available timezones
+
+To see all available time zones, run `bundle exec rake time:zones:all`.
+
+For Omnibus installations, run `gitlab-rake time:zones:all`.
+
+NOTE: **Note:**
+Currently, this rake task does not list timezones in TZInfo format required by GitLab Omnibus during a reconfigure: [#58672](https://gitlab.com/gitlab-org/gitlab-foss/issues/58672).
+
+## Changing time zone in Omnibus installations
+
+GitLab defaults its time zone to UTC. It has a global timezone configuration parameter in `/etc/gitlab/gitlab.rb`.
+
+To obtain a list of timezones, log in to your GitLab application server and run a command that generates a list of timezones in TZInfo format for the server. For example, install `timedatectl` and run `timedatectl list-timezones`.
+
+To update, add the timezone that best applies to your location. For example:
+
+```ruby
+gitlab_rails['time_zone'] = 'America/New_York'
+```
+
+After adding the configuration parameter, reconfigure and restart your GitLab instance:
+
+```sh
+gitlab-ctl reconfigure
+gitlab-ctl restart
+```
diff --git a/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
index 34a5acbe7b7..dd220d0871d 100644
--- a/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
+++ b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
@@ -442,7 +442,7 @@ personal_access_token = User.find(123).personal_access_tokens.create(
scopes: [:api]
)
-personal_access_token.token
+puts personal_access_token.token
```
You might also want to manually set the token string:
@@ -715,7 +715,7 @@ For more information, see the [confidential issue](../../user/project/issues/con
```ruby
Ci::Pipeline.where(project_id: p.id).where(status: 'pending').count
-Ci::Pipeline.where(project_id: p.id).where(status: 'pending').each {|p| p.cancel}
+Ci::Pipeline.where(project_id: p.id).where(status: 'pending').each {|p| p.cancel if p.stuck?}
Ci::Pipeline.where(project_id: p.id).where(status: 'pending').count
```
diff --git a/doc/administration/uploads.md b/doc/administration/uploads.md
index 04cebe568f3..bccfe7c542f 100644
--- a/doc/administration/uploads.md
+++ b/doc/administration/uploads.md
@@ -63,8 +63,8 @@ For source installations the following settings are nested under `uploads:` and
|---------|-------------|---------|
| `enabled` | Enable/disable object storage | `false` |
| `remote_directory` | The bucket name where Uploads will be stored| |
-| `direct_upload` | Set to true to enable direct upload of Uploads without the need of local shared storage. Option may be removed once we decide to support only single storage for all files. | `false` |
-| `background_upload` | Set to false to disable automatic upload. Option may be removed once upload is direct to S3 | `true` |
+| `direct_upload` | Set to true to remove Unicorn from the Upload path. Workhorse handles the actual Artifact Upload to Object Storage while Unicorn does minimal processing to keep track of the upload. There is no need for local shared storage. The option may be removed if support for a single storage type for all files is introduced. Read more on [what the direct_upload setting means](https://docs.gitlab.com/ee/development/uploads.html#what-does-the-direct_upload-setting-mean). | `false` |
+| `background_upload` | Set to false to disable automatic upload. Option may be removed once upload is direct to S3 (if `direct_upload` is set to `true` it will override `background_upload`) | `true` |
| `proxy_download` | Set to true to enable proxying all files served. Option allows to reduce egress traffic as this allows clients to download directly from remote storage instead of proxying all data | `false` |
| `connection` | Various connection options described below | |
diff --git a/doc/api/api_resources.md b/doc/api/api_resources.md
index 232a9825691..c2713f54c47 100644
--- a/doc/api/api_resources.md
+++ b/doc/api/api_resources.md
@@ -24,7 +24,7 @@ The following API resources are available in the project context:
| [Commits](commits.md) | `/projects/:id/repository/commits`, `/projects/:id/statuses` |
| [Container Registry](container_registry.md) | `/projects/:id/registry/repositories` |
| [Custom attributes](custom_attributes.md) | `/projects/:id/custom_attributes` (also available for groups and users) |
-| [Dependencies](dependencies.md) **(ULTIMATE)** | `/projects/:id/dependencies`
+| [Dependencies](dependencies.md) **(ULTIMATE)** | `/projects/:id/dependencies` |
| [Deploy keys](deploy_keys.md) | `/projects/:id/deploy_keys` (also available standalone) |
| [Deployments](deployments.md) | `/projects/:id/deployments` |
| [Discussions](discussions.md) (threaded comments) | `/projects/:id/issues/.../discussions`, `/projects/:id/snippets/.../discussions`, `/projects/:id/merge_requests/.../discussions`, `/projects/:id/commits/.../discussions` (also available for groups) |
@@ -67,7 +67,9 @@ The following API resources are available in the project context:
| [Search](search.md) | `/projects/:id/search` (also available for groups and standalone) |
| [Services](services.md) | `/projects/:id/services` |
| [Tags](tags.md) | `/projects/:id/repository/tags` |
-| [Vulnerabilities](vulnerabilities.md) **(ULTIMATE)** | `/projects/:id/vulnerabilities`
+| [Visual Review discussions](visual_review_discussions.md) **(STARTER**) | `/projects/:id/merge_requests/:merge_request_id/visual_review_discussions` |
+| [Vulnerabilities](vulnerabilities.md) **(ULTIMATE)** | `/projects/:id/vulnerabilities` |
+| [Vulnerability Findings](vulnerability_findings.md) **(ULTIMATE)** | `/projects/:id/vulnerability_findings` |
| [Wikis](wikis.md) | `/projects/:id/wikis` |
## Group resources
diff --git a/doc/api/audit_events.md b/doc/api/audit_events.md
index aca221cf990..e451b975d42 100644
--- a/doc/api/audit_events.md
+++ b/doc/api/audit_events.md
@@ -1,10 +1,12 @@
-# Audit Events API **(PREMIUM ONLY)**
+# Audit Events API
+
+## Instance Audit Events **(PREMIUM ONLY)**
The Audit Events API allows you to retrieve [instance audit events](../administration/audit_events.md#instance-events-premium-only).
To retrieve audit events using the API, you must [authenticate yourself](README.html#authentication) as an Administrator.
-## Retrieve all instance audit events
+### Retrieve all instance audit events
```
GET /audit_events
@@ -15,7 +17,7 @@ GET /audit_events
| `created_after` | string | no | Return audit events created on or after the given time. Format: ISO 8601 YYYY-MM-DDTHH:MM:SSZ |
| `created_before` | string | no | Return audit events created on or before the given time. Format: ISO 8601 YYYY-MM-DDTHH:MM:SSZ |
| `entity_type` | string | no | Return audit events for the given entity type. Valid values are: `User`, `Group`, or `Project`. |
-| `entity_id` | boolean | no | Return audit events for the given entity ID. Requires `entity_type` attribute to be present. |
+| `entity_id` | integer | no | Return audit events for the given entity ID. Requires `entity_type` attribute to be present. |
By default, `GET` requests return 20 results at a time because the API results
are paginated.
@@ -83,7 +85,7 @@ Example response:
]
```
-## Retrieve single instance audit event
+### Retrieve single instance audit event
```
GET /audit_events/:id
@@ -113,3 +115,109 @@ Example response:
"created_at": "2019-08-30T07:00:41.885Z"
}
```
+
+## Group Audit Events **(STARTER)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/34078) in GitLab 12.5.
+
+The Group Audit Events API allows you to retrieve [group audit events](../administration/audit_events.html#group-events-starter).
+
+To retrieve group audit events using the API, you must [authenticate yourself](README.html#authentication) as an Administrator or an owner of the group.
+
+### Retrieve all group audit events
+
+```
+GET /groups/:id/audit_events
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) |
+| `created_after` | string | no | Return group audit events created on or after the given time. Format: ISO 8601 YYYY-MM-DDTHH:MM:SSZ |
+| `created_before` | string | no | Return group audit events created on or before the given time. Format: ISO 8601 YYYY-MM-DDTHH:MM:SSZ |
+
+By default, `GET` requests return 20 results at a time because the API results
+are paginated.
+
+Read more on [pagination](README.md#pagination).
+
+```bash
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://primary.example.com/api/v4/groups/60/audit_events
+```
+
+Example response:
+
+```json
+[
+ {
+ "id": 2,
+ "author_id": 1,
+ "entity_id": 60,
+ "entity_type": "Group",
+ "details": {
+ "custom_message": "Group marked for deletion",
+ "author_name": "Administrator",
+ "target_id": "flightjs",
+ "target_type": "Group",
+ "target_details": "flightjs",
+ "ip_address": "127.0.0.1",
+ "entity_path": "flightjs"
+ },
+ "created_at": "2019-08-28T19:36:44.162Z"
+ },
+ {
+ "id": 1,
+ "author_id": 1,
+ "entity_id": 60,
+ "entity_type": "Group",
+ "details": {
+ "add": "group",
+ "author_name": "Administrator",
+ "target_id": "flightjs",
+ "target_type": "Group",
+ "target_details": "flightjs",
+ "ip_address": "127.0.0.1",
+ "entity_path": "flightjs"
+ },
+ "created_at": "2019-08-27T18:36:44.162Z"
+ }
+]
+```
+
+### Retrieve a specific group audit event
+
+Only available to group owners and administrators.
+
+```
+GET /groups/:id/audit_events/:audit_event_id
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) |
+| `audit_event_id` | integer | yes | ID of the audit event |
+
+```bash
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://primary.example.com/api/v4/groups/60/audit_events/2
+```
+
+Example response:
+
+```json
+{
+ "id": 2,
+ "author_id": 1,
+ "entity_id": 60,
+ "entity_type": "Group",
+ "details": {
+ "custom_message": "Group marked for deletion",
+ "author_name": "Administrator",
+ "target_id": "flightjs",
+ "target_type": "Group",
+ "target_details": "flightjs",
+ "ip_address": "127.0.0.1",
+ "entity_path": "flightjs"
+ },
+ "created_at": "2019-08-28T19:36:44.162Z"
+}
+```
diff --git a/doc/api/branches.md b/doc/api/branches.md
index 31c8add300d..bba8876163e 100644
--- a/doc/api/branches.md
+++ b/doc/api/branches.md
@@ -21,7 +21,7 @@ Parameters:
| Attribute | Type | Required | Description |
|:----------|:---------------|:---------|:------------|
| `id` | integer/string | yes | ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user.|
-| `search` | string | no | Return list of branches containing the search string. You can use `^term` and `term$` to find branches that begin and end with `term` respectively.|
+| `search` | string | no | Return list of branches containing the search string. You can use `^term` and `term$` to find branches that begin and end with `term` respectively. |
Example request:
diff --git a/doc/api/commits.md b/doc/api/commits.md
index 3927a4bbc62..f4bb09843c8 100644
--- a/doc/api/commits.md
+++ b/doc/api/commits.md
@@ -317,6 +317,21 @@ Example response:
}
```
+In the event of a failed cherry-pick, the response will provide context about
+why:
+
+```json
+{
+ "message": "Sorry, we cannot cherry-pick this commit automatically. This commit may already have been cherry-picked, or a more recent commit may have updated some of its content.",
+ "error_code": "empty"
+}
+```
+
+In this case, the cherry-pick failed because the changeset was empty and likely
+indicates that the commit already exists in the target branch. The other
+possible error code is `conflict`, which indicates that there was a merge
+conflict.
+
## Revert a commit
> [Introduced][ce-22919] in GitLab 11.5.
@@ -358,6 +373,19 @@ Example response:
}
```
+In the event of a failed revert, the response will provide context about why:
+
+```json
+{
+ "message": "Sorry, we cannot revert this commit automatically. This commit may already have been reverted, or a more recent commit may have updated some of its content.",
+ "error_code": "conflict"
+}
+```
+
+In this case, the revert failed because the attempted revert generated a merge
+conflict. The other possible error code is `empty`, which indicates that the
+changeset was empty, likely due to the change having already been reverted.
+
## Get the diff of a commit
Get the diff of a commit in a project.
@@ -670,6 +698,7 @@ Example response:
"merge_status":"can_be_merged",
"sha":"af5b13261899fb2c0db30abdd0af8b07cb44fdc5",
"merge_commit_sha":null,
+ "squash_commit_sha":null,
"user_notes_count":0,
"discussion_locked":null,
"should_remove_source_branch":null,
diff --git a/doc/api/deployments.md b/doc/api/deployments.md
index 27254c42e3a..6fc6599a47d 100644
--- a/doc/api/deployments.md
+++ b/doc/api/deployments.md
@@ -11,7 +11,7 @@ GET /projects/:id/deployments
| Attribute | Type | Required | Description |
|-----------|---------|----------|---------------------|
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
-| `order_by`| string | no | Return deployments ordered by `id` or `iid` or `created_at` or `ref` fields. Default is `id` |
+| `order_by`| string | no | Return deployments ordered by `id` or `iid` or `created_at` or `updated_at` or `ref` fields. Default is `id` |
| `sort` | string | no | Return deployments sorted in `asc` or `desc` order. Default is `asc` |
```bash
@@ -62,6 +62,15 @@ Example of response
"twitter": "",
"website_url": "",
"organization": ""
+ },
+ "pipeline": {
+ "created_at": "2016-08-11T02:12:10.222Z",
+ "id": 36,
+ "ref": "master",
+ "sha": "99d03678b90d914dbb1b109132516d71a4a03ea8",
+ "status": "success",
+ "updated_at": "2016-08-11T02:12:10.222Z",
+ "web_url": "http://gitlab.dev/root/project/pipelines/12"
}
},
"environment": {
@@ -122,6 +131,15 @@ Example of response
"twitter": "",
"website_url": "",
"organization": ""
+ },
+ "pipeline": {
+ "created_at": "2016-08-11T07:43:52.143Z",
+ "id": 37,
+ "ref": "master",
+ "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
+ "status": "success",
+ "updated_at": "2016-08-11T07:43:52.143Z",
+ "web_url": "http://gitlab.dev/root/project/pipelines/13"
}
},
"environment": {
@@ -219,6 +237,15 @@ Example of response
"created_at": "2016-08-11T13:28:26.000+02:00",
"message": "Merge branch 'rename-readme' into 'master'\r\n\r\nRename README\r\n\r\n\r\n\r\nSee merge request !2"
},
+ "pipeline": {
+ "created_at": "2016-08-11T07:43:52.143Z",
+ "id": 42,
+ "ref": "master",
+ "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
+ "status": "success",
+ "updated_at": "2016-08-11T07:43:52.143Z",
+ "web_url": "http://gitlab.dev/root/project/pipelines/5"
+ }
"runner": null
}
}
diff --git a/doc/api/epic_links.md b/doc/api/epic_links.md
index 665c902355f..e81dc88da81 100644
--- a/doc/api/epic_links.md
+++ b/doc/api/epic_links.md
@@ -50,12 +50,14 @@ Example response:
"start_date": null,
"start_date_is_fixed": false,
"start_date_fixed": null,
- "start_date_from_milestones": null,
- "end_date": "2018-07-31",
+ "start_date_from_milestones": null, //deprecated in favor of start_date_from_inherited_source
+ "start_date_from_inherited_source": null,
+ "end_date": "2018-07-31", //deprecated in favor of due_date
"due_date": "2018-07-31",
"due_date_is_fixed": false,
"due_date_fixed": null,
- "due_date_from_milestones": "2018-07-31",
+ "due_date_from_milestones": "2018-07-31", //deprecated in favor of start_date_from_inherited_source
+ "due_date_from_inherited_source": "2018-07-31",
"created_at": "2018-07-17T13:36:22.770Z",
"updated_at": "2018-07-18T12:22:05.239Z",
"labels": []
@@ -102,12 +104,14 @@ Example response:
"start_date": null,
"start_date_is_fixed": false,
"start_date_fixed": null,
- "start_date_from_milestones": null,
- "end_date": "2018-07-31",
+ "start_date_from_milestones": null, //deprecated in favor of start_date_from_inherited_source
+ "start_date_from_inherited_source": null,
+ "end_date": "2018-07-31", //deprecated in favor of due_date
"due_date": "2018-07-31",
"due_date_is_fixed": false,
"due_date_fixed": null,
- "due_date_from_milestones": "2018-07-31",
+ "due_date_from_milestones": "2018-07-31", //deprecated in favor of start_date_from_inherited_source
+ "due_date_from_inherited_source": "2018-07-31",
"created_at": "2018-07-17T13:36:22.770Z",
"updated_at": "2018-07-18T12:22:05.239Z",
"labels": []
@@ -189,12 +193,14 @@ Example response:
"start_date": null,
"start_date_is_fixed": false,
"start_date_fixed": null,
- "start_date_from_milestones": null,
- "end_date": "2018-07-31",
+ "start_date_from_milestones": null, //deprecated in favor of start_date_from_inherited_source
+ "start_date_from_inherited_source": null,
+ "end_date": "2018-07-31", //deprecated in favor of due_date
"due_date": "2018-07-31",
"due_date_is_fixed": false,
"due_date_fixed": null,
- "due_date_from_milestones": "2018-07-31",
+ "due_date_from_milestones": "2018-07-31", //deprecated in favor of start_date_from_inherited_source
+ "due_date_from_inherited_source": "2018-07-31",
"created_at": "2018-07-17T13:36:22.770Z",
"updated_at": "2018-07-18T12:22:05.239Z",
"labels": []
@@ -241,12 +247,14 @@ Example response:
"start_date": null,
"start_date_is_fixed": false,
"start_date_fixed": null,
- "start_date_from_milestones": null,
- "end_date": "2018-07-31",
+ "start_date_from_milestones": null, //deprecated in favor of start_date_from_inherited_source
+ "start_date_from_inherited_source": null,
+ "end_date": "2018-07-31", //deprecated in favor of due_date
"due_date": "2018-07-31",
"due_date_is_fixed": false,
"due_date_fixed": null,
- "due_date_from_milestones": "2018-07-31",
+ "due_date_from_milestones": "2018-07-31", //deprecated in favor of start_date_from_inherited_source
+ "due_date_from_inherited_source": "2018-07-31",
"created_at": "2018-07-17T13:36:22.770Z",
"updated_at": "2018-07-18T12:22:05.239Z",
"labels": []
diff --git a/doc/api/epics.md b/doc/api/epics.md
index c7a050f1465..531c75fd8c5 100644
--- a/doc/api/epics.md
+++ b/doc/api/epics.md
@@ -14,9 +14,13 @@ The [epic issues API](epic_issues.md) allows you to interact with issues associa
> [Introduced][ee-6448] in GitLab 11.3.
-Since start date and due date can be dynamically sourced from related issue milestones, when user has edit permission, additional fields will be shown. These include two boolean fields `start_date_is_fixed` and `due_date_is_fixed`, and four date fields `start_date_fixed`, `start_date_from_milestones`, `due_date_fixed` and `due_date_from_milestones`.
+Since start date and due date can be dynamically sourced from related issue milestones, when user has edit permission,
+additional fields will be shown. These include two boolean fields `start_date_is_fixed` and `due_date_is_fixed`,
+and four date fields `start_date_fixed`, `start_date_from_inherited_source`, `due_date_fixed` and `due_date_from_inherited_source`.
-`end_date` has been deprecated in favor of `due_date`.
+- `end_date` has been deprecated in favor of `due_date`.
+- `start_date_from_milestones` has been deprecated in favor of `start_date_from_inherited_source`
+- `due_date_from_milestones` has been deprecated in favor of `due_date_from_inherited_source`
## Epics pagination
@@ -80,12 +84,14 @@ Example response:
"start_date": null,
"start_date_is_fixed": false,
"start_date_fixed": null,
- "start_date_from_milestones": null,
- "end_date": "2018-07-31",
+ "start_date_from_milestones": null, //deprecated in favor of start_date_from_inherited_source
+ "start_date_from_inherited_source": null,
+ "end_date": "2018-07-31", //deprecated in favor of due_date
"due_date": "2018-07-31",
"due_date_is_fixed": false,
"due_date_fixed": null,
- "due_date_from_milestones": "2018-07-31",
+ "due_date_from_milestones": "2018-07-31", //deprecated in favor of start_date_from_inherited_source
+ "due_date_from_inherited_source": "2018-07-31",
"created_at": "2018-07-17T13:36:22.770Z",
"updated_at": "2018-07-18T12:22:05.239Z",
"closed_at": "2018-08-18T12:22:05.239Z",
@@ -136,12 +142,14 @@ Example response:
"start_date": null,
"start_date_is_fixed": false,
"start_date_fixed": null,
- "start_date_from_milestones": null,
- "end_date": "2018-07-31",
+ "start_date_from_milestones": null, //deprecated in favor of start_date_from_inherited_source
+ "start_date_from_inherited_source": null,
+ "end_date": "2018-07-31", //deprecated in favor of due_date
"due_date": "2018-07-31",
"due_date_is_fixed": false,
"due_date_fixed": null,
- "due_date_from_milestones": "2018-07-31",
+ "due_date_from_milestones": "2018-07-31", //deprecated in favor of start_date_from_inherited_source
+ "due_date_from_inherited_source": "2018-07-31",
"created_at": "2018-07-17T13:36:22.770Z",
"updated_at": "2018-07-18T12:22:05.239Z",
"closed_at": "2018-08-18T12:22:05.239Z",
@@ -204,12 +212,14 @@ Example response:
"start_date": null,
"start_date_is_fixed": false,
"start_date_fixed": null,
- "start_date_from_milestones": null,
- "end_date": "2018-07-31",
+ "start_date_from_milestones": null, //deprecated in favor of start_date_from_inherited_source
+ "start_date_from_inherited_source": null,
+ "end_date": "2018-07-31", //deprecated in favor of due_date
"due_date": "2018-07-31",
"due_date_is_fixed": false,
"due_date_fixed": null,
- "due_date_from_milestones": "2018-07-31",
+ "due_date_from_milestones": "2018-07-31", //deprecated in favor of start_date_from_inherited_source
+ "due_date_from_inherited_source": "2018-07-31",
"created_at": "2018-07-17T13:36:22.770Z",
"updated_at": "2018-07-18T12:22:05.239Z",
"closed_at": "2018-08-18T12:22:05.239Z",
@@ -272,12 +282,14 @@ Example response:
"start_date": null,
"start_date_is_fixed": false,
"start_date_fixed": null,
- "start_date_from_milestones": null,
- "end_date": "2018-07-31",
+ "start_date_from_milestones": null, //deprecated in favor of start_date_from_inherited_source
+ "start_date_from_inherited_source": null,
+ "end_date": "2018-07-31", //deprecated in favor of due_date
"due_date": "2018-07-31",
"due_date_is_fixed": false,
"due_date_fixed": null,
- "due_date_from_milestones": "2018-07-31",
+ "due_date_from_milestones": "2018-07-31", //deprecated in favor of start_date_from_inherited_source
+ "due_date_from_inherited_source": "2018-07-31",
"created_at": "2018-07-17T13:36:22.770Z",
"updated_at": "2018-07-18T12:22:05.239Z",
"closed_at": "2018-08-18T12:22:05.239Z",
diff --git a/doc/api/feature_flag_specs.md b/doc/api/feature_flag_specs.md
new file mode 100644
index 00000000000..6a2cd047f85
--- /dev/null
+++ b/doc/api/feature_flag_specs.md
@@ -0,0 +1,291 @@
+# Feature Flag Specs API **(PREMIUM)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/9566) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.5.
+
+The API for creating, updating, reading and deleting [Feature Flag Specs](../user/project/operations/feature_flags.md#define-environment-specs).
+Automation engineers benefit from this API by being able to modify Feature Flag Specs without accessing user interface.
+To manage the [Feature Flag](../user/project/operations/feature_flags.md) resources via public API, please refer to the [Feature Flags API](feature_flags.md) document.
+
+Users with Developer or higher [permissions](../user/permissions.md) can access Feature Flag Specs API.
+
+## List all effective feature flag specs under the specified environment
+
+Get all effective feature flag specs under the specified [environment](../ci/environments.md).
+
+For instance, there are two specs, `staging` and `production`, for a feature flag.
+When you pass `production` as a parameter to this endpoint, the system returns
+the `production` feature flag spec only.
+
+```
+GET /projects/:id/feature_flag_scopes
+```
+
+| Attribute | Type | Required | Description |
+| ------------------- | ---------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding). |
+| `environment` | string | yes | The [environment](../ci/environments.md) name |
+
+```bash
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/feature_flag_scopes?environment=production
+```
+
+Example response:
+
+```json
+[
+ {
+ "id": 88,
+ "active": true,
+ "environment_scope": "production",
+ "strategies": [
+ {
+ "name": "userWithId",
+ "parameters": {
+ "userIds": "1,2,3"
+ }
+ }
+ ],
+ "created_at": "2019-11-04T08:36:41.327Z",
+ "updated_at": "2019-11-04T08:36:41.327Z",
+ "name": "awesome_feature"
+ },
+ {
+ "id": 82,
+ "active": true,
+ "environment_scope": "*",
+ "strategies": [
+ {
+ "name": "default",
+ "parameters": {}
+ }
+ ],
+ "created_at": "2019-11-04T08:13:51.425Z",
+ "updated_at": "2019-11-04T08:39:45.751Z",
+ "name": "merge_train"
+ },
+ {
+ "id": 81,
+ "active": false,
+ "environment_scope": "production",
+ "strategies": [
+ {
+ "name": "default",
+ "parameters": {}
+ }
+ ],
+ "created_at": "2019-11-04T08:13:10.527Z",
+ "updated_at": "2019-11-04T08:13:10.527Z",
+ "name": "new_live_trace"
+ }
+]
+```
+
+## List all specs of a feature flag
+
+Get all specs of a feature flag.
+
+```
+GET /projects/:id/feature_flags/:name/scopes
+```
+
+| Attribute | Type | Required | Description |
+| ------------------- | ---------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding). |
+| `name` | string | yes | The name of the feature flag. |
+
+```bash
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/feature_flags/new_live_trace/scopes
+```
+
+Example response:
+
+```json
+[
+ {
+ "id": 79,
+ "active": false,
+ "environment_scope": "*",
+ "strategies": [
+ {
+ "name": "default",
+ "parameters": {}
+ }
+ ],
+ "created_at": "2019-11-04T08:13:10.516Z",
+ "updated_at": "2019-11-04T08:13:10.516Z"
+ },
+ {
+ "id": 80,
+ "active": true,
+ "environment_scope": "staging",
+ "strategies": [
+ {
+ "name": "default",
+ "parameters": {}
+ }
+ ],
+ "created_at": "2019-11-04T08:13:10.525Z",
+ "updated_at": "2019-11-04T08:13:10.525Z"
+ },
+ {
+ "id": 81,
+ "active": false,
+ "environment_scope": "production",
+ "strategies": [
+ {
+ "name": "default",
+ "parameters": {}
+ }
+ ],
+ "created_at": "2019-11-04T08:13:10.527Z",
+ "updated_at": "2019-11-04T08:13:10.527Z"
+ }
+]
+```
+
+## New feature flag spec
+
+Creates a new feature flag spec.
+
+```
+POST /projects/:id/feature_flags/:name/scopes
+```
+
+| Attribute | Type | Required | Description |
+| ------------------- | ---------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding). |
+| `name` | string | yes | The name of the feature flag. |
+| `environment_scope` | string | yes | The [environment spec](../ci/environments.md#scoping-environments-with-specs) of the feature flag. |
+| `active` | boolean | yes | Whether the spec is active. |
+| `strategies` | json | yes | The [strategies](../user/project/operations/feature_flags.md#feature-flag-strategies) of the feature flag spec. |
+
+```bash
+curl https://gitlab.example.com/api/v4/projects/1/feature_flags/new_live_trace/scopes \
+ --header "PRIVATE-TOKEN: <your_access_token>" \
+ --header "Content-type: application/json" \
+ --data @- << EOF
+{
+ "environment_scope": "*",
+ "active": false,
+ "strategies": [{ "name": "default", "parameters": {} }]
+}
+EOF
+```
+
+Example response:
+
+```json
+{
+ "id": 81,
+ "active": false,
+ "environment_scope": "*",
+ "strategies": [
+ {
+ "name": "default",
+ "parameters": {}
+ }
+ ],
+ "created_at": "2019-11-04T08:13:10.527Z",
+ "updated_at": "2019-11-04T08:13:10.527Z"
+}
+```
+
+## Single feature flag spec
+
+Gets a single feature flag spec.
+
+```
+GET /projects/:id/feature_flags/:name/scopes/:environment_scope
+```
+
+| Attribute | Type | Required | Description |
+| ------------------- | ---------------- | ---------- | ---------------------------------------------------------------------------------------|
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding). |
+| `name` | string | yes | The name of the feature flag. |
+| `environment_scope` | string | yes | The URL-encoded [environment spec](../ci/environments.md#scoping-environments-with-specs) of the feature flag. |
+
+```bash
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/:id/feature_flags/new_live_trace/scopes/production
+```
+
+Example response:
+
+```json
+{
+ "id": 81,
+ "active": false,
+ "environment_scope": "production",
+ "strategies": [
+ {
+ "name": "default",
+ "parameters": {}
+ }
+ ],
+ "created_at": "2019-11-04T08:13:10.527Z",
+ "updated_at": "2019-11-04T08:13:10.527Z"
+}
+```
+
+## Edit feature flag spec
+
+Updates an existing feature flag spec.
+
+```
+PUT /projects/:id/feature_flags/:name/scopes/:environment_scope
+```
+
+| Attribute | Type | Required | Description |
+| ------------------- | ---------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding). |
+| `name` | string | yes | The name of the feature flag. |
+| `environment_scope` | string | yes | The URL-encoded [environment spec](../ci/environments.md#scoping-environments-with-specs) of the feature flag. |
+| `active` | boolean | yes | Whether the spec is active. |
+| `strategies` | json | yes | The [strategies](../user/project/operations/feature_flags.md#feature-flag-strategies) of the feature flag spec. |
+
+```bash
+curl https://gitlab.example.com/api/v4/projects/1/feature_flags/new_live_trace/scopes/production \
+ --header "PRIVATE-TOKEN: <your_access_token>" \
+ --header "Content-type: application/json" \
+ --data @- << EOF
+{
+ "active": true,
+ "strategies": [{ "name": "userWithId", "parameters": { "userIds": "1,2,3" } }]
+}
+EOF
+```
+
+Example response:
+
+```json
+{
+ "id": 81,
+ "active": true,
+ "environment_scope": "production",
+ "strategies": [
+ {
+ "name": "userWithId",
+ "parameters": { "userIds": "1,2,3" }
+ }
+ ],
+ "created_at": "2019-11-04T08:13:10.527Z",
+ "updated_at": "2019-11-04T08:13:10.527Z"
+}
+```
+
+## Delete feature flag spec
+
+Deletes a feature flag spec.
+
+```
+DELETE /projects/:id/feature_flags/:name/scopes/:environment_scope
+```
+
+| Attribute | Type | Required | Description |
+| ------------------- | ---------------- | ---------- | ---------------------------------------------------------------------------------------|
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding). |
+| `name` | string | yes | The name of the feature flag. |
+| `environment_scope` | string | yes | The URL-encoded [environment spec](../ci/environments.md#scoping-environments-with-specs) of the feature flag. |
+
+```bash
+curl --header "PRIVATE-TOKEN: <your_access_token>" --request DELETE https://gitlab.example.com/api/v4/projects/1/feature_flags/new_live_trace/scopes/production
+```
diff --git a/doc/api/feature_flags.md b/doc/api/feature_flags.md
new file mode 100644
index 00000000000..def452d36fb
--- /dev/null
+++ b/doc/api/feature_flags.md
@@ -0,0 +1,308 @@
+# Feature Flags API **(PREMIUM)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/9566) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.5.
+
+API for accessing resources of [GitLab Feature Flags](../user/project/operations/feature_flags.md).
+
+Users with Developer or higher [permissions](../user/permissions.md) can access Feature Flag API.
+
+## Feature Flags pagination
+
+By default, `GET` requests return 20 results at a time because the API results
+are [paginated](README.md#pagination).
+
+## List feature flags for a project
+
+Gets all feature flags of the requested project.
+
+```
+GET /projects/:id/feature_flags
+```
+
+| Attribute | Type | Required | Description |
+| ------------------- | ---------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding). |
+| `scope` | string | no | The condition of feature flags, one of: `enabled`, `disabled`. |
+
+```bash
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/feature_flags
+```
+
+Example response:
+
+```json
+[
+ {
+ "name":"merge_train",
+ "description":"This feature is about merge train",
+ "created_at":"2019-11-04T08:13:51.423Z",
+ "updated_at":"2019-11-04T08:13:51.423Z",
+ "scopes":[
+ {
+ "id":82,
+ "active":false,
+ "environment_scope":"*",
+ "strategies":[
+ {
+ "name":"default",
+ "parameters":{
+
+ }
+ }
+ ],
+ "created_at":"2019-11-04T08:13:51.425Z",
+ "updated_at":"2019-11-04T08:13:51.425Z"
+ },
+ {
+ "id":83,
+ "active":true,
+ "environment_scope":"review/*",
+ "strategies":[
+ {
+ "name":"default",
+ "parameters":{
+
+ }
+ }
+ ],
+ "created_at":"2019-11-04T08:13:51.427Z",
+ "updated_at":"2019-11-04T08:13:51.427Z"
+ },
+ {
+ "id":84,
+ "active":false,
+ "environment_scope":"production",
+ "strategies":[
+ {
+ "name":"default",
+ "parameters":{
+
+ }
+ }
+ ],
+ "created_at":"2019-11-04T08:13:51.428Z",
+ "updated_at":"2019-11-04T08:13:51.428Z"
+ }
+ ]
+ },
+ {
+ "name":"new_live_trace",
+ "description":"This is a new live trace feature",
+ "created_at":"2019-11-04T08:13:10.507Z",
+ "updated_at":"2019-11-04T08:13:10.507Z",
+ "scopes":[
+ {
+ "id":79,
+ "active":false,
+ "environment_scope":"*",
+ "strategies":[
+ {
+ "name":"default",
+ "parameters":{
+
+ }
+ }
+ ],
+ "created_at":"2019-11-04T08:13:10.516Z",
+ "updated_at":"2019-11-04T08:13:10.516Z"
+ },
+ {
+ "id":80,
+ "active":true,
+ "environment_scope":"staging",
+ "strategies":[
+ {
+ "name":"default",
+ "parameters":{
+
+ }
+ }
+ ],
+ "created_at":"2019-11-04T08:13:10.525Z",
+ "updated_at":"2019-11-04T08:13:10.525Z"
+ },
+ {
+ "id":81,
+ "active":false,
+ "environment_scope":"production",
+ "strategies":[
+ {
+ "name":"default",
+ "parameters":{
+
+ }
+ }
+ ],
+ "created_at":"2019-11-04T08:13:10.527Z",
+ "updated_at":"2019-11-04T08:13:10.527Z"
+ }
+ ]
+ }
+]
+```
+
+## New feature flag
+
+Creates a new feature flag.
+
+```
+POST /projects/:id/feature_flags
+```
+
+| Attribute | Type | Required | Description |
+| ------------------- | ---------------- | ---------- | ---------------------------------------------------------------------------------------|
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding). |
+| `name` | string | yes | The name of the feature flag. |
+| `description` | string | no | The description of the feature flag. |
+| `scopes` | JSON | no | The [feature flag specs](../user/project/operations/feature_flags.md#define-environment-specs) of the feature flag. |
+| `scopes:environment_scope` | string | no | The [environment spec](../ci/environments.md#scoping-environments-with-specs). |
+| `scopes:active` | boolean | no | Whether the spec is active. |
+| `scopes:strategies` | JSON | no | The [strategies](../user/project/operations/feature_flags.md#feature-flag-strategies) of the feature flag spec. |
+
+```bash
+curl https://gitlab.example.com/api/v4/projects/1/feature_flags \
+ --header "PRIVATE-TOKEN: <your_access_token>" \
+ --header "Content-type: application/json" \
+ --data @- << EOF
+{
+ "name": "awesome_feature",
+ "scopes": [{ "environment_scope": "*", "active": false, "strategies": [{ "name": "default", "parameters": {} }] },
+ { "environment_scope": "production", "active": true, "strategies": [{ "name": "userWithId", "parameters": { "userIds": "1,2,3" } }] }]
+}
+EOF
+```
+
+Example response:
+
+```json
+{
+ "name":"awesome_feature",
+ "description":null,
+ "created_at":"2019-11-04T08:32:27.288Z",
+ "updated_at":"2019-11-04T08:32:27.288Z",
+ "scopes":[
+ {
+ "id":85,
+ "active":false,
+ "environment_scope":"*",
+ "strategies":[
+ {
+ "name":"default",
+ "parameters":{
+
+ }
+ }
+ ],
+ "created_at":"2019-11-04T08:32:29.324Z",
+ "updated_at":"2019-11-04T08:32:29.324Z"
+ },
+ {
+ "id":86,
+ "active":true,
+ "environment_scope":"production",
+ "strategies":[
+ {
+ "name":"userWithId",
+ "parameters":{
+ "userIds":"1,2,3"
+ }
+ }
+ ],
+ "created_at":"2019-11-04T08:32:29.328Z",
+ "updated_at":"2019-11-04T08:32:29.328Z"
+ }
+ ]
+}
+```
+
+## Single feature flag
+
+Gets a single feature flag.
+
+```
+GET /projects/:id/feature_flags/:name
+```
+
+| Attribute | Type | Required | Description |
+| ------------------- | ---------------- | ---------- | ---------------------------------------------------------------------------------------|
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding). |
+| `name` | string | yes | The name of the feature flag. |
+
+```bash
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/1/feature_flags/new_live_trace
+```
+
+Example response:
+
+```json
+{
+ "name":"new_live_trace",
+ "description":"This is a new live trace feature",
+ "created_at":"2019-11-04T08:13:10.507Z",
+ "updated_at":"2019-11-04T08:13:10.507Z",
+ "scopes":[
+ {
+ "id":79,
+ "active":false,
+ "environment_scope":"*",
+ "strategies":[
+ {
+ "name":"default",
+ "parameters":{
+
+ }
+ }
+ ],
+ "created_at":"2019-11-04T08:13:10.516Z",
+ "updated_at":"2019-11-04T08:13:10.516Z"
+ },
+ {
+ "id":80,
+ "active":true,
+ "environment_scope":"staging",
+ "strategies":[
+ {
+ "name":"default",
+ "parameters":{
+
+ }
+ }
+ ],
+ "created_at":"2019-11-04T08:13:10.525Z",
+ "updated_at":"2019-11-04T08:13:10.525Z"
+ },
+ {
+ "id":81,
+ "active":false,
+ "environment_scope":"production",
+ "strategies":[
+ {
+ "name":"default",
+ "parameters":{
+
+ }
+ }
+ ],
+ "created_at":"2019-11-04T08:13:10.527Z",
+ "updated_at":"2019-11-04T08:13:10.527Z"
+ }
+ ]
+}
+```
+
+## Delete feature flag
+
+Deletes a feature flag.
+
+```
+DELETE /projects/:id/feature_flags/:name
+```
+
+| Attribute | Type | Required | Description |
+| ------------------- | ---------------- | ---------- | ---------------------------------------------------------------------------------------|
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding). |
+| `name` | string | yes | The name of the feature flag. |
+
+```bash
+curl --header "PRIVATE-TOKEN: <your_access_token>" --request DELETE https://gitlab.example.com/api/v4/projects/1/feature_flags/awesome_feature
+```
diff --git a/doc/api/geo_nodes.md b/doc/api/geo_nodes.md
index 5eba7f038ed..e44d69f1419 100644
--- a/doc/api/geo_nodes.md
+++ b/doc/api/geo_nodes.md
@@ -237,6 +237,10 @@ Example response:
"container_repositories_synced_count": nil,
"container_repositories_failed_count": nil,
"container_repositories_synced_in_percentage": "0.00%",
+ "design_repositories_count": 3,
+ "design_repositories_synced_count": nil,
+ "design_repositories_failed_count": nil,
+ "design_repositories_synced_in_percentage": "0.00%",
"projects_count": 41,
"repositories_failed_count": nil,
"repositories_synced_count": nil,
@@ -304,6 +308,10 @@ Example response:
"container_repositories_synced_count": nil,
"container_repositories_failed_count": nil,
"container_repositories_synced_in_percentage": "0.00%",
+ "design_repositories_count": 3,
+ "design_repositories_synced_count": nil,
+ "design_repositories_failed_count": nil,
+ "design_repositories_synced_in_percentage": "0.00%",
"projects_count": 41,
"repositories_failed_count": 1,
"repositories_synced_count": 40,
@@ -387,6 +395,10 @@ Example response:
"container_repositories_synced_count": nil,
"container_repositories_failed_count": nil,
"container_repositories_synced_in_percentage": "0.00%",
+ "design_repositories_count": 3,
+ "design_repositories_synced_count": nil,
+ "design_repositories_failed_count": nil,
+ "design_repositories_synced_in_percentage": "0.00%",
"projects_count": 41,
"repositories_failed_count": 1,
"repositories_synced_count": 40,
diff --git a/doc/api/graphql/index.md b/doc/api/graphql/index.md
index 9eb254b4677..510b36eba8f 100644
--- a/doc/api/graphql/index.md
+++ b/doc/api/graphql/index.md
@@ -53,6 +53,11 @@ GitLab's GraphQL reference [is available](reference/index.md).
It is automatically generated from GitLab's GraphQL schema and embedded in a Markdown file.
+Machine-readable versions are also available:
+
+- [JSON format](reference/gitlab_schema.json)
+- [IDL format](reference/gitlab_schema.graphql)
+
## GraphiQL
The API can be explored by using the GraphiQL IDE, it is available on your
diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql
new file mode 100644
index 00000000000..a357c93b020
--- /dev/null
+++ b/doc/api/graphql/reference/gitlab_schema.graphql
@@ -0,0 +1,5422 @@
+"""
+Autogenerated input type of AddAwardEmoji
+"""
+input AddAwardEmojiInput {
+ """
+ The global id of the awardable resource
+ """
+ awardableId: ID!
+
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The emoji name
+ """
+ name: String!
+}
+
+"""
+Autogenerated return type of AddAwardEmoji
+"""
+type AddAwardEmojiPayload {
+ """
+ The award emoji after mutation
+ """
+ awardEmoji: AwardEmoji
+
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Reasons why the mutation failed.
+ """
+ errors: [String!]!
+}
+
+type AwardEmoji {
+ """
+ The emoji description
+ """
+ description: String!
+
+ """
+ The emoji as an icon
+ """
+ emoji: String!
+
+ """
+ The emoji name
+ """
+ name: String!
+
+ """
+ The emoji in unicode
+ """
+ unicode: String!
+
+ """
+ The unicode version for this emoji
+ """
+ unicodeVersion: String!
+
+ """
+ The user who awarded the emoji
+ """
+ user: User!
+}
+
+type Blob implements Entry {
+ flatPath: String!
+ id: ID!
+ lfsOid: String
+ name: String!
+ path: String!
+
+ """
+ Last commit sha for entry
+ """
+ sha: String!
+ type: EntryType!
+ webUrl: String
+}
+
+"""
+The connection type for Blob.
+"""
+type BlobConnection {
+ """
+ A list of edges.
+ """
+ edges: [BlobEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [Blob]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+}
+
+"""
+An edge in a connection.
+"""
+type BlobEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: Blob
+}
+
+type Commit {
+ """
+ Author of the commit
+ """
+ author: User
+
+ """
+ Commit authors name
+ """
+ authorName: String
+
+ """
+ Timestamp of when the commit was authored
+ """
+ authoredDate: Time
+
+ """
+ Description of the commit message
+ """
+ description: String
+
+ """
+ ID (global ID) of the commit
+ """
+ id: ID!
+
+ """
+ Latest pipeline of the commit
+ """
+ latestPipeline(
+ """
+ Filter pipelines by the ref they are run for
+ """
+ ref: String
+
+ """
+ Filter pipelines by the sha of the commit they are run for
+ """
+ sha: String
+
+ """
+ Filter pipelines by their status
+ """
+ status: PipelineStatusEnum
+ ): Pipeline @deprecated(reason: "use pipelines")
+
+ """
+ Raw commit message
+ """
+ message: String
+
+ """
+ Pipelines of the commit ordered latest first
+ """
+ pipelines(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+
+ """
+ Filter pipelines by the ref they are run for
+ """
+ ref: String
+
+ """
+ Filter pipelines by the sha of the commit they are run for
+ """
+ sha: String
+
+ """
+ Filter pipelines by their status
+ """
+ status: PipelineStatusEnum
+ ): PipelineConnection
+
+ """
+ SHA1 ID of the commit
+ """
+ sha: String!
+
+ """
+ Rendered HTML of the commit signature
+ """
+ signatureHtml: String
+
+ """
+ Title of the commit message
+ """
+ title: String
+
+ """
+ Web URL of the commit
+ """
+ webUrl: String!
+}
+
+"""
+Autogenerated input type of CreateDiffNote
+"""
+input CreateDiffNoteInput {
+ """
+ The content note itself
+ """
+ body: String!
+
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The global id of the resource to add a note to
+ """
+ noteableId: ID!
+
+ """
+ The position of this note on a diff
+ """
+ position: DiffPositionInput!
+}
+
+"""
+Autogenerated return type of CreateDiffNote
+"""
+type CreateDiffNotePayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Reasons why the mutation failed.
+ """
+ errors: [String!]!
+
+ """
+ The note after mutation
+ """
+ note: Note
+}
+
+"""
+Autogenerated input type of CreateEpic
+"""
+input CreateEpicInput {
+ """
+ The IDs of labels to be added to the epic.
+ """
+ addLabelIds: [ID!]
+
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The description of the epic
+ """
+ description: String
+
+ """
+ The end date of the epic
+ """
+ dueDateFixed: String
+
+ """
+ Indicates end date should be sourced from due_date_fixed field not the issue milestones
+ """
+ dueDateIsFixed: Boolean
+
+ """
+ The group the epic to mutate is in
+ """
+ groupPath: ID!
+
+ """
+ The IDs of labels to be removed from the epic.
+ """
+ removeLabelIds: [ID!]
+
+ """
+ The start date of the epic
+ """
+ startDateFixed: String
+
+ """
+ Indicates start date should be sourced from start_date_fixed field not the issue milestones
+ """
+ startDateIsFixed: Boolean
+
+ """
+ The title of the epic
+ """
+ title: String
+}
+
+"""
+Autogenerated return type of CreateEpic
+"""
+type CreateEpicPayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The created epic
+ """
+ epic: Epic
+
+ """
+ Reasons why the mutation failed.
+ """
+ errors: [String!]!
+}
+
+"""
+Autogenerated input type of CreateImageDiffNote
+"""
+input CreateImageDiffNoteInput {
+ """
+ The content note itself
+ """
+ body: String!
+
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The global id of the resource to add a note to
+ """
+ noteableId: ID!
+
+ """
+ The position of this note on a diff
+ """
+ position: DiffImagePositionInput!
+}
+
+"""
+Autogenerated return type of CreateImageDiffNote
+"""
+type CreateImageDiffNotePayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Reasons why the mutation failed.
+ """
+ errors: [String!]!
+
+ """
+ The note after mutation
+ """
+ note: Note
+}
+
+"""
+Autogenerated input type of CreateNote
+"""
+input CreateNoteInput {
+ """
+ The content note itself
+ """
+ body: String!
+
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The global id of the discussion this note is in reply to
+ """
+ discussionId: ID
+
+ """
+ The global id of the resource to add a note to
+ """
+ noteableId: ID!
+}
+
+"""
+Autogenerated return type of CreateNote
+"""
+type CreateNotePayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Reasons why the mutation failed.
+ """
+ errors: [String!]!
+
+ """
+ The note after mutation
+ """
+ note: Note
+}
+
+type Design implements Noteable {
+ diffRefs: DiffRefs!
+
+ """
+ All discussions on this noteable
+ """
+ discussions(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): DiscussionConnection!
+
+ """
+ The change that happened to the design at this version
+ """
+ event: DesignVersionEvent!
+ filename: String!
+ fullPath: String!
+ id: ID!
+ image: String!
+ issue: Issue!
+
+ """
+ All notes on this noteable
+ """
+ notes(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): NoteConnection!
+
+ """
+ The total count of user-created notes for this design
+ """
+ notesCount: Int!
+ project: Project!
+
+ """
+ All versions related to this design ordered newest first
+ """
+ versions(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): DesignVersionConnection!
+}
+
+type DesignCollection {
+ """
+ All designs for this collection
+ """
+ designs(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Filters designs to only those that existed at the version. If argument is
+ omitted or nil then all designs will reflect the latest version
+ """
+ atVersion: ID
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Filters designs by their filename
+ """
+ filenames: [String!]
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Filters designs by their ID
+ """
+ ids: [ID!]
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): DesignConnection!
+ issue: Issue!
+ project: Project!
+
+ """
+ All versions related to all designs ordered newest first
+ """
+ versions(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): DesignVersionConnection!
+}
+
+"""
+The connection type for Design.
+"""
+type DesignConnection {
+ """
+ A list of edges.
+ """
+ edges: [DesignEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [Design]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+}
+
+"""
+An edge in a connection.
+"""
+type DesignEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: Design
+}
+
+"""
+Autogenerated input type of DesignManagementDelete
+"""
+input DesignManagementDeleteInput {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The filenames of the designs to delete
+ """
+ filenames: [String!]!
+
+ """
+ The iid of the issue to modify designs for
+ """
+ iid: ID!
+
+ """
+ The project where the issue is to upload designs for
+ """
+ projectPath: ID!
+}
+
+"""
+Autogenerated return type of DesignManagementDelete
+"""
+type DesignManagementDeletePayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Reasons why the mutation failed.
+ """
+ errors: [String!]!
+
+ """
+ The new version in which the designs are deleted
+ """
+ version: DesignVersion
+}
+
+"""
+Autogenerated input type of DesignManagementUpload
+"""
+input DesignManagementUploadInput {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The files to upload
+ """
+ files: [Upload!]!
+
+ """
+ The iid of the issue to modify designs for
+ """
+ iid: ID!
+
+ """
+ The project where the issue is to upload designs for
+ """
+ projectPath: ID!
+}
+
+"""
+Autogenerated return type of DesignManagementUpload
+"""
+type DesignManagementUploadPayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The designs that were uploaded by the mutation
+ """
+ designs: [Design!]!
+
+ """
+ Reasons why the mutation failed.
+ """
+ errors: [String!]!
+
+ """
+ Any designs that were skipped from the upload due to there being no change to their content since their last version
+ """
+ skippedDesigns: [Design!]!
+}
+
+type DesignVersion {
+ """
+ All designs that were changed in this version
+ """
+ designs(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): DesignConnection!
+ id: ID!
+ sha: ID!
+}
+
+"""
+The connection type for DesignVersion.
+"""
+type DesignVersionConnection {
+ """
+ A list of edges.
+ """
+ edges: [DesignVersionEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [DesignVersion]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+}
+
+"""
+An edge in a connection.
+"""
+type DesignVersionEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: DesignVersion
+}
+
+"""
+Mutation event of a Design within a Version
+"""
+enum DesignVersionEvent {
+ """
+ A creation event
+ """
+ CREATION
+
+ """
+ A deletion event
+ """
+ DELETION
+
+ """
+ A modification event
+ """
+ MODIFICATION
+
+ """
+ No change
+ """
+ NONE
+}
+
+"""
+Autogenerated input type of DestroyNote
+"""
+input DestroyNoteInput {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The global id of the note to destroy
+ """
+ id: ID!
+}
+
+"""
+Autogenerated return type of DestroyNote
+"""
+type DestroyNotePayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Reasons why the mutation failed.
+ """
+ errors: [String!]!
+
+ """
+ The note after mutation
+ """
+ note: Note
+}
+
+type DetailedStatus {
+ detailsPath: String!
+ favicon: String!
+ group: String!
+ hasDetails: Boolean!
+ icon: String!
+ label: String!
+ text: String!
+ tooltip: String!
+}
+
+input DiffImagePositionInput {
+ """
+ The merge base of the branch the comment was made on
+ """
+ baseSha: String
+
+ """
+ The sha of the head at the time the comment was made
+ """
+ headSha: String!
+
+ """
+ The total height of the image
+ """
+ height: Int!
+
+ """
+ The paths of the file that was changed. Both of the properties of this input
+ are optional, but at least one of them is required
+ """
+ paths: DiffPathsInput!
+
+ """
+ The sha of the branch being compared against
+ """
+ startSha: String!
+
+ """
+ The total width of the image
+ """
+ width: Int!
+
+ """
+ The X postion on which the comment was made
+ """
+ x: Int!
+
+ """
+ The Y position on which the comment was made
+ """
+ y: Int!
+}
+
+input DiffPathsInput {
+ """
+ The path of the file on the head sha
+ """
+ newPath: String
+
+ """
+ The path of the file on the start sha
+ """
+ oldPath: String
+}
+
+type DiffPosition {
+ diffRefs: DiffRefs!
+
+ """
+ The path of the file that was changed
+ """
+ filePath: String!
+
+ """
+ The total height of the image
+ """
+ height: Int
+
+ """
+ The line on head sha that was changed
+ """
+ newLine: Int
+
+ """
+ The path of the file on the head sha.
+ """
+ newPath: String
+
+ """
+ The line on start sha that was changed
+ """
+ oldLine: Int
+
+ """
+ The path of the file on the start sha.
+ """
+ oldPath: String
+ positionType: DiffPositionType!
+
+ """
+ The total width of the image
+ """
+ width: Int
+
+ """
+ The X postion on which the comment was made
+ """
+ x: Int
+
+ """
+ The Y position on which the comment was made
+ """
+ y: Int
+}
+
+input DiffPositionInput {
+ """
+ The merge base of the branch the comment was made on
+ """
+ baseSha: String
+
+ """
+ The sha of the head at the time the comment was made
+ """
+ headSha: String!
+
+ """
+ The line on head sha that was changed
+ """
+ newLine: Int!
+
+ """
+ The line on start sha that was changed
+ """
+ oldLine: Int
+
+ """
+ The paths of the file that was changed. Both of the properties of this input
+ are optional, but at least one of them is required
+ """
+ paths: DiffPathsInput!
+
+ """
+ The sha of the branch being compared against
+ """
+ startSha: String!
+}
+
+"""
+Type of file the position refers to
+"""
+enum DiffPositionType {
+ image
+ text
+}
+
+type DiffRefs {
+ """
+ The merge base of the branch the comment was made on
+ """
+ baseSha: String!
+
+ """
+ The sha of the head at the time the comment was made
+ """
+ headSha: String!
+
+ """
+ The sha of the branch being compared against
+ """
+ startSha: String!
+}
+
+type Discussion {
+ createdAt: Time!
+ id: ID!
+
+ """
+ All notes in the discussion
+ """
+ notes(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): NoteConnection!
+
+ """
+ The ID used to reply to this discussion
+ """
+ replyId: ID!
+}
+
+"""
+The connection type for Discussion.
+"""
+type DiscussionConnection {
+ """
+ A list of edges.
+ """
+ edges: [DiscussionEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [Discussion]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+}
+
+"""
+An edge in a connection.
+"""
+type DiscussionEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: Discussion
+}
+
+interface Entry {
+ flatPath: String!
+ id: ID!
+ name: String!
+ path: String!
+
+ """
+ Last commit sha for entry
+ """
+ sha: String!
+ type: EntryType!
+}
+
+"""
+Type of a tree entry
+"""
+enum EntryType {
+ blob
+ commit
+ tree
+}
+
+type Epic implements Noteable {
+ author: User!
+ children(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Filter epics by author
+ """
+ authorUsername: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ List epics within a time frame where epics.end_date is between start_date
+ and end_date parameters (start_date parameter must be present)
+ """
+ endDate: Time
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ The IID of the epic, e.g., "1"
+ """
+ iid: ID
+
+ """
+ The list of IIDs of epics, e.g., [1, 2]
+ """
+ iids: [ID!]
+
+ """
+ Filter epics by labels
+ """
+ labelName: [String!]
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+
+ """
+ Filter epics by title and description
+ """
+ search: String
+
+ """
+ List epics by sort order
+ """
+ sort: EpicSort
+
+ """
+ List epics within a time frame where epics.start_date is between start_date
+ and end_date parameters (end_date parameter must be present)
+ """
+ startDate: Time
+
+ """
+ Filter epics by state
+ """
+ state: EpicState
+ ): EpicConnection
+ closedAt: Time
+ createdAt: Time
+
+ """
+ Number of open and closed descendant epics and issues
+ """
+ descendantCounts: EpicDescendantCount
+ description: String
+
+ """
+ All discussions on this noteable
+ """
+ discussions(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): DiscussionConnection!
+ dueDate: Time
+ dueDateFixed: Time
+ dueDateFromMilestones: Time
+ dueDateIsFixed: Boolean
+ group: Group!
+ hasChildren: Boolean!
+ hasIssues: Boolean!
+ id: ID!
+ iid: ID!
+
+ """
+ A list of issues associated with the epic
+ """
+ issues(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): EpicIssueConnection
+
+ """
+ Labels assigned to the epic
+ """
+ labels(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): LabelConnection
+
+ """
+ All notes on this noteable
+ """
+ notes(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): NoteConnection!
+ parent: Epic
+
+ """
+ List of participants for the epic
+ """
+ participants(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): UserConnection
+ reference(full: Boolean = false): String!
+ relationPath: String
+
+ """
+ The relative position of the epic in the Epic tree
+ """
+ relativePosition: Int
+ startDate: Time
+ startDateFixed: Time
+ startDateFromMilestones: Time
+ startDateIsFixed: Boolean
+ state: EpicState!
+
+ """
+ Boolean flag for whether the currently logged in user is subscribed to this epic
+ """
+ subscribed: Boolean!
+ title: String
+ updatedAt: Time
+
+ """
+ Permissions for the current user on the resource
+ """
+ userPermissions: EpicPermissions!
+ webPath: String!
+ webUrl: String!
+}
+
+"""
+The connection type for Epic.
+"""
+type EpicConnection {
+ """
+ A list of edges.
+ """
+ edges: [EpicEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [Epic]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+}
+
+type EpicDescendantCount {
+ """
+ Number of closed sub-epics
+ """
+ closedEpics: Int
+
+ """
+ Number of closed epic issues
+ """
+ closedIssues: Int
+
+ """
+ Number of opened sub-epics
+ """
+ openedEpics: Int
+
+ """
+ Number of opened epic issues
+ """
+ openedIssues: Int
+}
+
+"""
+An edge in a connection.
+"""
+type EpicEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: Epic
+}
+
+type EpicIssue implements Noteable {
+ """
+ Assignees of the issue
+ """
+ assignees(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): UserConnection
+
+ """
+ User that created the issue
+ """
+ author: User!
+
+ """
+ Timestamp of when the issue was closed
+ """
+ closedAt: Time
+
+ """
+ Indicates the issue is confidential
+ """
+ confidential: Boolean!
+
+ """
+ Timestamp of when the issue was created
+ """
+ createdAt: Time!
+
+ """
+ Description of the issue
+ """
+ description: String
+
+ """
+ The GitLab Flavored Markdown rendering of `description`
+ """
+ descriptionHtml: String
+ designCollection: DesignCollection
+ designs: DesignCollection @deprecated(reason: "use design_collection")
+
+ """
+ Indicates discussion is locked on the issue
+ """
+ discussionLocked: Boolean!
+
+ """
+ All discussions on this noteable
+ """
+ discussions(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): DiscussionConnection!
+
+ """
+ Number of downvotes the issue has received
+ """
+ downvotes: Int!
+
+ """
+ Due date of the issue
+ """
+ dueDate: Time
+
+ """
+ The epic to which issue belongs
+ """
+ epic: Epic
+ epicIssueId: ID!
+
+ """
+ The global id of the epic-issue relation
+ """
+ id: ID
+
+ """
+ Internal ID of the issue
+ """
+ iid: ID!
+
+ """
+ Labels of the issue
+ """
+ labels(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): LabelConnection
+
+ """
+ Milestone of the issue
+ """
+ milestone: Milestone
+
+ """
+ All notes on this noteable
+ """
+ notes(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): NoteConnection!
+
+ """
+ List of participants in the issue
+ """
+ participants(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): UserConnection
+
+ """
+ Internal reference of the issue. Returned in shortened format by default
+ """
+ reference(
+ """
+ Boolean option specifying whether the reference should be returned in full
+ """
+ full: Boolean = false
+ ): String!
+ relationPath: String
+
+ """
+ Relative position of the issue (used for positioning in epic tree and issue boards)
+ """
+ relativePosition: Int
+
+ """
+ State of the issue
+ """
+ state: IssueState!
+
+ """
+ Boolean flag for whether the currently logged in user is subscribed to this issue
+ """
+ subscribed: Boolean!
+
+ """
+ Task completion status of the issue
+ """
+ taskCompletionStatus: TaskCompletionStatus!
+
+ """
+ Time estimate of the issue
+ """
+ timeEstimate: Int!
+
+ """
+ Title of the issue
+ """
+ title: String!
+
+ """
+ The GitLab Flavored Markdown rendering of `title`
+ """
+ titleHtml: String
+
+ """
+ Total time reported as spent on the issue
+ """
+ totalTimeSpent: Int!
+
+ """
+ Timestamp of when the issue was last updated
+ """
+ updatedAt: Time!
+
+ """
+ Number of upvotes the issue has received
+ """
+ upvotes: Int!
+
+ """
+ Number of user notes of the issue
+ """
+ userNotesCount: Int!
+
+ """
+ Permissions for the current user on the resource
+ """
+ userPermissions: IssuePermissions!
+
+ """
+ Web path of the issue
+ """
+ webPath: String!
+
+ """
+ Web URL of the issue
+ """
+ webUrl: String!
+ weight: Int
+}
+
+"""
+The connection type for EpicIssue.
+"""
+type EpicIssueConnection {
+ """
+ A list of edges.
+ """
+ edges: [EpicIssueEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [EpicIssue]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+}
+
+"""
+An edge in a connection.
+"""
+type EpicIssueEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: EpicIssue
+}
+
+"""
+Check permissions for the current user on an epic
+"""
+type EpicPermissions {
+ """
+ Whether or not a user can perform `admin_epic` on this resource
+ """
+ adminEpic: Boolean!
+
+ """
+ Whether or not a user can perform `award_emoji` on this resource
+ """
+ awardEmoji: Boolean!
+
+ """
+ Whether or not a user can perform `create_epic` on this resource
+ """
+ createEpic: Boolean!
+
+ """
+ Whether or not a user can perform `create_note` on this resource
+ """
+ createNote: Boolean!
+
+ """
+ Whether or not a user can perform `destroy_epic` on this resource
+ """
+ destroyEpic: Boolean!
+
+ """
+ Whether or not a user can perform `read_epic` on this resource
+ """
+ readEpic: Boolean!
+
+ """
+ Whether or not a user can perform `read_epic_iid` on this resource
+ """
+ readEpicIid: Boolean!
+
+ """
+ Whether or not a user can perform `update_epic` on this resource
+ """
+ updateEpic: Boolean!
+}
+
+"""
+Autogenerated input type of EpicSetSubscription
+"""
+input EpicSetSubscriptionInput {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The group the epic to (un)subscribe is in
+ """
+ groupPath: ID!
+
+ """
+ The iid of the epic to (un)subscribe
+ """
+ iid: ID!
+
+ """
+ The desired state of the subscription
+ """
+ subscribedState: Boolean!
+}
+
+"""
+Autogenerated return type of EpicSetSubscription
+"""
+type EpicSetSubscriptionPayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The epic after mutation
+ """
+ epic: Epic
+
+ """
+ Reasons why the mutation failed.
+ """
+ errors: [String!]!
+}
+
+"""
+Roadmap sort values
+"""
+enum EpicSort {
+ """
+ End date at ascending order
+ """
+ end_date_asc
+
+ """
+ End date at descending order
+ """
+ end_date_desc
+
+ """
+ Start date at ascending order
+ """
+ start_date_asc
+
+ """
+ Start date at descending order
+ """
+ start_date_desc
+}
+
+"""
+State of a GitLab epic
+"""
+enum EpicState {
+ all
+ closed
+ opened
+}
+
+"""
+State event of a GitLab Epic
+"""
+enum EpicStateEvent {
+ """
+ Close the Epic
+ """
+ CLOSE
+
+ """
+ Reopen the Epic
+ """
+ REOPEN
+}
+
+input EpicTreeNodeFieldsInputType {
+ """
+ The id of the epic_issue or issue that the actual epic or issue is switched with
+ """
+ adjacentReferenceId: ID!
+
+ """
+ The id of the epic_issue or epic that is being moved
+ """
+ id: ID!
+
+ """
+ The type of the switch, after or before allowed
+ """
+ relativePosition: MoveType!
+}
+
+"""
+Autogenerated input type of EpicTreeReorder
+"""
+input EpicTreeReorderInput {
+ """
+ The id of the base epic of the tree
+ """
+ baseEpicId: ID!
+
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Parameters for updating the tree positions
+ """
+ moved: EpicTreeNodeFieldsInputType!
+}
+
+"""
+Autogenerated return type of EpicTreeReorder
+"""
+type EpicTreeReorderPayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Reasons why the mutation failed.
+ """
+ errors: [String!]!
+}
+
+type Group {
+ """
+ Avatar URL of the group
+ """
+ avatarUrl: String
+
+ """
+ Description of the namespace
+ """
+ description: String
+
+ """
+ The GitLab Flavored Markdown rendering of `description`
+ """
+ descriptionHtml: String
+ epic(
+ """
+ Filter epics by author
+ """
+ authorUsername: String
+
+ """
+ List epics within a time frame where epics.end_date is between start_date
+ and end_date parameters (start_date parameter must be present)
+ """
+ endDate: Time
+
+ """
+ The IID of the epic, e.g., "1"
+ """
+ iid: ID
+
+ """
+ The list of IIDs of epics, e.g., [1, 2]
+ """
+ iids: [ID!]
+
+ """
+ Filter epics by labels
+ """
+ labelName: [String!]
+
+ """
+ Filter epics by title and description
+ """
+ search: String
+
+ """
+ List epics by sort order
+ """
+ sort: EpicSort
+
+ """
+ List epics within a time frame where epics.start_date is between start_date
+ and end_date parameters (end_date parameter must be present)
+ """
+ startDate: Time
+
+ """
+ Filter epics by state
+ """
+ state: EpicState
+ ): Epic
+ epics(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Filter epics by author
+ """
+ authorUsername: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ List epics within a time frame where epics.end_date is between start_date
+ and end_date parameters (start_date parameter must be present)
+ """
+ endDate: Time
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ The IID of the epic, e.g., "1"
+ """
+ iid: ID
+
+ """
+ The list of IIDs of epics, e.g., [1, 2]
+ """
+ iids: [ID!]
+
+ """
+ Filter epics by labels
+ """
+ labelName: [String!]
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+
+ """
+ Filter epics by title and description
+ """
+ search: String
+
+ """
+ List epics by sort order
+ """
+ sort: EpicSort
+
+ """
+ List epics within a time frame where epics.start_date is between start_date
+ and end_date parameters (end_date parameter must be present)
+ """
+ startDate: Time
+
+ """
+ Filter epics by state
+ """
+ state: EpicState
+ ): EpicConnection
+ epicsEnabled: Boolean
+
+ """
+ Full name of the namespace
+ """
+ fullName: String!
+
+ """
+ Full path of the namespace
+ """
+ fullPath: ID!
+
+ """
+ ID of the namespace
+ """
+ id: ID!
+
+ """
+ Indicates if Large File Storage (LFS) is enabled for namespace
+ """
+ lfsEnabled: Boolean
+
+ """
+ Name of the namespace
+ """
+ name: String!
+
+ """
+ Parent group
+ """
+ parent: Group
+
+ """
+ Path of the namespace
+ """
+ path: String!
+
+ """
+ Projects within this namespace
+ """
+ projects(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Include also subgroup projects
+ """
+ includeSubgroups: Boolean = false
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): ProjectConnection!
+
+ """
+ Indicates if users can request access to namespace
+ """
+ requestAccessEnabled: Boolean
+
+ """
+ Aggregated storage statistics of the namespace. Only available for root namespaces
+ """
+ rootStorageStatistics: RootStorageStatistics
+
+ """
+ Permissions for the current user on the resource
+ """
+ userPermissions: GroupPermissions!
+
+ """
+ Visibility of the namespace
+ """
+ visibility: String
+
+ """
+ Web URL of the group
+ """
+ webUrl: String!
+}
+
+type GroupPermissions {
+ """
+ Whether or not a user can perform `read_group` on this resource
+ """
+ readGroup: Boolean!
+}
+
+"""
+State of a GitLab issue or merge request
+"""
+enum IssuableState {
+ closed
+ locked
+ opened
+}
+
+type Issue implements Noteable {
+ """
+ Assignees of the issue
+ """
+ assignees(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): UserConnection
+
+ """
+ User that created the issue
+ """
+ author: User!
+
+ """
+ Timestamp of when the issue was closed
+ """
+ closedAt: Time
+
+ """
+ Indicates the issue is confidential
+ """
+ confidential: Boolean!
+
+ """
+ Timestamp of when the issue was created
+ """
+ createdAt: Time!
+
+ """
+ Description of the issue
+ """
+ description: String
+
+ """
+ The GitLab Flavored Markdown rendering of `description`
+ """
+ descriptionHtml: String
+ designCollection: DesignCollection
+ designs: DesignCollection @deprecated(reason: "use design_collection")
+
+ """
+ Indicates discussion is locked on the issue
+ """
+ discussionLocked: Boolean!
+
+ """
+ All discussions on this noteable
+ """
+ discussions(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): DiscussionConnection!
+
+ """
+ Number of downvotes the issue has received
+ """
+ downvotes: Int!
+
+ """
+ Due date of the issue
+ """
+ dueDate: Time
+
+ """
+ The epic to which issue belongs
+ """
+ epic: Epic
+
+ """
+ Internal ID of the issue
+ """
+ iid: ID!
+
+ """
+ Labels of the issue
+ """
+ labels(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): LabelConnection
+
+ """
+ Milestone of the issue
+ """
+ milestone: Milestone
+
+ """
+ All notes on this noteable
+ """
+ notes(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): NoteConnection!
+
+ """
+ List of participants in the issue
+ """
+ participants(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): UserConnection
+
+ """
+ Internal reference of the issue. Returned in shortened format by default
+ """
+ reference(
+ """
+ Boolean option specifying whether the reference should be returned in full
+ """
+ full: Boolean = false
+ ): String!
+
+ """
+ Relative position of the issue (used for positioning in epic tree and issue boards)
+ """
+ relativePosition: Int
+
+ """
+ State of the issue
+ """
+ state: IssueState!
+
+ """
+ Boolean flag for whether the currently logged in user is subscribed to this issue
+ """
+ subscribed: Boolean!
+
+ """
+ Task completion status of the issue
+ """
+ taskCompletionStatus: TaskCompletionStatus!
+
+ """
+ Time estimate of the issue
+ """
+ timeEstimate: Int!
+
+ """
+ Title of the issue
+ """
+ title: String!
+
+ """
+ The GitLab Flavored Markdown rendering of `title`
+ """
+ titleHtml: String
+
+ """
+ Total time reported as spent on the issue
+ """
+ totalTimeSpent: Int!
+
+ """
+ Timestamp of when the issue was last updated
+ """
+ updatedAt: Time!
+
+ """
+ Number of upvotes the issue has received
+ """
+ upvotes: Int!
+
+ """
+ Number of user notes of the issue
+ """
+ userNotesCount: Int!
+
+ """
+ Permissions for the current user on the resource
+ """
+ userPermissions: IssuePermissions!
+
+ """
+ Web path of the issue
+ """
+ webPath: String!
+
+ """
+ Web URL of the issue
+ """
+ webUrl: String!
+ weight: Int
+}
+
+"""
+The connection type for Issue.
+"""
+type IssueConnection {
+ """
+ A list of edges.
+ """
+ edges: [IssueEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [Issue]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+}
+
+"""
+An edge in a connection.
+"""
+type IssueEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: Issue
+}
+
+"""
+Check permissions for the current user on a issue
+"""
+type IssuePermissions {
+ """
+ Whether or not a user can perform `admin_issue` on this resource
+ """
+ adminIssue: Boolean!
+
+ """
+ Whether or not a user can perform `create_design` on this resource
+ """
+ createDesign: Boolean!
+
+ """
+ Whether or not a user can perform `create_note` on this resource
+ """
+ createNote: Boolean!
+
+ """
+ Whether or not a user can perform `destroy_design` on this resource
+ """
+ destroyDesign: Boolean!
+
+ """
+ Whether or not a user can perform `read_design` on this resource
+ """
+ readDesign: Boolean!
+
+ """
+ Whether or not a user can perform `read_issue` on this resource
+ """
+ readIssue: Boolean!
+
+ """
+ Whether or not a user can perform `reopen_issue` on this resource
+ """
+ reopenIssue: Boolean!
+
+ """
+ Whether or not a user can perform `update_issue` on this resource
+ """
+ updateIssue: Boolean!
+}
+
+"""
+Values for sorting issues
+"""
+enum IssueSort {
+ """
+ Due date by ascending order
+ """
+ DUE_DATE_ASC
+
+ """
+ Due date by descending order
+ """
+ DUE_DATE_DESC
+
+ """
+ Relative position by ascending order
+ """
+ RELATIVE_POSITION_ASC
+
+ """
+ Created at ascending order
+ """
+ created_asc
+
+ """
+ Created at descending order
+ """
+ created_desc
+
+ """
+ Updated at ascending order
+ """
+ updated_asc
+
+ """
+ Updated at descending order
+ """
+ updated_desc
+}
+
+"""
+State of a GitLab issue
+"""
+enum IssueState {
+ closed
+ locked
+ opened
+}
+
+type Label {
+ """
+ Background color of the label
+ """
+ color: String!
+
+ """
+ Description of the label (markdown rendered as HTML for caching)
+ """
+ description: String
+
+ """
+ The GitLab Flavored Markdown rendering of `description`
+ """
+ descriptionHtml: String
+
+ """
+ Label ID
+ """
+ id: ID!
+
+ """
+ Text color of the label
+ """
+ textColor: String!
+
+ """
+ Content of the label
+ """
+ title: String!
+}
+
+"""
+The connection type for Label.
+"""
+type LabelConnection {
+ """
+ A list of edges.
+ """
+ edges: [LabelEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [Label]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+}
+
+"""
+An edge in a connection.
+"""
+type LabelEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: Label
+}
+
+type MergeRequest implements Noteable {
+ """
+ Indicates if members of the target project can push to the fork
+ """
+ allowCollaboration: Boolean
+
+ """
+ Assignees of the merge request
+ """
+ assignees(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): UserConnection
+
+ """
+ Timestamp of when the merge request was created
+ """
+ createdAt: Time!
+
+ """
+ Default merge commit message of the merge request
+ """
+ defaultMergeCommitMessage: String
+
+ """
+ Description of the merge request (markdown rendered as HTML for caching)
+ """
+ description: String
+
+ """
+ The GitLab Flavored Markdown rendering of `description`
+ """
+ descriptionHtml: String
+
+ """
+ Diff head SHA of the merge request
+ """
+ diffHeadSha: String
+
+ """
+ References of the base SHA, the head SHA, and the start SHA for this merge request
+ """
+ diffRefs: DiffRefs
+
+ """
+ Indicates if comments on the merge request are locked to members only
+ """
+ discussionLocked: Boolean!
+
+ """
+ All discussions on this noteable
+ """
+ discussions(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): DiscussionConnection!
+
+ """
+ Number of downvotes for the merge request
+ """
+ downvotes: Int!
+
+ """
+ Indicates if the project settings will lead to source branch deletion after merge
+ """
+ forceRemoveSourceBranch: Boolean
+
+ """
+ The pipeline running on the branch HEAD of the merge request
+ """
+ headPipeline: Pipeline
+
+ """
+ ID of the merge request
+ """
+ id: ID!
+
+ """
+ Internal ID of the merge request
+ """
+ iid: String!
+
+ """
+ Commit SHA of the merge request if merge is in progress
+ """
+ inProgressMergeCommitSha: String
+
+ """
+ Labels of the merge request
+ """
+ labels(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): LabelConnection
+
+ """
+ Deprecated - renamed to defaultMergeCommitMessage
+ """
+ mergeCommitMessage: String @deprecated(reason: "Renamed to defaultMergeCommitMessage")
+
+ """
+ SHA of the merge request commit (set once merged)
+ """
+ mergeCommitSha: String
+
+ """
+ Error message due to a merge error
+ """
+ mergeError: String
+
+ """
+ Indicates if a merge is currently occurring
+ """
+ mergeOngoing: Boolean!
+
+ """
+ Status of the merge request
+ """
+ mergeStatus: String
+
+ """
+ Indicates if the merge has been set to be merged when its pipeline succeeds (MWPS)
+ """
+ mergeWhenPipelineSucceeds: Boolean
+
+ """
+ Indicates if all discussions in the merge request have been resolved, allowing the merge request to be merged
+ """
+ mergeableDiscussionsState: Boolean
+
+ """
+ The milestone of the merge request
+ """
+ milestone: Milestone
+
+ """
+ All notes on this noteable
+ """
+ notes(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): NoteConnection!
+
+ """
+ Participants in the merge request
+ """
+ participants(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): UserConnection
+
+ """
+ Pipelines for the merge request
+ """
+ pipelines(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+
+ """
+ Filter pipelines by the ref they are run for
+ """
+ ref: String
+
+ """
+ Filter pipelines by the sha of the commit they are run for
+ """
+ sha: String
+
+ """
+ Filter pipelines by their status
+ """
+ status: PipelineStatusEnum
+ ): PipelineConnection!
+
+ """
+ Alias for target_project
+ """
+ project: Project!
+
+ """
+ ID of the merge request project
+ """
+ projectId: Int!
+
+ """
+ Rebase commit SHA of the merge request
+ """
+ rebaseCommitSha: String
+
+ """
+ Indicates if there is a rebase currently in progress for the merge request
+ """
+ rebaseInProgress: Boolean!
+
+ """
+ Internal reference of the merge request. Returned in shortened format by default
+ """
+ reference(
+ """
+ Boolean option specifying whether the reference should be returned in full
+ """
+ full: Boolean = false
+ ): String!
+
+ """
+ Indicates if the merge request will be rebased
+ """
+ shouldBeRebased: Boolean!
+
+ """
+ Indicates if the source branch of the merge request will be deleted after merge
+ """
+ shouldRemoveSourceBranch: Boolean
+
+ """
+ Source branch of the merge request
+ """
+ sourceBranch: String!
+
+ """
+ Indicates if the source branch of the merge request exists
+ """
+ sourceBranchExists: Boolean!
+
+ """
+ Source project of the merge request
+ """
+ sourceProject: Project
+
+ """
+ ID of the merge request source project
+ """
+ sourceProjectId: Int
+
+ """
+ State of the merge request
+ """
+ state: MergeRequestState!
+
+ """
+ Indicates if the currently logged in user is subscribed to this merge request
+ """
+ subscribed: Boolean!
+
+ """
+ Target branch of the merge request
+ """
+ targetBranch: String!
+
+ """
+ Target project of the merge request
+ """
+ targetProject: Project!
+
+ """
+ ID of the merge request target project
+ """
+ targetProjectId: Int!
+
+ """
+ Completion status of tasks
+ """
+ taskCompletionStatus: TaskCompletionStatus!
+
+ """
+ Time estimate of the merge request
+ """
+ timeEstimate: Int!
+
+ """
+ Title of the merge request
+ """
+ title: String!
+
+ """
+ The GitLab Flavored Markdown rendering of `title`
+ """
+ titleHtml: String
+
+ """
+ Total time reported as spent on the merge request
+ """
+ totalTimeSpent: Int!
+
+ """
+ Timestamp of when the merge request was last updated
+ """
+ updatedAt: Time!
+
+ """
+ Number of upvotes for the merge request
+ """
+ upvotes: Int!
+
+ """
+ User notes count of the merge request
+ """
+ userNotesCount: Int
+
+ """
+ Permissions for the current user on the resource
+ """
+ userPermissions: MergeRequestPermissions!
+
+ """
+ Web URL of the merge request
+ """
+ webUrl: String
+
+ """
+ Indicates if the merge request is a work in progress (WIP)
+ """
+ workInProgress: Boolean!
+}
+
+"""
+The connection type for MergeRequest.
+"""
+type MergeRequestConnection {
+ """
+ A list of edges.
+ """
+ edges: [MergeRequestEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [MergeRequest]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+}
+
+"""
+An edge in a connection.
+"""
+type MergeRequestEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: MergeRequest
+}
+
+"""
+Check permissions for the current user on a merge request
+"""
+type MergeRequestPermissions {
+ """
+ Whether or not a user can perform `admin_merge_request` on this resource
+ """
+ adminMergeRequest: Boolean!
+
+ """
+ Whether or not a user can perform `cherry_pick_on_current_merge_request` on this resource
+ """
+ cherryPickOnCurrentMergeRequest: Boolean!
+
+ """
+ Whether or not a user can perform `create_note` on this resource
+ """
+ createNote: Boolean!
+
+ """
+ Whether or not a user can perform `push_to_source_branch` on this resource
+ """
+ pushToSourceBranch: Boolean!
+
+ """
+ Whether or not a user can perform `read_merge_request` on this resource
+ """
+ readMergeRequest: Boolean!
+
+ """
+ Whether or not a user can perform `remove_source_branch` on this resource
+ """
+ removeSourceBranch: Boolean!
+
+ """
+ Whether or not a user can perform `revert_on_current_merge_request` on this resource
+ """
+ revertOnCurrentMergeRequest: Boolean!
+
+ """
+ Whether or not a user can perform `update_merge_request` on this resource
+ """
+ updateMergeRequest: Boolean!
+}
+
+"""
+Autogenerated input type of MergeRequestSetAssignees
+"""
+input MergeRequestSetAssigneesInput {
+ """
+ The usernames to assign to the merge request. Replaces existing assignees by default.
+ """
+ assigneeUsernames: [String!]!
+
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The iid of the merge request to mutate
+ """
+ iid: String!
+
+ """
+ The operation to perform. Defaults to REPLACE.
+ """
+ operationMode: MutationOperationMode
+
+ """
+ The project the merge request to mutate is in
+ """
+ projectPath: ID!
+}
+
+"""
+Autogenerated return type of MergeRequestSetAssignees
+"""
+type MergeRequestSetAssigneesPayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Reasons why the mutation failed.
+ """
+ errors: [String!]!
+
+ """
+ The merge request after mutation
+ """
+ mergeRequest: MergeRequest
+}
+
+"""
+Autogenerated input type of MergeRequestSetLabels
+"""
+input MergeRequestSetLabelsInput {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The iid of the merge request to mutate
+ """
+ iid: String!
+
+ """
+ The Label IDs to set. Replaces existing labels by default.
+ """
+ labelIds: [ID!]!
+
+ """
+ Changes the operation mode. Defaults to REPLACE.
+ """
+ operationMode: MutationOperationMode
+
+ """
+ The project the merge request to mutate is in
+ """
+ projectPath: ID!
+}
+
+"""
+Autogenerated return type of MergeRequestSetLabels
+"""
+type MergeRequestSetLabelsPayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Reasons why the mutation failed.
+ """
+ errors: [String!]!
+
+ """
+ The merge request after mutation
+ """
+ mergeRequest: MergeRequest
+}
+
+"""
+Autogenerated input type of MergeRequestSetLocked
+"""
+input MergeRequestSetLockedInput {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The iid of the merge request to mutate
+ """
+ iid: String!
+
+ """
+ Whether or not to lock the merge request.
+ """
+ locked: Boolean!
+
+ """
+ The project the merge request to mutate is in
+ """
+ projectPath: ID!
+}
+
+"""
+Autogenerated return type of MergeRequestSetLocked
+"""
+type MergeRequestSetLockedPayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Reasons why the mutation failed.
+ """
+ errors: [String!]!
+
+ """
+ The merge request after mutation
+ """
+ mergeRequest: MergeRequest
+}
+
+"""
+Autogenerated input type of MergeRequestSetMilestone
+"""
+input MergeRequestSetMilestoneInput {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The iid of the merge request to mutate
+ """
+ iid: String!
+
+ """
+ The milestone to assign to the merge request.
+ """
+ milestoneId: ID
+
+ """
+ The project the merge request to mutate is in
+ """
+ projectPath: ID!
+}
+
+"""
+Autogenerated return type of MergeRequestSetMilestone
+"""
+type MergeRequestSetMilestonePayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Reasons why the mutation failed.
+ """
+ errors: [String!]!
+
+ """
+ The merge request after mutation
+ """
+ mergeRequest: MergeRequest
+}
+
+"""
+Autogenerated input type of MergeRequestSetSubscription
+"""
+input MergeRequestSetSubscriptionInput {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The iid of the merge request to mutate
+ """
+ iid: String!
+
+ """
+ The project the merge request to mutate is in
+ """
+ projectPath: ID!
+
+ """
+ The desired state of the subscription
+ """
+ subscribedState: Boolean!
+}
+
+"""
+Autogenerated return type of MergeRequestSetSubscription
+"""
+type MergeRequestSetSubscriptionPayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Reasons why the mutation failed.
+ """
+ errors: [String!]!
+
+ """
+ The merge request after mutation
+ """
+ mergeRequest: MergeRequest
+}
+
+"""
+Autogenerated input type of MergeRequestSetWip
+"""
+input MergeRequestSetWipInput {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The iid of the merge request to mutate
+ """
+ iid: String!
+
+ """
+ The project the merge request to mutate is in
+ """
+ projectPath: ID!
+
+ """
+ Whether or not to set the merge request as a WIP.
+ """
+ wip: Boolean!
+}
+
+"""
+Autogenerated return type of MergeRequestSetWip
+"""
+type MergeRequestSetWipPayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Reasons why the mutation failed.
+ """
+ errors: [String!]!
+
+ """
+ The merge request after mutation
+ """
+ mergeRequest: MergeRequest
+}
+
+"""
+State of a GitLab merge request
+"""
+enum MergeRequestState {
+ closed
+ locked
+ merged
+ opened
+}
+
+type Metadata {
+ """
+ Revision
+ """
+ revision: String!
+
+ """
+ Version
+ """
+ version: String!
+}
+
+type Milestone {
+ """
+ Timestamp of milestone creation
+ """
+ createdAt: Time!
+
+ """
+ Description of the milestone
+ """
+ description: String
+
+ """
+ Timestamp of the milestone due date
+ """
+ dueDate: Time
+
+ """
+ ID of the milestone
+ """
+ id: ID!
+
+ """
+ Timestamp of the milestone start date
+ """
+ startDate: Time
+
+ """
+ State of the milestone
+ """
+ state: String!
+
+ """
+ Title of the milestone
+ """
+ title: String!
+
+ """
+ Timestamp of last milestone update
+ """
+ updatedAt: Time!
+}
+
+"""
+The position the adjacent object should be moved.
+"""
+enum MoveType {
+ """
+ The adjacent object will be moved after the object that is being moved.
+ """
+ after
+
+ """
+ The adjacent object will be moved before the object that is being moved.
+ """
+ before
+}
+
+type Mutation {
+ addAwardEmoji(input: AddAwardEmojiInput!): AddAwardEmojiPayload
+ createDiffNote(input: CreateDiffNoteInput!): CreateDiffNotePayload
+ createEpic(input: CreateEpicInput!): CreateEpicPayload
+ createImageDiffNote(input: CreateImageDiffNoteInput!): CreateImageDiffNotePayload
+ createNote(input: CreateNoteInput!): CreateNotePayload
+ designManagementDelete(input: DesignManagementDeleteInput!): DesignManagementDeletePayload
+ designManagementUpload(input: DesignManagementUploadInput!): DesignManagementUploadPayload
+ destroyNote(input: DestroyNoteInput!): DestroyNotePayload
+ epicSetSubscription(input: EpicSetSubscriptionInput!): EpicSetSubscriptionPayload
+ epicTreeReorder(input: EpicTreeReorderInput!): EpicTreeReorderPayload
+ mergeRequestSetAssignees(input: MergeRequestSetAssigneesInput!): MergeRequestSetAssigneesPayload
+ mergeRequestSetLabels(input: MergeRequestSetLabelsInput!): MergeRequestSetLabelsPayload
+ mergeRequestSetLocked(input: MergeRequestSetLockedInput!): MergeRequestSetLockedPayload
+ mergeRequestSetMilestone(input: MergeRequestSetMilestoneInput!): MergeRequestSetMilestonePayload
+ mergeRequestSetSubscription(input: MergeRequestSetSubscriptionInput!): MergeRequestSetSubscriptionPayload
+ mergeRequestSetWip(input: MergeRequestSetWipInput!): MergeRequestSetWipPayload
+ removeAwardEmoji(input: RemoveAwardEmojiInput!): RemoveAwardEmojiPayload
+ todoMarkDone(input: TodoMarkDoneInput!): TodoMarkDonePayload
+ toggleAwardEmoji(input: ToggleAwardEmojiInput!): ToggleAwardEmojiPayload
+ updateEpic(input: UpdateEpicInput!): UpdateEpicPayload
+ updateNote(input: UpdateNoteInput!): UpdateNotePayload
+}
+
+"""
+Different toggles for changing mutator behavior.
+"""
+enum MutationOperationMode {
+ """
+ Performs an append operation
+ """
+ APPEND
+
+ """
+ Performs a removal operation
+ """
+ REMOVE
+
+ """
+ Performs a replace operation
+ """
+ REPLACE
+}
+
+type Namespace {
+ """
+ Description of the namespace
+ """
+ description: String
+
+ """
+ The GitLab Flavored Markdown rendering of `description`
+ """
+ descriptionHtml: String
+
+ """
+ Full name of the namespace
+ """
+ fullName: String!
+
+ """
+ Full path of the namespace
+ """
+ fullPath: ID!
+
+ """
+ ID of the namespace
+ """
+ id: ID!
+
+ """
+ Indicates if Large File Storage (LFS) is enabled for namespace
+ """
+ lfsEnabled: Boolean
+
+ """
+ Name of the namespace
+ """
+ name: String!
+
+ """
+ Path of the namespace
+ """
+ path: String!
+
+ """
+ Projects within this namespace
+ """
+ projects(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Include also subgroup projects
+ """
+ includeSubgroups: Boolean = false
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): ProjectConnection!
+
+ """
+ Indicates if users can request access to namespace
+ """
+ requestAccessEnabled: Boolean
+
+ """
+ Aggregated storage statistics of the namespace. Only available for root namespaces
+ """
+ rootStorageStatistics: RootStorageStatistics
+
+ """
+ Visibility of the namespace
+ """
+ visibility: String
+}
+
+type Note {
+ """
+ The user who wrote this note
+ """
+ author: User!
+
+ """
+ The content note itself
+ """
+ body: String!
+
+ """
+ The GitLab Flavored Markdown rendering of `note`
+ """
+ bodyHtml: String
+ createdAt: Time!
+
+ """
+ The discussion this note is a part of
+ """
+ discussion: Discussion
+ id: ID!
+
+ """
+ The position of this note on a diff
+ """
+ position: DiffPosition
+
+ """
+ The project this note is associated to
+ """
+ project: Project
+ resolvable: Boolean!
+
+ """
+ The time the discussion was resolved
+ """
+ resolvedAt: Time
+
+ """
+ The user that resolved the discussion
+ """
+ resolvedBy: User
+
+ """
+ Whether or not this note was created by the system or by a user
+ """
+ system: Boolean!
+ updatedAt: Time!
+
+ """
+ Permissions for the current user on the resource
+ """
+ userPermissions: NotePermissions!
+}
+
+"""
+The connection type for Note.
+"""
+type NoteConnection {
+ """
+ A list of edges.
+ """
+ edges: [NoteEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [Note]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+}
+
+"""
+An edge in a connection.
+"""
+type NoteEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: Note
+}
+
+type NotePermissions {
+ """
+ Whether or not a user can perform `admin_note` on this resource
+ """
+ adminNote: Boolean!
+
+ """
+ Whether or not a user can perform `award_emoji` on this resource
+ """
+ awardEmoji: Boolean!
+
+ """
+ Whether or not a user can perform `create_note` on this resource
+ """
+ createNote: Boolean!
+
+ """
+ Whether or not a user can perform `read_note` on this resource
+ """
+ readNote: Boolean!
+
+ """
+ Whether or not a user can perform `resolve_note` on this resource
+ """
+ resolveNote: Boolean!
+}
+
+interface Noteable {
+ """
+ All discussions on this noteable
+ """
+ discussions(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): DiscussionConnection!
+
+ """
+ All notes on this noteable
+ """
+ notes(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): NoteConnection!
+}
+
+"""
+Information about pagination in a connection.
+"""
+type PageInfo {
+ """
+ When paginating forwards, the cursor to continue.
+ """
+ endCursor: String
+
+ """
+ When paginating forwards, are there more items?
+ """
+ hasNextPage: Boolean!
+
+ """
+ When paginating backwards, are there more items?
+ """
+ hasPreviousPage: Boolean!
+
+ """
+ When paginating backwards, the cursor to continue.
+ """
+ startCursor: String
+}
+
+type Pipeline {
+ beforeSha: String
+ committedAt: Time
+
+ """
+ Coverage percentage
+ """
+ coverage: Float
+ createdAt: Time!
+ detailedStatus: DetailedStatus!
+
+ """
+ Duration of the pipeline in seconds
+ """
+ duration: Int
+ finishedAt: Time
+ id: ID!
+ iid: String!
+ sha: String!
+ startedAt: Time
+ status: PipelineStatusEnum!
+ updatedAt: Time!
+
+ """
+ Permissions for the current user on the resource
+ """
+ userPermissions: PipelinePermissions!
+}
+
+"""
+The connection type for Pipeline.
+"""
+type PipelineConnection {
+ """
+ A list of edges.
+ """
+ edges: [PipelineEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [Pipeline]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+}
+
+"""
+An edge in a connection.
+"""
+type PipelineEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: Pipeline
+}
+
+type PipelinePermissions {
+ """
+ Whether or not a user can perform `admin_pipeline` on this resource
+ """
+ adminPipeline: Boolean!
+
+ """
+ Whether or not a user can perform `destroy_pipeline` on this resource
+ """
+ destroyPipeline: Boolean!
+
+ """
+ Whether or not a user can perform `update_pipeline` on this resource
+ """
+ updatePipeline: Boolean!
+}
+
+enum PipelineStatusEnum {
+ CANCELED
+ CREATED
+ FAILED
+ MANUAL
+ PENDING
+ PREPARING
+ RUNNING
+ SCHEDULED
+ SKIPPED
+ SUCCESS
+}
+
+type Project {
+ """
+ Archived status of the project
+ """
+ archived: Boolean
+
+ """
+ URL to avatar image file of the project
+ """
+ avatarUrl: String
+
+ """
+ Indicates if the project stores Docker container images in a container registry
+ """
+ containerRegistryEnabled: Boolean
+
+ """
+ Timestamp of the project creation
+ """
+ createdAt: Time
+
+ """
+ Short description of the project
+ """
+ description: String
+
+ """
+ The GitLab Flavored Markdown rendering of `description`
+ """
+ descriptionHtml: String
+
+ """
+ Number of times the project has been forked
+ """
+ forksCount: Int!
+
+ """
+ Full path of the project
+ """
+ fullPath: ID!
+
+ """
+ Group of the project
+ """
+ group: Group
+
+ """
+ URL to connect to the project via HTTPS
+ """
+ httpUrlToRepo: String
+
+ """
+ ID of the project
+ """
+ id: ID!
+
+ """
+ Status of project import background job of the project
+ """
+ importStatus: String
+
+ """
+ A single issue of the project
+ """
+ issue(
+ """
+ Issues closed after this date
+ """
+ closedAfter: Time
+
+ """
+ Issues closed before this date
+ """
+ closedBefore: Time
+
+ """
+ Issues created after this date
+ """
+ createdAfter: Time
+
+ """
+ Issues created before this date
+ """
+ createdBefore: Time
+
+ """
+ The IID of the issue, e.g., "1"
+ """
+ iid: String
+
+ """
+ The list of IIDs of issues, e.g., [1, 2]
+ """
+ iids: [String!]
+
+ """
+ Labels applied to the Issue
+ """
+ labelName: [String]
+ search: String
+
+ """
+ Sort issues by this criteria
+ """
+ sort: IssueSort = created_desc
+
+ """
+ Current state of Issue
+ """
+ state: IssuableState
+
+ """
+ Issues updated after this date
+ """
+ updatedAfter: Time
+
+ """
+ Issues updated before this date
+ """
+ updatedBefore: Time
+ ): Issue
+
+ """
+ Issues of the project
+ """
+ issues(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Issues closed after this date
+ """
+ closedAfter: Time
+
+ """
+ Issues closed before this date
+ """
+ closedBefore: Time
+
+ """
+ Issues created after this date
+ """
+ createdAfter: Time
+
+ """
+ Issues created before this date
+ """
+ createdBefore: Time
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ The IID of the issue, e.g., "1"
+ """
+ iid: String
+
+ """
+ The list of IIDs of issues, e.g., [1, 2]
+ """
+ iids: [String!]
+
+ """
+ Labels applied to the Issue
+ """
+ labelName: [String]
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ search: String
+
+ """
+ Sort issues by this criteria
+ """
+ sort: IssueSort = created_desc
+
+ """
+ Current state of Issue
+ """
+ state: IssuableState
+
+ """
+ Issues updated after this date
+ """
+ updatedAfter: Time
+
+ """
+ Issues updated before this date
+ """
+ updatedBefore: Time
+ ): IssueConnection
+
+ """
+ (deprecated) Does this project have issues enabled?. Use `issues_access_level` instead
+ """
+ issuesEnabled: Boolean
+
+ """
+ (deprecated) Enable jobs for this project. Use `builds_access_level` instead
+ """
+ jobsEnabled: Boolean
+
+ """
+ Timestamp of the project last activity
+ """
+ lastActivityAt: Time
+
+ """
+ Indicates if the project has Large File Storage (LFS) enabled
+ """
+ lfsEnabled: Boolean
+
+ """
+ A single merge request of the project
+ """
+ mergeRequest(
+ """
+ The IID of the merge request, e.g., "1"
+ """
+ iid: String
+
+ """
+ The list of IIDs of issues, e.g., [1, 2]
+ """
+ iids: [String!]
+ ): MergeRequest
+
+ """
+ Merge requests of the project
+ """
+ mergeRequests(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ The IID of the merge request, e.g., "1"
+ """
+ iid: String
+
+ """
+ The list of IIDs of issues, e.g., [1, 2]
+ """
+ iids: [String!]
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): MergeRequestConnection
+
+ """
+ (deprecated) Does this project have merge_requests enabled?. Use `merge_requests_access_level` instead
+ """
+ mergeRequestsEnabled: Boolean
+
+ """
+ Indicates if no merge commits should be created and all merges should instead
+ be fast-forwarded, which means that merging is only allowed if the branch
+ could be fast-forwarded.
+ """
+ mergeRequestsFfOnlyEnabled: Boolean
+
+ """
+ Name of the project (without namespace)
+ """
+ name: String!
+
+ """
+ Full name of the project with its namespace
+ """
+ nameWithNamespace: String!
+
+ """
+ Namespace of the project
+ """
+ namespace: Namespace
+
+ """
+ Indicates if merge requests of the project can only be merged when all the discussions are resolved
+ """
+ onlyAllowMergeIfAllDiscussionsAreResolved: Boolean
+
+ """
+ Indicates if merge requests of the project can only be merged with successful jobs
+ """
+ onlyAllowMergeIfPipelineSucceeds: Boolean
+
+ """
+ Number of open issues for the project
+ """
+ openIssuesCount: Int
+
+ """
+ Path of the project
+ """
+ path: String!
+
+ """
+ Build pipelines of the project
+ """
+ pipelines(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+
+ """
+ Filter pipelines by the ref they are run for
+ """
+ ref: String
+
+ """
+ Filter pipelines by the sha of the commit they are run for
+ """
+ sha: String
+
+ """
+ Filter pipelines by their status
+ """
+ status: PipelineStatusEnum
+ ): PipelineConnection
+
+ """
+ Indicates if a link to create or view a merge request should display after a
+ push to Git repositories of the project from the command line
+ """
+ printingMergeRequestLinkEnabled: Boolean
+
+ """
+ Indicates if there is public access to pipelines and job details of the project, including output logs and artifacts
+ """
+ publicJobs: Boolean
+
+ """
+ Indicates if `Delete source branch` option should be enabled by default for all new merge requests of the project
+ """
+ removeSourceBranchAfterMerge: Boolean
+
+ """
+ Git repository of the project
+ """
+ repository: Repository
+
+ """
+ Indicates if users can request member access to the project
+ """
+ requestAccessEnabled: Boolean
+
+ """
+ Indicates if shared runners are enabled on the project
+ """
+ sharedRunnersEnabled: Boolean
+
+ """
+ (deprecated) Does this project have snippets enabled?. Use `snippets_access_level` instead
+ """
+ snippetsEnabled: Boolean
+
+ """
+ URL to connect to the project via SSH
+ """
+ sshUrlToRepo: String
+
+ """
+ Number of times the project has been starred
+ """
+ starCount: Int!
+
+ """
+ Statistics of the project
+ """
+ statistics: ProjectStatistics
+
+ """
+ List of project tags
+ """
+ tagList: String
+
+ """
+ Permissions for the current user on the resource
+ """
+ userPermissions: ProjectPermissions!
+
+ """
+ Visibility of the project
+ """
+ visibility: String
+
+ """
+ Web URL of the project
+ """
+ webUrl: String
+
+ """
+ (deprecated) Does this project have wiki enabled?. Use `wiki_access_level` instead
+ """
+ wikiEnabled: Boolean
+}
+
+"""
+The connection type for Project.
+"""
+type ProjectConnection {
+ """
+ A list of edges.
+ """
+ edges: [ProjectEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [Project]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+}
+
+"""
+An edge in a connection.
+"""
+type ProjectEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: Project
+}
+
+type ProjectPermissions {
+ """
+ Whether or not a user can perform `admin_operations` on this resource
+ """
+ adminOperations: Boolean!
+
+ """
+ Whether or not a user can perform `admin_project` on this resource
+ """
+ adminProject: Boolean!
+
+ """
+ Whether or not a user can perform `admin_remote_mirror` on this resource
+ """
+ adminRemoteMirror: Boolean!
+
+ """
+ Whether or not a user can perform `admin_wiki` on this resource
+ """
+ adminWiki: Boolean!
+
+ """
+ Whether or not a user can perform `archive_project` on this resource
+ """
+ archiveProject: Boolean!
+
+ """
+ Whether or not a user can perform `change_namespace` on this resource
+ """
+ changeNamespace: Boolean!
+
+ """
+ Whether or not a user can perform `change_visibility_level` on this resource
+ """
+ changeVisibilityLevel: Boolean!
+
+ """
+ Whether or not a user can perform `create_deployment` on this resource
+ """
+ createDeployment: Boolean!
+
+ """
+ Whether or not a user can perform `create_design` on this resource
+ """
+ createDesign: Boolean!
+
+ """
+ Whether or not a user can perform `create_issue` on this resource
+ """
+ createIssue: Boolean!
+
+ """
+ Whether or not a user can perform `create_label` on this resource
+ """
+ createLabel: Boolean!
+
+ """
+ Whether or not a user can perform `create_merge_request_from` on this resource
+ """
+ createMergeRequestFrom: Boolean!
+
+ """
+ Whether or not a user can perform `create_merge_request_in` on this resource
+ """
+ createMergeRequestIn: Boolean!
+
+ """
+ Whether or not a user can perform `create_pages` on this resource
+ """
+ createPages: Boolean!
+
+ """
+ Whether or not a user can perform `create_pipeline` on this resource
+ """
+ createPipeline: Boolean!
+
+ """
+ Whether or not a user can perform `create_pipeline_schedule` on this resource
+ """
+ createPipelineSchedule: Boolean!
+
+ """
+ Whether or not a user can perform `create_project_snippet` on this resource
+ """
+ createProjectSnippet: Boolean!
+
+ """
+ Whether or not a user can perform `create_wiki` on this resource
+ """
+ createWiki: Boolean!
+
+ """
+ Whether or not a user can perform `destroy_design` on this resource
+ """
+ destroyDesign: Boolean!
+
+ """
+ Whether or not a user can perform `destroy_pages` on this resource
+ """
+ destroyPages: Boolean!
+
+ """
+ Whether or not a user can perform `destroy_wiki` on this resource
+ """
+ destroyWiki: Boolean!
+
+ """
+ Whether or not a user can perform `download_code` on this resource
+ """
+ downloadCode: Boolean!
+
+ """
+ Whether or not a user can perform `download_wiki_code` on this resource
+ """
+ downloadWikiCode: Boolean!
+
+ """
+ Whether or not a user can perform `fork_project` on this resource
+ """
+ forkProject: Boolean!
+
+ """
+ Whether or not a user can perform `push_code` on this resource
+ """
+ pushCode: Boolean!
+
+ """
+ Whether or not a user can perform `push_to_delete_protected_branch` on this resource
+ """
+ pushToDeleteProtectedBranch: Boolean!
+
+ """
+ Whether or not a user can perform `read_commit_status` on this resource
+ """
+ readCommitStatus: Boolean!
+
+ """
+ Whether or not a user can perform `read_cycle_analytics` on this resource
+ """
+ readCycleAnalytics: Boolean!
+
+ """
+ Whether or not a user can perform `read_design` on this resource
+ """
+ readDesign: Boolean!
+
+ """
+ Whether or not a user can perform `read_pages_content` on this resource
+ """
+ readPagesContent: Boolean!
+
+ """
+ Whether or not a user can perform `read_project` on this resource
+ """
+ readProject: Boolean!
+
+ """
+ Whether or not a user can perform `read_project_member` on this resource
+ """
+ readProjectMember: Boolean!
+
+ """
+ Whether or not a user can perform `read_wiki` on this resource
+ """
+ readWiki: Boolean!
+
+ """
+ Whether or not a user can perform `remove_fork_project` on this resource
+ """
+ removeForkProject: Boolean!
+
+ """
+ Whether or not a user can perform `remove_pages` on this resource
+ """
+ removePages: Boolean!
+
+ """
+ Whether or not a user can perform `remove_project` on this resource
+ """
+ removeProject: Boolean!
+
+ """
+ Whether or not a user can perform `rename_project` on this resource
+ """
+ renameProject: Boolean!
+
+ """
+ Whether or not a user can perform `request_access` on this resource
+ """
+ requestAccess: Boolean!
+
+ """
+ Whether or not a user can perform `update_pages` on this resource
+ """
+ updatePages: Boolean!
+
+ """
+ Whether or not a user can perform `update_wiki` on this resource
+ """
+ updateWiki: Boolean!
+
+ """
+ Whether or not a user can perform `upload_file` on this resource
+ """
+ uploadFile: Boolean!
+}
+
+type ProjectStatistics {
+ """
+ Build artifacts size of the project
+ """
+ buildArtifactsSize: Int!
+
+ """
+ Commit count of the project
+ """
+ commitCount: Int!
+
+ """
+ Large File Storage (LFS) object size of the project
+ """
+ lfsObjectsSize: Int!
+
+ """
+ Packages size of the project
+ """
+ packagesSize: Int!
+
+ """
+ Repository size of the project
+ """
+ repositorySize: Int!
+
+ """
+ Storage size of the project
+ """
+ storageSize: Int!
+
+ """
+ Wiki size of the project
+ """
+ wikiSize: Int
+}
+
+type Query {
+ """
+ Get information about current user
+ """
+ currentUser: User
+
+ """
+ Testing endpoint to validate the API with
+ """
+ echo(text: String!): String!
+
+ """
+ Find a group
+ """
+ group(
+ """
+ The full path of the project, group or namespace, e.g., "gitlab-org/gitlab-foss"
+ """
+ fullPath: ID!
+ ): Group
+
+ """
+ Metadata about GitLab
+ """
+ metadata: Metadata
+
+ """
+ Find a namespace
+ """
+ namespace(
+ """
+ The full path of the project, group or namespace, e.g., "gitlab-org/gitlab-foss"
+ """
+ fullPath: ID!
+ ): Namespace
+
+ """
+ Find a project
+ """
+ project(
+ """
+ The full path of the project, group or namespace, e.g., "gitlab-org/gitlab-foss"
+ """
+ fullPath: ID!
+ ): Project
+}
+
+"""
+Autogenerated input type of RemoveAwardEmoji
+"""
+input RemoveAwardEmojiInput {
+ """
+ The global id of the awardable resource
+ """
+ awardableId: ID!
+
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The emoji name
+ """
+ name: String!
+}
+
+"""
+Autogenerated return type of RemoveAwardEmoji
+"""
+type RemoveAwardEmojiPayload {
+ """
+ The award emoji after mutation
+ """
+ awardEmoji: AwardEmoji
+
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Reasons why the mutation failed.
+ """
+ errors: [String!]!
+}
+
+type Repository {
+ """
+ Indicates repository has no visible content
+ """
+ empty: Boolean!
+
+ """
+ Indicates a corresponding Git repository exists on disk
+ """
+ exists: Boolean!
+
+ """
+ Default branch of the repository
+ """
+ rootRef: String
+
+ """
+ Tree of the repository
+ """
+ tree(
+ """
+ The path to get the tree for. Default value is the root of the repository
+ """
+ path: String = ""
+
+ """
+ Used to get a recursive tree. Default is false
+ """
+ recursive: Boolean = false
+
+ """
+ The commit ref to get the tree for. Default value is HEAD
+ """
+ ref: String = "head"
+ ): Tree
+}
+
+type RootStorageStatistics {
+ """
+ The CI artifacts size in bytes
+ """
+ buildArtifactsSize: Int!
+
+ """
+ The LFS objects size in bytes
+ """
+ lfsObjectsSize: Int!
+
+ """
+ The packages size in bytes
+ """
+ packagesSize: Int!
+
+ """
+ The git repository size in bytes
+ """
+ repositorySize: Int!
+
+ """
+ The total storage in bytes
+ """
+ storageSize: Int!
+
+ """
+ The wiki size in bytes
+ """
+ wikiSize: Int!
+}
+
+type Submodule implements Entry {
+ flatPath: String!
+ id: ID!
+ name: String!
+ path: String!
+
+ """
+ Last commit sha for entry
+ """
+ sha: String!
+ treeUrl: String
+ type: EntryType!
+ webUrl: String
+}
+
+"""
+The connection type for Submodule.
+"""
+type SubmoduleConnection {
+ """
+ A list of edges.
+ """
+ edges: [SubmoduleEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [Submodule]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+}
+
+"""
+An edge in a connection.
+"""
+type SubmoduleEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: Submodule
+}
+
+"""
+Completion status of tasks
+"""
+type TaskCompletionStatus {
+ """
+ Number of completed tasks
+ """
+ completedCount: Int!
+
+ """
+ Number of total tasks
+ """
+ count: Int!
+}
+
+"""
+Time represented in ISO 8601
+"""
+scalar Time
+
+"""
+Representing a todo entry
+"""
+type Todo {
+ """
+ Action of the todo
+ """
+ action: TodoActionEnum!
+
+ """
+ The owner of this todo
+ """
+ author: User!
+
+ """
+ Body of the todo
+ """
+ body: String!
+
+ """
+ Timestamp this todo was created
+ """
+ createdAt: Time!
+
+ """
+ Group this todo is associated with
+ """
+ group: Group
+
+ """
+ Id of the todo
+ """
+ id: ID!
+
+ """
+ The project this todo is associated with
+ """
+ project: Project
+
+ """
+ State of the todo
+ """
+ state: TodoStateEnum!
+
+ """
+ Target type of the todo
+ """
+ targetType: TodoTargetEnum!
+}
+
+enum TodoActionEnum {
+ approval_required
+ assigned
+ build_failed
+ directly_addressed
+ marked
+ mentioned
+ unmergeable
+}
+
+"""
+The connection type for Todo.
+"""
+type TodoConnection {
+ """
+ A list of edges.
+ """
+ edges: [TodoEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [Todo]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+}
+
+"""
+An edge in a connection.
+"""
+type TodoEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: Todo
+}
+
+"""
+Autogenerated input type of TodoMarkDone
+"""
+input TodoMarkDoneInput {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The global id of the todo to mark as done
+ """
+ id: ID!
+}
+
+"""
+Autogenerated return type of TodoMarkDone
+"""
+type TodoMarkDonePayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Reasons why the mutation failed.
+ """
+ errors: [String!]!
+
+ """
+ The requested todo
+ """
+ todo: Todo!
+}
+
+enum TodoStateEnum {
+ done
+ pending
+}
+
+enum TodoTargetEnum {
+ """
+ A Commit
+ """
+ COMMIT
+
+ """
+ A Design
+ """
+ DESIGN
+
+ """
+ An Epic
+ """
+ EPIC
+
+ """
+ An Issue
+ """
+ ISSUE
+
+ """
+ A MergeRequest
+ """
+ MERGEREQUEST
+}
+
+"""
+Autogenerated input type of ToggleAwardEmoji
+"""
+input ToggleAwardEmojiInput {
+ """
+ The global id of the awardable resource
+ """
+ awardableId: ID!
+
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The emoji name
+ """
+ name: String!
+}
+
+"""
+Autogenerated return type of ToggleAwardEmoji
+"""
+type ToggleAwardEmojiPayload {
+ """
+ The award emoji after mutation
+ """
+ awardEmoji: AwardEmoji
+
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Reasons why the mutation failed.
+ """
+ errors: [String!]!
+
+ """
+ True when the emoji was awarded, false when it was removed
+ """
+ toggledOn: Boolean!
+}
+
+type Tree {
+ blobs(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): BlobConnection!
+
+ """
+ Last commit for the tree
+ """
+ lastCommit: Commit
+ submodules(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): SubmoduleConnection!
+ trees(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): TreeEntryConnection!
+}
+
+"""
+Represents a directory
+"""
+type TreeEntry implements Entry {
+ flatPath: String!
+ id: ID!
+ name: String!
+ path: String!
+
+ """
+ Last commit sha for entry
+ """
+ sha: String!
+ type: EntryType!
+ webUrl: String
+}
+
+"""
+The connection type for TreeEntry.
+"""
+type TreeEntryConnection {
+ """
+ A list of edges.
+ """
+ edges: [TreeEntryEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [TreeEntry]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+}
+
+"""
+An edge in a connection.
+"""
+type TreeEntryEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: TreeEntry
+}
+
+"""
+Autogenerated input type of UpdateEpic
+"""
+input UpdateEpicInput {
+ """
+ The IDs of labels to be added to the epic.
+ """
+ addLabelIds: [ID!]
+
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The description of the epic
+ """
+ description: String
+
+ """
+ The end date of the epic
+ """
+ dueDateFixed: String
+
+ """
+ Indicates end date should be sourced from due_date_fixed field not the issue milestones
+ """
+ dueDateIsFixed: Boolean
+
+ """
+ The group the epic to mutate is in
+ """
+ groupPath: ID!
+
+ """
+ The iid of the epic to mutate
+ """
+ iid: String!
+
+ """
+ The IDs of labels to be removed from the epic.
+ """
+ removeLabelIds: [ID!]
+
+ """
+ The start date of the epic
+ """
+ startDateFixed: String
+
+ """
+ Indicates start date should be sourced from start_date_fixed field not the issue milestones
+ """
+ startDateIsFixed: Boolean
+
+ """
+ State event for the epic
+ """
+ stateEvent: EpicStateEvent
+
+ """
+ The title of the epic
+ """
+ title: String
+}
+
+"""
+Autogenerated return type of UpdateEpic
+"""
+type UpdateEpicPayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The epic after mutation
+ """
+ epic: Epic
+
+ """
+ Reasons why the mutation failed.
+ """
+ errors: [String!]!
+}
+
+"""
+Autogenerated input type of UpdateNote
+"""
+input UpdateNoteInput {
+ """
+ The content note itself
+ """
+ body: String!
+
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The global id of the note to update
+ """
+ id: ID!
+}
+
+"""
+Autogenerated return type of UpdateNote
+"""
+type UpdateNotePayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Reasons why the mutation failed.
+ """
+ errors: [String!]!
+
+ """
+ The note after mutation
+ """
+ note: Note
+}
+
+scalar Upload
+
+type User {
+ """
+ URL of the user's avatar
+ """
+ avatarUrl: String!
+
+ """
+ Human-readable name of the user
+ """
+ name: String!
+
+ """
+ Todos of the user
+ """
+ todos(
+ """
+ The action to be filtered
+ """
+ action: [TodoActionEnum!]
+
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ The ID of an author
+ """
+ authorId: [ID!]
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ The ID of a group
+ """
+ groupId: [ID!]
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+
+ """
+ The ID of a project
+ """
+ projectId: [ID!]
+
+ """
+ The state of the todo
+ """
+ state: [TodoStateEnum!]
+
+ """
+ The type of the todo
+ """
+ type: [TodoTargetEnum!]
+ ): TodoConnection!
+
+ """
+ Username of the user. Unique within this instance of GitLab
+ """
+ username: String!
+
+ """
+ Web URL of the user
+ """
+ webUrl: String!
+}
+
+"""
+The connection type for User.
+"""
+type UserConnection {
+ """
+ A list of edges.
+ """
+ edges: [UserEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [User]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+}
+
+"""
+An edge in a connection.
+"""
+type UserEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: User
+} \ No newline at end of file
diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json
new file mode 100644
index 00000000000..fea67f28d69
--- /dev/null
+++ b/doc/api/graphql/reference/gitlab_schema.json
@@ -0,0 +1,18749 @@
+{
+ "data": {
+ "__schema": {
+ "queryType": {
+ "name": "Query"
+ },
+ "mutationType": {
+ "name": "Mutation"
+ },
+ "subscriptionType": null,
+ "types": [
+ {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "description": "Represents `true` or `false` values.",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "SCALAR",
+ "name": "String",
+ "description": "Represents textual data as UTF-8 character sequences. This type is most often used by GraphQL to represent free-form human-readable text.",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "Query",
+ "description": null,
+ "fields": [
+ {
+ "name": "currentUser",
+ "description": "Get information about current user",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "User",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "echo",
+ "description": "Testing endpoint to validate the API with",
+ "args": [
+ {
+ "name": "text",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "group",
+ "description": "Find a group",
+ "args": [
+ {
+ "name": "fullPath",
+ "description": "The full path of the project, group or namespace, e.g., \"gitlab-org/gitlab-foss\"",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Group",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "metadata",
+ "description": "Metadata about GitLab",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Metadata",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "namespace",
+ "description": "Find a namespace",
+ "args": [
+ {
+ "name": "fullPath",
+ "description": "The full path of the project, group or namespace, e.g., \"gitlab-org/gitlab-foss\"",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Namespace",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "project",
+ "description": "Find a project",
+ "args": [
+ {
+ "name": "fullPath",
+ "description": "The full path of the project, group or namespace, e.g., \"gitlab-org/gitlab-foss\"",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Project",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "Project",
+ "description": null,
+ "fields": [
+ {
+ "name": "archived",
+ "description": "Archived status of the project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "avatarUrl",
+ "description": "URL to avatar image file of the project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "containerRegistryEnabled",
+ "description": "Indicates if the project stores Docker container images in a container registry",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createdAt",
+ "description": "Timestamp of the project creation",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "description",
+ "description": "Short description of the project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "descriptionHtml",
+ "description": "The GitLab Flavored Markdown rendering of `description`",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "forksCount",
+ "description": "Number of times the project has been forked",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "fullPath",
+ "description": "Full path of the project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "group",
+ "description": "Group of the project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Group",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "httpUrlToRepo",
+ "description": "URL to connect to the project via HTTPS",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": "ID of the project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "importStatus",
+ "description": "Status of project import background job of the project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "issue",
+ "description": "A single issue of the project",
+ "args": [
+ {
+ "name": "iid",
+ "description": "The IID of the issue, e.g., \"1\"",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "iids",
+ "description": "The list of IIDs of issues, e.g., [1, 2]",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "state",
+ "description": "Current state of Issue",
+ "type": {
+ "kind": "ENUM",
+ "name": "IssuableState",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "labelName",
+ "description": "Labels applied to the Issue",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "createdBefore",
+ "description": "Issues created before this date",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "createdAfter",
+ "description": "Issues created after this date",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "updatedBefore",
+ "description": "Issues updated before this date",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "updatedAfter",
+ "description": "Issues updated after this date",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "closedBefore",
+ "description": "Issues closed before this date",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "closedAfter",
+ "description": "Issues closed after this date",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "search",
+ "description": null,
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "sort",
+ "description": "Sort issues by this criteria",
+ "type": {
+ "kind": "ENUM",
+ "name": "IssueSort",
+ "ofType": null
+ },
+ "defaultValue": "created_desc"
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Issue",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "issues",
+ "description": "Issues of the project",
+ "args": [
+ {
+ "name": "iid",
+ "description": "The IID of the issue, e.g., \"1\"",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "iids",
+ "description": "The list of IIDs of issues, e.g., [1, 2]",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "state",
+ "description": "Current state of Issue",
+ "type": {
+ "kind": "ENUM",
+ "name": "IssuableState",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "labelName",
+ "description": "Labels applied to the Issue",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "createdBefore",
+ "description": "Issues created before this date",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "createdAfter",
+ "description": "Issues created after this date",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "updatedBefore",
+ "description": "Issues updated before this date",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "updatedAfter",
+ "description": "Issues updated after this date",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "closedBefore",
+ "description": "Issues closed before this date",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "closedAfter",
+ "description": "Issues closed after this date",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "search",
+ "description": null,
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "sort",
+ "description": "Sort issues by this criteria",
+ "type": {
+ "kind": "ENUM",
+ "name": "IssueSort",
+ "ofType": null
+ },
+ "defaultValue": "created_desc"
+ },
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "IssueConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "issuesEnabled",
+ "description": "(deprecated) Does this project have issues enabled?. Use `issues_access_level` instead",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "jobsEnabled",
+ "description": "(deprecated) Enable jobs for this project. Use `builds_access_level` instead",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "lastActivityAt",
+ "description": "Timestamp of the project last activity",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "lfsEnabled",
+ "description": "Indicates if the project has Large File Storage (LFS) enabled",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mergeRequest",
+ "description": "A single merge request of the project",
+ "args": [
+ {
+ "name": "iid",
+ "description": "The IID of the merge request, e.g., \"1\"",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "iids",
+ "description": "The list of IIDs of issues, e.g., [1, 2]",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "MergeRequest",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mergeRequests",
+ "description": "Merge requests of the project",
+ "args": [
+ {
+ "name": "iid",
+ "description": "The IID of the merge request, e.g., \"1\"",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "iids",
+ "description": "The list of IIDs of issues, e.g., [1, 2]",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "MergeRequestConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mergeRequestsEnabled",
+ "description": "(deprecated) Does this project have merge_requests enabled?. Use `merge_requests_access_level` instead",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mergeRequestsFfOnlyEnabled",
+ "description": "Indicates if no merge commits should be created and all merges should instead be fast-forwarded, which means that merging is only allowed if the branch could be fast-forwarded.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "name",
+ "description": "Name of the project (without namespace)",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nameWithNamespace",
+ "description": "Full name of the project with its namespace",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "namespace",
+ "description": "Namespace of the project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Namespace",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "onlyAllowMergeIfAllDiscussionsAreResolved",
+ "description": "Indicates if merge requests of the project can only be merged when all the discussions are resolved",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "onlyAllowMergeIfPipelineSucceeds",
+ "description": "Indicates if merge requests of the project can only be merged with successful jobs",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "openIssuesCount",
+ "description": "Number of open issues for the project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "path",
+ "description": "Path of the project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pipelines",
+ "description": "Build pipelines of the project",
+ "args": [
+ {
+ "name": "status",
+ "description": "Filter pipelines by their status",
+ "type": {
+ "kind": "ENUM",
+ "name": "PipelineStatusEnum",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "ref",
+ "description": "Filter pipelines by the ref they are run for",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "sha",
+ "description": "Filter pipelines by the sha of the commit they are run for",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "PipelineConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "printingMergeRequestLinkEnabled",
+ "description": "Indicates if a link to create or view a merge request should display after a push to Git repositories of the project from the command line",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "publicJobs",
+ "description": "Indicates if there is public access to pipelines and job details of the project, including output logs and artifacts",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "removeSourceBranchAfterMerge",
+ "description": "Indicates if `Delete source branch` option should be enabled by default for all new merge requests of the project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "repository",
+ "description": "Git repository of the project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Repository",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "requestAccessEnabled",
+ "description": "Indicates if users can request member access to the project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "sharedRunnersEnabled",
+ "description": "Indicates if shared runners are enabled on the project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "snippetsEnabled",
+ "description": "(deprecated) Does this project have snippets enabled?. Use `snippets_access_level` instead",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "sshUrlToRepo",
+ "description": "URL to connect to the project via SSH",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "starCount",
+ "description": "Number of times the project has been starred",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "statistics",
+ "description": "Statistics of the project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "ProjectStatistics",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "tagList",
+ "description": "List of project tags",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "userPermissions",
+ "description": "Permissions for the current user on the resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "ProjectPermissions",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "visibility",
+ "description": "Visibility of the project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "webUrl",
+ "description": "Web URL of the project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "wikiEnabled",
+ "description": "(deprecated) Does this project have wiki enabled?. Use `wiki_access_level` instead",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "ProjectPermissions",
+ "description": null,
+ "fields": [
+ {
+ "name": "adminOperations",
+ "description": "Whether or not a user can perform `admin_operations` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "adminProject",
+ "description": "Whether or not a user can perform `admin_project` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "adminRemoteMirror",
+ "description": "Whether or not a user can perform `admin_remote_mirror` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "adminWiki",
+ "description": "Whether or not a user can perform `admin_wiki` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "archiveProject",
+ "description": "Whether or not a user can perform `archive_project` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "changeNamespace",
+ "description": "Whether or not a user can perform `change_namespace` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "changeVisibilityLevel",
+ "description": "Whether or not a user can perform `change_visibility_level` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createDeployment",
+ "description": "Whether or not a user can perform `create_deployment` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createDesign",
+ "description": "Whether or not a user can perform `create_design` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createIssue",
+ "description": "Whether or not a user can perform `create_issue` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createLabel",
+ "description": "Whether or not a user can perform `create_label` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createMergeRequestFrom",
+ "description": "Whether or not a user can perform `create_merge_request_from` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createMergeRequestIn",
+ "description": "Whether or not a user can perform `create_merge_request_in` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createPages",
+ "description": "Whether or not a user can perform `create_pages` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createPipeline",
+ "description": "Whether or not a user can perform `create_pipeline` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createPipelineSchedule",
+ "description": "Whether or not a user can perform `create_pipeline_schedule` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createProjectSnippet",
+ "description": "Whether or not a user can perform `create_project_snippet` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createWiki",
+ "description": "Whether or not a user can perform `create_wiki` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "destroyDesign",
+ "description": "Whether or not a user can perform `destroy_design` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "destroyPages",
+ "description": "Whether or not a user can perform `destroy_pages` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "destroyWiki",
+ "description": "Whether or not a user can perform `destroy_wiki` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "downloadCode",
+ "description": "Whether or not a user can perform `download_code` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "downloadWikiCode",
+ "description": "Whether or not a user can perform `download_wiki_code` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "forkProject",
+ "description": "Whether or not a user can perform `fork_project` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pushCode",
+ "description": "Whether or not a user can perform `push_code` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pushToDeleteProtectedBranch",
+ "description": "Whether or not a user can perform `push_to_delete_protected_branch` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "readCommitStatus",
+ "description": "Whether or not a user can perform `read_commit_status` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "readCycleAnalytics",
+ "description": "Whether or not a user can perform `read_cycle_analytics` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "readDesign",
+ "description": "Whether or not a user can perform `read_design` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "readPagesContent",
+ "description": "Whether or not a user can perform `read_pages_content` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "readProject",
+ "description": "Whether or not a user can perform `read_project` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "readProjectMember",
+ "description": "Whether or not a user can perform `read_project_member` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "readWiki",
+ "description": "Whether or not a user can perform `read_wiki` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "removeForkProject",
+ "description": "Whether or not a user can perform `remove_fork_project` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "removePages",
+ "description": "Whether or not a user can perform `remove_pages` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "removeProject",
+ "description": "Whether or not a user can perform `remove_project` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "renameProject",
+ "description": "Whether or not a user can perform `rename_project` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "requestAccess",
+ "description": "Whether or not a user can perform `request_access` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "updatePages",
+ "description": "Whether or not a user can perform `update_pages` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "updateWiki",
+ "description": "Whether or not a user can perform `update_wiki` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "uploadFile",
+ "description": "Whether or not a user can perform `upload_file` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "SCALAR",
+ "name": "ID",
+ "description": "Represents a unique identifier that is Base64 obfuscated. It is often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"VXNlci0xMA==\"`) or integer (such as `4`) input value will be accepted as an ID.",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "SCALAR",
+ "name": "Int",
+ "description": "Represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "SCALAR",
+ "name": "Time",
+ "description": "Time represented in ISO 8601",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "Namespace",
+ "description": null,
+ "fields": [
+ {
+ "name": "description",
+ "description": "Description of the namespace",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "descriptionHtml",
+ "description": "The GitLab Flavored Markdown rendering of `description`",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "fullName",
+ "description": "Full name of the namespace",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "fullPath",
+ "description": "Full path of the namespace",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": "ID of the namespace",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "lfsEnabled",
+ "description": "Indicates if Large File Storage (LFS) is enabled for namespace",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "name",
+ "description": "Name of the namespace",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "path",
+ "description": "Path of the namespace",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "projects",
+ "description": "Projects within this namespace",
+ "args": [
+ {
+ "name": "includeSubgroups",
+ "description": "Include also subgroup projects",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": "false"
+ },
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "ProjectConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "requestAccessEnabled",
+ "description": "Indicates if users can request access to namespace",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "rootStorageStatistics",
+ "description": "Aggregated storage statistics of the namespace. Only available for root namespaces",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "RootStorageStatistics",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "visibility",
+ "description": "Visibility of the namespace",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "RootStorageStatistics",
+ "description": null,
+ "fields": [
+ {
+ "name": "buildArtifactsSize",
+ "description": "The CI artifacts size in bytes",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "lfsObjectsSize",
+ "description": "The LFS objects size in bytes",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "packagesSize",
+ "description": "The packages size in bytes",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "repositorySize",
+ "description": "The git repository size in bytes",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "storageSize",
+ "description": "The total storage in bytes",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "wikiSize",
+ "description": "The wiki size in bytes",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "ProjectConnection",
+ "description": "The connection type for Project.",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "ProjectEdge",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "Project",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "description": "Information about pagination in a connection.",
+ "fields": [
+ {
+ "name": "endCursor",
+ "description": "When paginating forwards, the cursor to continue.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "hasNextPage",
+ "description": "When paginating forwards, are there more items?",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "hasPreviousPage",
+ "description": "When paginating backwards, are there more items?",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "startCursor",
+ "description": "When paginating backwards, the cursor to continue.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "ProjectEdge",
+ "description": "An edge in a connection.",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Project",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "Group",
+ "description": null,
+ "fields": [
+ {
+ "name": "avatarUrl",
+ "description": "Avatar URL of the group",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "description",
+ "description": "Description of the namespace",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "descriptionHtml",
+ "description": "The GitLab Flavored Markdown rendering of `description`",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "epic",
+ "description": null,
+ "args": [
+ {
+ "name": "iid",
+ "description": "The IID of the epic, e.g., \"1\"",
+ "type": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "iids",
+ "description": "The list of IIDs of epics, e.g., [1, 2]",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "state",
+ "description": "Filter epics by state",
+ "type": {
+ "kind": "ENUM",
+ "name": "EpicState",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "search",
+ "description": "Filter epics by title and description",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "sort",
+ "description": "List epics by sort order",
+ "type": {
+ "kind": "ENUM",
+ "name": "EpicSort",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "authorUsername",
+ "description": "Filter epics by author",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "labelName",
+ "description": "Filter epics by labels",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "startDate",
+ "description": "List epics within a time frame where epics.start_date is between start_date and end_date parameters (end_date parameter must be present)",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "endDate",
+ "description": "List epics within a time frame where epics.end_date is between start_date and end_date parameters (start_date parameter must be present)",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Epic",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "epics",
+ "description": null,
+ "args": [
+ {
+ "name": "iid",
+ "description": "The IID of the epic, e.g., \"1\"",
+ "type": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "iids",
+ "description": "The list of IIDs of epics, e.g., [1, 2]",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "state",
+ "description": "Filter epics by state",
+ "type": {
+ "kind": "ENUM",
+ "name": "EpicState",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "search",
+ "description": "Filter epics by title and description",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "sort",
+ "description": "List epics by sort order",
+ "type": {
+ "kind": "ENUM",
+ "name": "EpicSort",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "authorUsername",
+ "description": "Filter epics by author",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "labelName",
+ "description": "Filter epics by labels",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "startDate",
+ "description": "List epics within a time frame where epics.start_date is between start_date and end_date parameters (end_date parameter must be present)",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "endDate",
+ "description": "List epics within a time frame where epics.end_date is between start_date and end_date parameters (start_date parameter must be present)",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "EpicConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "epicsEnabled",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "fullName",
+ "description": "Full name of the namespace",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "fullPath",
+ "description": "Full path of the namespace",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": "ID of the namespace",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "lfsEnabled",
+ "description": "Indicates if Large File Storage (LFS) is enabled for namespace",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "name",
+ "description": "Name of the namespace",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "parent",
+ "description": "Parent group",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Group",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "path",
+ "description": "Path of the namespace",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "projects",
+ "description": "Projects within this namespace",
+ "args": [
+ {
+ "name": "includeSubgroups",
+ "description": "Include also subgroup projects",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": "false"
+ },
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "ProjectConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "requestAccessEnabled",
+ "description": "Indicates if users can request access to namespace",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "rootStorageStatistics",
+ "description": "Aggregated storage statistics of the namespace. Only available for root namespaces",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "RootStorageStatistics",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "userPermissions",
+ "description": "Permissions for the current user on the resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "GroupPermissions",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "visibility",
+ "description": "Visibility of the namespace",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "webUrl",
+ "description": "Web URL of the group",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "GroupPermissions",
+ "description": null,
+ "fields": [
+ {
+ "name": "readGroup",
+ "description": "Whether or not a user can perform `read_group` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "Epic",
+ "description": null,
+ "fields": [
+ {
+ "name": "author",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "User",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "children",
+ "description": null,
+ "args": [
+ {
+ "name": "iid",
+ "description": "The IID of the epic, e.g., \"1\"",
+ "type": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "iids",
+ "description": "The list of IIDs of epics, e.g., [1, 2]",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "state",
+ "description": "Filter epics by state",
+ "type": {
+ "kind": "ENUM",
+ "name": "EpicState",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "search",
+ "description": "Filter epics by title and description",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "sort",
+ "description": "List epics by sort order",
+ "type": {
+ "kind": "ENUM",
+ "name": "EpicSort",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "authorUsername",
+ "description": "Filter epics by author",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "labelName",
+ "description": "Filter epics by labels",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "startDate",
+ "description": "List epics within a time frame where epics.start_date is between start_date and end_date parameters (end_date parameter must be present)",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "endDate",
+ "description": "List epics within a time frame where epics.end_date is between start_date and end_date parameters (start_date parameter must be present)",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "EpicConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "closedAt",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createdAt",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "descendantCounts",
+ "description": "Number of open and closed descendant epics and issues",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "EpicDescendantCount",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "description",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "discussions",
+ "description": "All discussions on this noteable",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "DiscussionConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "dueDate",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "dueDateFixed",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "dueDateFromMilestones",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "dueDateIsFixed",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "group",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "Group",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "hasChildren",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "hasIssues",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "iid",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "issues",
+ "description": "A list of issues associated with the epic",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "EpicIssueConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "labels",
+ "description": "Labels assigned to the epic",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "LabelConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "notes",
+ "description": "All notes on this noteable",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "NoteConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "parent",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Epic",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "participants",
+ "description": "List of participants for the epic",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "UserConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "reference",
+ "description": null,
+ "args": [
+ {
+ "name": "full",
+ "description": null,
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": "false"
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "relationPath",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "relativePosition",
+ "description": "The relative position of the epic in the Epic tree",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "startDate",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "startDateFixed",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "startDateFromMilestones",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "startDateIsFixed",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "state",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "ENUM",
+ "name": "EpicState",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "subscribed",
+ "description": "Boolean flag for whether the currently logged in user is subscribed to this epic",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "title",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "updatedAt",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "userPermissions",
+ "description": "Permissions for the current user on the resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "EpicPermissions",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "webPath",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "webUrl",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+ {
+ "kind": "INTERFACE",
+ "name": "Noteable",
+ "ofType": null
+ }
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INTERFACE",
+ "name": "Noteable",
+ "description": null,
+ "fields": [
+ {
+ "name": "discussions",
+ "description": "All discussions on this noteable",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "DiscussionConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "notes",
+ "description": "All notes on this noteable",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "NoteConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": [
+ {
+ "kind": "OBJECT",
+ "name": "Design",
+ "ofType": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "Epic",
+ "ofType": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "EpicIssue",
+ "ofType": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "Issue",
+ "ofType": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "MergeRequest",
+ "ofType": null
+ }
+ ]
+ },
+ {
+ "kind": "OBJECT",
+ "name": "NoteConnection",
+ "description": "The connection type for Note.",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "NoteEdge",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "Note",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "NoteEdge",
+ "description": "An edge in a connection.",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Note",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "Note",
+ "description": null,
+ "fields": [
+ {
+ "name": "author",
+ "description": "The user who wrote this note",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "User",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "body",
+ "description": "The content note itself",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "bodyHtml",
+ "description": "The GitLab Flavored Markdown rendering of `note`",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createdAt",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "discussion",
+ "description": "The discussion this note is a part of",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Discussion",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "position",
+ "description": "The position of this note on a diff",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "DiffPosition",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "project",
+ "description": "The project this note is associated to",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Project",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "resolvable",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "resolvedAt",
+ "description": "The time the discussion was resolved",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "resolvedBy",
+ "description": "The user that resolved the discussion",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "User",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "system",
+ "description": "Whether or not this note was created by the system or by a user",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "updatedAt",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "userPermissions",
+ "description": "Permissions for the current user on the resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "NotePermissions",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "NotePermissions",
+ "description": null,
+ "fields": [
+ {
+ "name": "adminNote",
+ "description": "Whether or not a user can perform `admin_note` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "awardEmoji",
+ "description": "Whether or not a user can perform `award_emoji` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createNote",
+ "description": "Whether or not a user can perform `create_note` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "readNote",
+ "description": "Whether or not a user can perform `read_note` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "resolveNote",
+ "description": "Whether or not a user can perform `resolve_note` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "User",
+ "description": null,
+ "fields": [
+ {
+ "name": "avatarUrl",
+ "description": "URL of the user's avatar",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "name",
+ "description": "Human-readable name of the user",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "todos",
+ "description": "Todos of the user",
+ "args": [
+ {
+ "name": "action",
+ "description": "The action to be filtered",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "ENUM",
+ "name": "TodoActionEnum",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "authorId",
+ "description": "The ID of an author",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "projectId",
+ "description": "The ID of a project",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "groupId",
+ "description": "The ID of a group",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "state",
+ "description": "The state of the todo",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "ENUM",
+ "name": "TodoStateEnum",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "type",
+ "description": "The type of the todo",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "ENUM",
+ "name": "TodoTargetEnum",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "TodoConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "username",
+ "description": "Username of the user. Unique within this instance of GitLab",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "webUrl",
+ "description": "Web URL of the user",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "TodoConnection",
+ "description": "The connection type for Todo.",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "TodoEdge",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "Todo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "TodoEdge",
+ "description": "An edge in a connection.",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Todo",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "Todo",
+ "description": "Representing a todo entry",
+ "fields": [
+ {
+ "name": "action",
+ "description": "Action of the todo",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "ENUM",
+ "name": "TodoActionEnum",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "author",
+ "description": "The owner of this todo",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "User",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "body",
+ "description": "Body of the todo",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createdAt",
+ "description": "Timestamp this todo was created",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "group",
+ "description": "Group this todo is associated with",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Group",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": "Id of the todo",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "project",
+ "description": "The project this todo is associated with",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Project",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "state",
+ "description": "State of the todo",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "ENUM",
+ "name": "TodoStateEnum",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "targetType",
+ "description": "Target type of the todo",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "ENUM",
+ "name": "TodoTargetEnum",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "ENUM",
+ "name": "TodoActionEnum",
+ "description": null,
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": [
+ {
+ "name": "assigned",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mentioned",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "build_failed",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "marked",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "approval_required",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "unmergeable",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "directly_addressed",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "possibleTypes": null
+ },
+ {
+ "kind": "ENUM",
+ "name": "TodoTargetEnum",
+ "description": null,
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": [
+ {
+ "name": "COMMIT",
+ "description": "A Commit",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "ISSUE",
+ "description": "An Issue",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "MERGEREQUEST",
+ "description": "A MergeRequest",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "DESIGN",
+ "description": "A Design",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "EPIC",
+ "description": "An Epic",
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "possibleTypes": null
+ },
+ {
+ "kind": "ENUM",
+ "name": "TodoStateEnum",
+ "description": null,
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": [
+ {
+ "name": "pending",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "done",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "Discussion",
+ "description": null,
+ "fields": [
+ {
+ "name": "createdAt",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "notes",
+ "description": "All notes in the discussion",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "NoteConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "replyId",
+ "description": "The ID used to reply to this discussion",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "DiffPosition",
+ "description": null,
+ "fields": [
+ {
+ "name": "diffRefs",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "DiffRefs",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "filePath",
+ "description": "The path of the file that was changed",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "height",
+ "description": "The total height of the image",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "newLine",
+ "description": "The line on head sha that was changed",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "newPath",
+ "description": "The path of the file on the head sha.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "oldLine",
+ "description": "The line on start sha that was changed",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "oldPath",
+ "description": "The path of the file on the start sha.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "positionType",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "ENUM",
+ "name": "DiffPositionType",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "width",
+ "description": "The total width of the image",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "x",
+ "description": "The X postion on which the comment was made",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "y",
+ "description": "The Y position on which the comment was made",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "DiffRefs",
+ "description": null,
+ "fields": [
+ {
+ "name": "baseSha",
+ "description": "The merge base of the branch the comment was made on",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "headSha",
+ "description": "The sha of the head at the time the comment was made",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "startSha",
+ "description": "The sha of the branch being compared against",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "ENUM",
+ "name": "DiffPositionType",
+ "description": "Type of file the position refers to",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": [
+ {
+ "name": "text",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "image",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "DiscussionConnection",
+ "description": "The connection type for Discussion.",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "DiscussionEdge",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "Discussion",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "DiscussionEdge",
+ "description": "An edge in a connection.",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Discussion",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "EpicPermissions",
+ "description": "Check permissions for the current user on an epic",
+ "fields": [
+ {
+ "name": "adminEpic",
+ "description": "Whether or not a user can perform `admin_epic` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "awardEmoji",
+ "description": "Whether or not a user can perform `award_emoji` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createEpic",
+ "description": "Whether or not a user can perform `create_epic` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createNote",
+ "description": "Whether or not a user can perform `create_note` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "destroyEpic",
+ "description": "Whether or not a user can perform `destroy_epic` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "readEpic",
+ "description": "Whether or not a user can perform `read_epic` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "readEpicIid",
+ "description": "Whether or not a user can perform `read_epic_iid` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "updateEpic",
+ "description": "Whether or not a user can perform `update_epic` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "ENUM",
+ "name": "EpicState",
+ "description": "State of a GitLab epic",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": [
+ {
+ "name": "all",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "opened",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "closed",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "EpicConnection",
+ "description": "The connection type for Epic.",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "EpicEdge",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "Epic",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "EpicEdge",
+ "description": "An edge in a connection.",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Epic",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "ENUM",
+ "name": "EpicSort",
+ "description": "Roadmap sort values",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": [
+ {
+ "name": "start_date_desc",
+ "description": "Start date at descending order",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "start_date_asc",
+ "description": "Start date at ascending order",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "end_date_desc",
+ "description": "End date at descending order",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "end_date_asc",
+ "description": "End date at ascending order",
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "LabelConnection",
+ "description": "The connection type for Label.",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "LabelEdge",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "Label",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "LabelEdge",
+ "description": "An edge in a connection.",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Label",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "Label",
+ "description": null,
+ "fields": [
+ {
+ "name": "color",
+ "description": "Background color of the label",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "description",
+ "description": "Description of the label (markdown rendered as HTML for caching)",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "descriptionHtml",
+ "description": "The GitLab Flavored Markdown rendering of `description`",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": "Label ID",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "textColor",
+ "description": "Text color of the label",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "title",
+ "description": "Content of the label",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "UserConnection",
+ "description": "The connection type for User.",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "UserEdge",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "User",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "UserEdge",
+ "description": "An edge in a connection.",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "User",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "EpicIssueConnection",
+ "description": "The connection type for EpicIssue.",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "EpicIssueEdge",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "EpicIssue",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "EpicIssueEdge",
+ "description": "An edge in a connection.",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "EpicIssue",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "EpicIssue",
+ "description": null,
+ "fields": [
+ {
+ "name": "assignees",
+ "description": "Assignees of the issue",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "UserConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "author",
+ "description": "User that created the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "User",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "closedAt",
+ "description": "Timestamp of when the issue was closed",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "confidential",
+ "description": "Indicates the issue is confidential",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createdAt",
+ "description": "Timestamp of when the issue was created",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "description",
+ "description": "Description of the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "descriptionHtml",
+ "description": "The GitLab Flavored Markdown rendering of `description`",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "designCollection",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "DesignCollection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "designs",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "DesignCollection",
+ "ofType": null
+ },
+ "isDeprecated": true,
+ "deprecationReason": "use design_collection"
+ },
+ {
+ "name": "discussionLocked",
+ "description": "Indicates discussion is locked on the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "discussions",
+ "description": "All discussions on this noteable",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "DiscussionConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "downvotes",
+ "description": "Number of downvotes the issue has received",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "dueDate",
+ "description": "Due date of the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "epic",
+ "description": "The epic to which issue belongs",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Epic",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "epicIssueId",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": "The global id of the epic-issue relation",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "iid",
+ "description": "Internal ID of the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "labels",
+ "description": "Labels of the issue",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "LabelConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "milestone",
+ "description": "Milestone of the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Milestone",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "notes",
+ "description": "All notes on this noteable",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "NoteConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "participants",
+ "description": "List of participants in the issue",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "UserConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "reference",
+ "description": "Internal reference of the issue. Returned in shortened format by default",
+ "args": [
+ {
+ "name": "full",
+ "description": "Boolean option specifying whether the reference should be returned in full",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": "false"
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "relationPath",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "relativePosition",
+ "description": "Relative position of the issue (used for positioning in epic tree and issue boards)",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "state",
+ "description": "State of the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "ENUM",
+ "name": "IssueState",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "subscribed",
+ "description": "Boolean flag for whether the currently logged in user is subscribed to this issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "taskCompletionStatus",
+ "description": "Task completion status of the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "TaskCompletionStatus",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "timeEstimate",
+ "description": "Time estimate of the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "title",
+ "description": "Title of the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "titleHtml",
+ "description": "The GitLab Flavored Markdown rendering of `title`",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "totalTimeSpent",
+ "description": "Total time reported as spent on the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "updatedAt",
+ "description": "Timestamp of when the issue was last updated",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "upvotes",
+ "description": "Number of upvotes the issue has received",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "userNotesCount",
+ "description": "Number of user notes of the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "userPermissions",
+ "description": "Permissions for the current user on the resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "IssuePermissions",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "webPath",
+ "description": "Web path of the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "webUrl",
+ "description": "Web URL of the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "weight",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+ {
+ "kind": "INTERFACE",
+ "name": "Noteable",
+ "ofType": null
+ }
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "IssuePermissions",
+ "description": "Check permissions for the current user on a issue",
+ "fields": [
+ {
+ "name": "adminIssue",
+ "description": "Whether or not a user can perform `admin_issue` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createDesign",
+ "description": "Whether or not a user can perform `create_design` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createNote",
+ "description": "Whether or not a user can perform `create_note` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "destroyDesign",
+ "description": "Whether or not a user can perform `destroy_design` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "readDesign",
+ "description": "Whether or not a user can perform `read_design` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "readIssue",
+ "description": "Whether or not a user can perform `read_issue` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "reopenIssue",
+ "description": "Whether or not a user can perform `reopen_issue` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "updateIssue",
+ "description": "Whether or not a user can perform `update_issue` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "ENUM",
+ "name": "IssueState",
+ "description": "State of a GitLab issue",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": [
+ {
+ "name": "opened",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "closed",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "locked",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "Milestone",
+ "description": null,
+ "fields": [
+ {
+ "name": "createdAt",
+ "description": "Timestamp of milestone creation",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "description",
+ "description": "Description of the milestone",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "dueDate",
+ "description": "Timestamp of the milestone due date",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": "ID of the milestone",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "startDate",
+ "description": "Timestamp of the milestone start date",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "state",
+ "description": "State of the milestone",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "title",
+ "description": "Title of the milestone",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "updatedAt",
+ "description": "Timestamp of last milestone update",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "TaskCompletionStatus",
+ "description": "Completion status of tasks",
+ "fields": [
+ {
+ "name": "completedCount",
+ "description": "Number of completed tasks",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "count",
+ "description": "Number of total tasks",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "DesignCollection",
+ "description": null,
+ "fields": [
+ {
+ "name": "designs",
+ "description": "All designs for this collection",
+ "args": [
+ {
+ "name": "ids",
+ "description": "Filters designs by their ID",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "filenames",
+ "description": "Filters designs by their filename",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "atVersion",
+ "description": "Filters designs to only those that existed at the version. If argument is omitted or nil then all designs will reflect the latest version",
+ "type": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "DesignConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "issue",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "Issue",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "project",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "Project",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "versions",
+ "description": "All versions related to all designs ordered newest first",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "DesignVersionConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "Issue",
+ "description": null,
+ "fields": [
+ {
+ "name": "assignees",
+ "description": "Assignees of the issue",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "UserConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "author",
+ "description": "User that created the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "User",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "closedAt",
+ "description": "Timestamp of when the issue was closed",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "confidential",
+ "description": "Indicates the issue is confidential",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createdAt",
+ "description": "Timestamp of when the issue was created",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "description",
+ "description": "Description of the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "descriptionHtml",
+ "description": "The GitLab Flavored Markdown rendering of `description`",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "designCollection",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "DesignCollection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "designs",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "DesignCollection",
+ "ofType": null
+ },
+ "isDeprecated": true,
+ "deprecationReason": "use design_collection"
+ },
+ {
+ "name": "discussionLocked",
+ "description": "Indicates discussion is locked on the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "discussions",
+ "description": "All discussions on this noteable",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "DiscussionConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "downvotes",
+ "description": "Number of downvotes the issue has received",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "dueDate",
+ "description": "Due date of the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "epic",
+ "description": "The epic to which issue belongs",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Epic",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "iid",
+ "description": "Internal ID of the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "labels",
+ "description": "Labels of the issue",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "LabelConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "milestone",
+ "description": "Milestone of the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Milestone",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "notes",
+ "description": "All notes on this noteable",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "NoteConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "participants",
+ "description": "List of participants in the issue",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "UserConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "reference",
+ "description": "Internal reference of the issue. Returned in shortened format by default",
+ "args": [
+ {
+ "name": "full",
+ "description": "Boolean option specifying whether the reference should be returned in full",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": "false"
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "relativePosition",
+ "description": "Relative position of the issue (used for positioning in epic tree and issue boards)",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "state",
+ "description": "State of the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "ENUM",
+ "name": "IssueState",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "subscribed",
+ "description": "Boolean flag for whether the currently logged in user is subscribed to this issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "taskCompletionStatus",
+ "description": "Task completion status of the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "TaskCompletionStatus",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "timeEstimate",
+ "description": "Time estimate of the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "title",
+ "description": "Title of the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "titleHtml",
+ "description": "The GitLab Flavored Markdown rendering of `title`",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "totalTimeSpent",
+ "description": "Total time reported as spent on the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "updatedAt",
+ "description": "Timestamp of when the issue was last updated",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "upvotes",
+ "description": "Number of upvotes the issue has received",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "userNotesCount",
+ "description": "Number of user notes of the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "userPermissions",
+ "description": "Permissions for the current user on the resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "IssuePermissions",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "webPath",
+ "description": "Web path of the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "webUrl",
+ "description": "Web URL of the issue",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "weight",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+ {
+ "kind": "INTERFACE",
+ "name": "Noteable",
+ "ofType": null
+ }
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "DesignConnection",
+ "description": "The connection type for Design.",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "DesignEdge",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "Design",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "DesignEdge",
+ "description": "An edge in a connection.",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Design",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "Design",
+ "description": null,
+ "fields": [
+ {
+ "name": "diffRefs",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "DiffRefs",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "discussions",
+ "description": "All discussions on this noteable",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "DiscussionConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "event",
+ "description": "The change that happened to the design at this version",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "ENUM",
+ "name": "DesignVersionEvent",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "filename",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "fullPath",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "image",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "issue",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "Issue",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "notes",
+ "description": "All notes on this noteable",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "NoteConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "notesCount",
+ "description": "The total count of user-created notes for this design",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "project",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "Project",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "versions",
+ "description": "All versions related to this design ordered newest first",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "DesignVersionConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+ {
+ "kind": "INTERFACE",
+ "name": "Noteable",
+ "ofType": null
+ }
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "ENUM",
+ "name": "DesignVersionEvent",
+ "description": "Mutation event of a Design within a Version",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": [
+ {
+ "name": "NONE",
+ "description": "No change",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "CREATION",
+ "description": "A creation event",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "MODIFICATION",
+ "description": "A modification event",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "DELETION",
+ "description": "A deletion event",
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "DesignVersionConnection",
+ "description": "The connection type for DesignVersion.",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "DesignVersionEdge",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "DesignVersion",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "DesignVersionEdge",
+ "description": "An edge in a connection.",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "DesignVersion",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "DesignVersion",
+ "description": null,
+ "fields": [
+ {
+ "name": "designs",
+ "description": "All designs that were changed in this version",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "DesignConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "sha",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "EpicDescendantCount",
+ "description": null,
+ "fields": [
+ {
+ "name": "closedEpics",
+ "description": "Number of closed sub-epics",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "closedIssues",
+ "description": "Number of closed epic issues",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "openedEpics",
+ "description": "Number of opened sub-epics",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "openedIssues",
+ "description": "Number of opened epic issues",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "ProjectStatistics",
+ "description": null,
+ "fields": [
+ {
+ "name": "buildArtifactsSize",
+ "description": "Build artifacts size of the project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "commitCount",
+ "description": "Commit count of the project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "lfsObjectsSize",
+ "description": "Large File Storage (LFS) object size of the project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "packagesSize",
+ "description": "Packages size of the project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "repositorySize",
+ "description": "Repository size of the project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "storageSize",
+ "description": "Storage size of the project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "wikiSize",
+ "description": "Wiki size of the project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "Repository",
+ "description": null,
+ "fields": [
+ {
+ "name": "empty",
+ "description": "Indicates repository has no visible content",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "exists",
+ "description": "Indicates a corresponding Git repository exists on disk",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "rootRef",
+ "description": "Default branch of the repository",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "tree",
+ "description": "Tree of the repository",
+ "args": [
+ {
+ "name": "path",
+ "description": "The path to get the tree for. Default value is the root of the repository",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": "\"\""
+ },
+ {
+ "name": "ref",
+ "description": "The commit ref to get the tree for. Default value is HEAD",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": "\"head\""
+ },
+ {
+ "name": "recursive",
+ "description": "Used to get a recursive tree. Default is false",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": "false"
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Tree",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "Tree",
+ "description": null,
+ "fields": [
+ {
+ "name": "blobs",
+ "description": null,
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "BlobConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "lastCommit",
+ "description": "Last commit for the tree",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Commit",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "submodules",
+ "description": null,
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "SubmoduleConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "trees",
+ "description": null,
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "TreeEntryConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "Commit",
+ "description": null,
+ "fields": [
+ {
+ "name": "author",
+ "description": "Author of the commit",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "User",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "authorName",
+ "description": "Commit authors name",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "authoredDate",
+ "description": "Timestamp of when the commit was authored",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "description",
+ "description": "Description of the commit message",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": "ID (global ID) of the commit",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "latestPipeline",
+ "description": "Latest pipeline of the commit",
+ "args": [
+ {
+ "name": "status",
+ "description": "Filter pipelines by their status",
+ "type": {
+ "kind": "ENUM",
+ "name": "PipelineStatusEnum",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "ref",
+ "description": "Filter pipelines by the ref they are run for",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "sha",
+ "description": "Filter pipelines by the sha of the commit they are run for",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Pipeline",
+ "ofType": null
+ },
+ "isDeprecated": true,
+ "deprecationReason": "use pipelines"
+ },
+ {
+ "name": "message",
+ "description": "Raw commit message",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pipelines",
+ "description": "Pipelines of the commit ordered latest first",
+ "args": [
+ {
+ "name": "status",
+ "description": "Filter pipelines by their status",
+ "type": {
+ "kind": "ENUM",
+ "name": "PipelineStatusEnum",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "ref",
+ "description": "Filter pipelines by the ref they are run for",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "sha",
+ "description": "Filter pipelines by the sha of the commit they are run for",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "PipelineConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "sha",
+ "description": "SHA1 ID of the commit",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "signatureHtml",
+ "description": "Rendered HTML of the commit signature",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "title",
+ "description": "Title of the commit message",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "webUrl",
+ "description": "Web URL of the commit",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "PipelineConnection",
+ "description": "The connection type for Pipeline.",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PipelineEdge",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "Pipeline",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "PipelineEdge",
+ "description": "An edge in a connection.",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Pipeline",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "Pipeline",
+ "description": null,
+ "fields": [
+ {
+ "name": "beforeSha",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "committedAt",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "coverage",
+ "description": "Coverage percentage",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Float",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createdAt",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "detailedStatus",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "DetailedStatus",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "duration",
+ "description": "Duration of the pipeline in seconds",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "finishedAt",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "iid",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "sha",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "startedAt",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "status",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "ENUM",
+ "name": "PipelineStatusEnum",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "updatedAt",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "userPermissions",
+ "description": "Permissions for the current user on the resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PipelinePermissions",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "PipelinePermissions",
+ "description": null,
+ "fields": [
+ {
+ "name": "adminPipeline",
+ "description": "Whether or not a user can perform `admin_pipeline` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "destroyPipeline",
+ "description": "Whether or not a user can perform `destroy_pipeline` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "updatePipeline",
+ "description": "Whether or not a user can perform `update_pipeline` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "ENUM",
+ "name": "PipelineStatusEnum",
+ "description": null,
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": [
+ {
+ "name": "CREATED",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "PREPARING",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "PENDING",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "RUNNING",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "FAILED",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "SUCCESS",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "CANCELED",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "SKIPPED",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "MANUAL",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "SCHEDULED",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "DetailedStatus",
+ "description": null,
+ "fields": [
+ {
+ "name": "detailsPath",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "favicon",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "group",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "hasDetails",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "icon",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "label",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "text",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "tooltip",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "SCALAR",
+ "name": "Float",
+ "description": "Represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "TreeEntryConnection",
+ "description": "The connection type for TreeEntry.",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "TreeEntryEdge",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "TreeEntry",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "TreeEntryEdge",
+ "description": "An edge in a connection.",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "TreeEntry",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "TreeEntry",
+ "description": "Represents a directory",
+ "fields": [
+ {
+ "name": "flatPath",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "name",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "path",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "sha",
+ "description": "Last commit sha for entry",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "type",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "ENUM",
+ "name": "EntryType",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "webUrl",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+ {
+ "kind": "INTERFACE",
+ "name": "Entry",
+ "ofType": null
+ }
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INTERFACE",
+ "name": "Entry",
+ "description": null,
+ "fields": [
+ {
+ "name": "flatPath",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "name",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "path",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "sha",
+ "description": "Last commit sha for entry",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "type",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "ENUM",
+ "name": "EntryType",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": [
+ {
+ "kind": "OBJECT",
+ "name": "Blob",
+ "ofType": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "Submodule",
+ "ofType": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "TreeEntry",
+ "ofType": null
+ }
+ ]
+ },
+ {
+ "kind": "ENUM",
+ "name": "EntryType",
+ "description": "Type of a tree entry",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": [
+ {
+ "name": "tree",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "blob",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "commit",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "SubmoduleConnection",
+ "description": "The connection type for Submodule.",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "SubmoduleEdge",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "Submodule",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "SubmoduleEdge",
+ "description": "An edge in a connection.",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Submodule",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "Submodule",
+ "description": null,
+ "fields": [
+ {
+ "name": "flatPath",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "name",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "path",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "sha",
+ "description": "Last commit sha for entry",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "treeUrl",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "type",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "ENUM",
+ "name": "EntryType",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "webUrl",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+ {
+ "kind": "INTERFACE",
+ "name": "Entry",
+ "ofType": null
+ }
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "BlobConnection",
+ "description": "The connection type for Blob.",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "BlobEdge",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "Blob",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "BlobEdge",
+ "description": "An edge in a connection.",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Blob",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "Blob",
+ "description": null,
+ "fields": [
+ {
+ "name": "flatPath",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "lfsOid",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "name",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "path",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "sha",
+ "description": "Last commit sha for entry",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "type",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "ENUM",
+ "name": "EntryType",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "webUrl",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+ {
+ "kind": "INTERFACE",
+ "name": "Entry",
+ "ofType": null
+ }
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "MergeRequestConnection",
+ "description": "The connection type for MergeRequest.",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "MergeRequestEdge",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "MergeRequest",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "MergeRequestEdge",
+ "description": "An edge in a connection.",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "MergeRequest",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "MergeRequest",
+ "description": null,
+ "fields": [
+ {
+ "name": "allowCollaboration",
+ "description": "Indicates if members of the target project can push to the fork",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "assignees",
+ "description": "Assignees of the merge request",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "UserConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createdAt",
+ "description": "Timestamp of when the merge request was created",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "defaultMergeCommitMessage",
+ "description": "Default merge commit message of the merge request",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "description",
+ "description": "Description of the merge request (markdown rendered as HTML for caching)",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "descriptionHtml",
+ "description": "The GitLab Flavored Markdown rendering of `description`",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "diffHeadSha",
+ "description": "Diff head SHA of the merge request",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "diffRefs",
+ "description": "References of the base SHA, the head SHA, and the start SHA for this merge request",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "DiffRefs",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "discussionLocked",
+ "description": "Indicates if comments on the merge request are locked to members only",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "discussions",
+ "description": "All discussions on this noteable",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "DiscussionConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "downvotes",
+ "description": "Number of downvotes for the merge request",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "forceRemoveSourceBranch",
+ "description": "Indicates if the project settings will lead to source branch deletion after merge",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "headPipeline",
+ "description": "The pipeline running on the branch HEAD of the merge request",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Pipeline",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": "ID of the merge request",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "iid",
+ "description": "Internal ID of the merge request",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "inProgressMergeCommitSha",
+ "description": "Commit SHA of the merge request if merge is in progress",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "labels",
+ "description": "Labels of the merge request",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "LabelConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mergeCommitMessage",
+ "description": "Deprecated - renamed to defaultMergeCommitMessage",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": true,
+ "deprecationReason": "Renamed to defaultMergeCommitMessage"
+ },
+ {
+ "name": "mergeCommitSha",
+ "description": "SHA of the merge request commit (set once merged)",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mergeError",
+ "description": "Error message due to a merge error",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mergeOngoing",
+ "description": "Indicates if a merge is currently occurring",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mergeStatus",
+ "description": "Status of the merge request",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mergeWhenPipelineSucceeds",
+ "description": "Indicates if the merge has been set to be merged when its pipeline succeeds (MWPS)",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mergeableDiscussionsState",
+ "description": "Indicates if all discussions in the merge request have been resolved, allowing the merge request to be merged",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "milestone",
+ "description": "The milestone of the merge request",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Milestone",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "notes",
+ "description": "All notes on this noteable",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "NoteConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "participants",
+ "description": "Participants in the merge request",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "UserConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pipelines",
+ "description": "Pipelines for the merge request",
+ "args": [
+ {
+ "name": "status",
+ "description": "Filter pipelines by their status",
+ "type": {
+ "kind": "ENUM",
+ "name": "PipelineStatusEnum",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "ref",
+ "description": "Filter pipelines by the ref they are run for",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "sha",
+ "description": "Filter pipelines by the sha of the commit they are run for",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PipelineConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "project",
+ "description": "Alias for target_project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "Project",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "projectId",
+ "description": "ID of the merge request project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "rebaseCommitSha",
+ "description": "Rebase commit SHA of the merge request",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "rebaseInProgress",
+ "description": "Indicates if there is a rebase currently in progress for the merge request",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "reference",
+ "description": "Internal reference of the merge request. Returned in shortened format by default",
+ "args": [
+ {
+ "name": "full",
+ "description": "Boolean option specifying whether the reference should be returned in full",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": "false"
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "shouldBeRebased",
+ "description": "Indicates if the merge request will be rebased",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "shouldRemoveSourceBranch",
+ "description": "Indicates if the source branch of the merge request will be deleted after merge",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "sourceBranch",
+ "description": "Source branch of the merge request",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "sourceBranchExists",
+ "description": "Indicates if the source branch of the merge request exists",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "sourceProject",
+ "description": "Source project of the merge request",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Project",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "sourceProjectId",
+ "description": "ID of the merge request source project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "state",
+ "description": "State of the merge request",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "ENUM",
+ "name": "MergeRequestState",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "subscribed",
+ "description": "Indicates if the currently logged in user is subscribed to this merge request",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "targetBranch",
+ "description": "Target branch of the merge request",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "targetProject",
+ "description": "Target project of the merge request",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "Project",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "targetProjectId",
+ "description": "ID of the merge request target project",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "taskCompletionStatus",
+ "description": "Completion status of tasks",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "TaskCompletionStatus",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "timeEstimate",
+ "description": "Time estimate of the merge request",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "title",
+ "description": "Title of the merge request",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "titleHtml",
+ "description": "The GitLab Flavored Markdown rendering of `title`",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "totalTimeSpent",
+ "description": "Total time reported as spent on the merge request",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "updatedAt",
+ "description": "Timestamp of when the merge request was last updated",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "upvotes",
+ "description": "Number of upvotes for the merge request",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "userNotesCount",
+ "description": "User notes count of the merge request",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "userPermissions",
+ "description": "Permissions for the current user on the resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "MergeRequestPermissions",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "webUrl",
+ "description": "Web URL of the merge request",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "workInProgress",
+ "description": "Indicates if the merge request is a work in progress (WIP)",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+ {
+ "kind": "INTERFACE",
+ "name": "Noteable",
+ "ofType": null
+ }
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "MergeRequestPermissions",
+ "description": "Check permissions for the current user on a merge request",
+ "fields": [
+ {
+ "name": "adminMergeRequest",
+ "description": "Whether or not a user can perform `admin_merge_request` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "cherryPickOnCurrentMergeRequest",
+ "description": "Whether or not a user can perform `cherry_pick_on_current_merge_request` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createNote",
+ "description": "Whether or not a user can perform `create_note` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pushToSourceBranch",
+ "description": "Whether or not a user can perform `push_to_source_branch` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "readMergeRequest",
+ "description": "Whether or not a user can perform `read_merge_request` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "removeSourceBranch",
+ "description": "Whether or not a user can perform `remove_source_branch` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "revertOnCurrentMergeRequest",
+ "description": "Whether or not a user can perform `revert_on_current_merge_request` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "updateMergeRequest",
+ "description": "Whether or not a user can perform `update_merge_request` on this resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "ENUM",
+ "name": "MergeRequestState",
+ "description": "State of a GitLab merge request",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": [
+ {
+ "name": "opened",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "closed",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "locked",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "merged",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "IssueConnection",
+ "description": "The connection type for Issue.",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "IssueEdge",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "Issue",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "IssueEdge",
+ "description": "An edge in a connection.",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Issue",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "ENUM",
+ "name": "IssuableState",
+ "description": "State of a GitLab issue or merge request",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": [
+ {
+ "name": "opened",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "closed",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "locked",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "possibleTypes": null
+ },
+ {
+ "kind": "ENUM",
+ "name": "IssueSort",
+ "description": "Values for sorting issues",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": [
+ {
+ "name": "updated_desc",
+ "description": "Updated at descending order",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "updated_asc",
+ "description": "Updated at ascending order",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "created_desc",
+ "description": "Created at descending order",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "created_asc",
+ "description": "Created at ascending order",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "DUE_DATE_ASC",
+ "description": "Due date by ascending order",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "DUE_DATE_DESC",
+ "description": "Due date by descending order",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "RELATIVE_POSITION_ASC",
+ "description": "Relative position by ascending order",
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "Metadata",
+ "description": null,
+ "fields": [
+ {
+ "name": "revision",
+ "description": "Revision",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "version",
+ "description": "Version",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "Mutation",
+ "description": null,
+ "fields": [
+ {
+ "name": "addAwardEmoji",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "AddAwardEmojiInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "AddAwardEmojiPayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createDiffNote",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "CreateDiffNoteInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "CreateDiffNotePayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createEpic",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "CreateEpicInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "CreateEpicPayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createImageDiffNote",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "CreateImageDiffNoteInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "CreateImageDiffNotePayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createNote",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "CreateNoteInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "CreateNotePayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "designManagementDelete",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "DesignManagementDeleteInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "DesignManagementDeletePayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "designManagementUpload",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "DesignManagementUploadInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "DesignManagementUploadPayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "destroyNote",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "DestroyNoteInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "DestroyNotePayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "epicSetSubscription",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "EpicSetSubscriptionInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "EpicSetSubscriptionPayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "epicTreeReorder",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "EpicTreeReorderInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "EpicTreeReorderPayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mergeRequestSetAssignees",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "MergeRequestSetAssigneesInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "MergeRequestSetAssigneesPayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mergeRequestSetLabels",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "MergeRequestSetLabelsInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "MergeRequestSetLabelsPayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mergeRequestSetLocked",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "MergeRequestSetLockedInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "MergeRequestSetLockedPayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mergeRequestSetMilestone",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "MergeRequestSetMilestoneInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "MergeRequestSetMilestonePayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mergeRequestSetSubscription",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "MergeRequestSetSubscriptionInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "MergeRequestSetSubscriptionPayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mergeRequestSetWip",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "MergeRequestSetWipInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "MergeRequestSetWipPayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "removeAwardEmoji",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "RemoveAwardEmojiInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "RemoveAwardEmojiPayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "todoMarkDone",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "TodoMarkDoneInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "TodoMarkDonePayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "toggleAwardEmoji",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "ToggleAwardEmojiInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "ToggleAwardEmojiPayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "updateEpic",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "UpdateEpicInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "UpdateEpicPayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "updateNote",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "UpdateNoteInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "UpdateNotePayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "AddAwardEmojiPayload",
+ "description": "Autogenerated return type of AddAwardEmoji",
+ "fields": [
+ {
+ "name": "awardEmoji",
+ "description": "The award emoji after mutation",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "AwardEmoji",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Reasons why the mutation failed.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "AwardEmoji",
+ "description": null,
+ "fields": [
+ {
+ "name": "description",
+ "description": "The emoji description",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "emoji",
+ "description": "The emoji as an icon",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "name",
+ "description": "The emoji name",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "unicode",
+ "description": "The emoji in unicode",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "unicodeVersion",
+ "description": "The unicode version for this emoji",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "user",
+ "description": "The user who awarded the emoji",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "User",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "AddAwardEmojiInput",
+ "description": "Autogenerated input type of AddAwardEmoji",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "awardableId",
+ "description": "The global id of the awardable resource",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "name",
+ "description": "The emoji name",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "RemoveAwardEmojiPayload",
+ "description": "Autogenerated return type of RemoveAwardEmoji",
+ "fields": [
+ {
+ "name": "awardEmoji",
+ "description": "The award emoji after mutation",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "AwardEmoji",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Reasons why the mutation failed.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "RemoveAwardEmojiInput",
+ "description": "Autogenerated input type of RemoveAwardEmoji",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "awardableId",
+ "description": "The global id of the awardable resource",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "name",
+ "description": "The emoji name",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "ToggleAwardEmojiPayload",
+ "description": "Autogenerated return type of ToggleAwardEmoji",
+ "fields": [
+ {
+ "name": "awardEmoji",
+ "description": "The award emoji after mutation",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "AwardEmoji",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Reasons why the mutation failed.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "toggledOn",
+ "description": "True when the emoji was awarded, false when it was removed",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "ToggleAwardEmojiInput",
+ "description": "Autogenerated input type of ToggleAwardEmoji",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "awardableId",
+ "description": "The global id of the awardable resource",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "name",
+ "description": "The emoji name",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "MergeRequestSetLabelsPayload",
+ "description": "Autogenerated return type of MergeRequestSetLabels",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Reasons why the mutation failed.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mergeRequest",
+ "description": "The merge request after mutation",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "MergeRequest",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "MergeRequestSetLabelsInput",
+ "description": "Autogenerated input type of MergeRequestSetLabels",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "projectPath",
+ "description": "The project the merge request to mutate is in",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "iid",
+ "description": "The iid of the merge request to mutate",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "labelIds",
+ "description": "The Label IDs to set. Replaces existing labels by default.\n",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "operationMode",
+ "description": "Changes the operation mode. Defaults to REPLACE.\n",
+ "type": {
+ "kind": "ENUM",
+ "name": "MutationOperationMode",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "ENUM",
+ "name": "MutationOperationMode",
+ "description": "Different toggles for changing mutator behavior.",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": [
+ {
+ "name": "REPLACE",
+ "description": "Performs a replace operation",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "APPEND",
+ "description": "Performs an append operation",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "REMOVE",
+ "description": "Performs a removal operation",
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "MergeRequestSetLockedPayload",
+ "description": "Autogenerated return type of MergeRequestSetLocked",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Reasons why the mutation failed.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mergeRequest",
+ "description": "The merge request after mutation",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "MergeRequest",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "MergeRequestSetLockedInput",
+ "description": "Autogenerated input type of MergeRequestSetLocked",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "projectPath",
+ "description": "The project the merge request to mutate is in",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "iid",
+ "description": "The iid of the merge request to mutate",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "locked",
+ "description": "Whether or not to lock the merge request.\n",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "MergeRequestSetMilestonePayload",
+ "description": "Autogenerated return type of MergeRequestSetMilestone",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Reasons why the mutation failed.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mergeRequest",
+ "description": "The merge request after mutation",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "MergeRequest",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "MergeRequestSetMilestoneInput",
+ "description": "Autogenerated input type of MergeRequestSetMilestone",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "projectPath",
+ "description": "The project the merge request to mutate is in",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "iid",
+ "description": "The iid of the merge request to mutate",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "milestoneId",
+ "description": "The milestone to assign to the merge request.\n",
+ "type": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "MergeRequestSetSubscriptionPayload",
+ "description": "Autogenerated return type of MergeRequestSetSubscription",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Reasons why the mutation failed.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mergeRequest",
+ "description": "The merge request after mutation",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "MergeRequest",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "MergeRequestSetSubscriptionInput",
+ "description": "Autogenerated input type of MergeRequestSetSubscription",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "projectPath",
+ "description": "The project the merge request to mutate is in",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "iid",
+ "description": "The iid of the merge request to mutate",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "subscribedState",
+ "description": "The desired state of the subscription",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "MergeRequestSetWipPayload",
+ "description": "Autogenerated return type of MergeRequestSetWip",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Reasons why the mutation failed.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mergeRequest",
+ "description": "The merge request after mutation",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "MergeRequest",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "MergeRequestSetWipInput",
+ "description": "Autogenerated input type of MergeRequestSetWip",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "projectPath",
+ "description": "The project the merge request to mutate is in",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "iid",
+ "description": "The iid of the merge request to mutate",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "wip",
+ "description": "Whether or not to set the merge request as a WIP.\n",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "MergeRequestSetAssigneesPayload",
+ "description": "Autogenerated return type of MergeRequestSetAssignees",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Reasons why the mutation failed.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mergeRequest",
+ "description": "The merge request after mutation",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "MergeRequest",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "MergeRequestSetAssigneesInput",
+ "description": "Autogenerated input type of MergeRequestSetAssignees",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "projectPath",
+ "description": "The project the merge request to mutate is in",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "iid",
+ "description": "The iid of the merge request to mutate",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "assigneeUsernames",
+ "description": "The usernames to assign to the merge request. Replaces existing assignees by default.\n",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "operationMode",
+ "description": "The operation to perform. Defaults to REPLACE.\n",
+ "type": {
+ "kind": "ENUM",
+ "name": "MutationOperationMode",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "CreateNotePayload",
+ "description": "Autogenerated return type of CreateNote",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Reasons why the mutation failed.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "note",
+ "description": "The note after mutation",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Note",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "CreateNoteInput",
+ "description": "Autogenerated input type of CreateNote",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "noteableId",
+ "description": "The global id of the resource to add a note to",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "body",
+ "description": "The content note itself",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "discussionId",
+ "description": "The global id of the discussion this note is in reply to",
+ "type": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "CreateDiffNotePayload",
+ "description": "Autogenerated return type of CreateDiffNote",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Reasons why the mutation failed.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "note",
+ "description": "The note after mutation",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Note",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "CreateDiffNoteInput",
+ "description": "Autogenerated input type of CreateDiffNote",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "noteableId",
+ "description": "The global id of the resource to add a note to",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "body",
+ "description": "The content note itself",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "position",
+ "description": "The position of this note on a diff",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "DiffPositionInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "DiffPositionInput",
+ "description": null,
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "headSha",
+ "description": "The sha of the head at the time the comment was made",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "baseSha",
+ "description": "The merge base of the branch the comment was made on",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "startSha",
+ "description": "The sha of the branch being compared against",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "paths",
+ "description": "The paths of the file that was changed. Both of the properties of this input are optional, but at least one of them is required",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "DiffPathsInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "oldLine",
+ "description": "The line on start sha that was changed",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "newLine",
+ "description": "The line on head sha that was changed",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "DiffPathsInput",
+ "description": null,
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "oldPath",
+ "description": "The path of the file on the start sha",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "newPath",
+ "description": "The path of the file on the head sha",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "CreateImageDiffNotePayload",
+ "description": "Autogenerated return type of CreateImageDiffNote",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Reasons why the mutation failed.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "note",
+ "description": "The note after mutation",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Note",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "CreateImageDiffNoteInput",
+ "description": "Autogenerated input type of CreateImageDiffNote",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "noteableId",
+ "description": "The global id of the resource to add a note to",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "body",
+ "description": "The content note itself",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "position",
+ "description": "The position of this note on a diff",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "DiffImagePositionInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "DiffImagePositionInput",
+ "description": null,
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "headSha",
+ "description": "The sha of the head at the time the comment was made",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "baseSha",
+ "description": "The merge base of the branch the comment was made on",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "startSha",
+ "description": "The sha of the branch being compared against",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "paths",
+ "description": "The paths of the file that was changed. Both of the properties of this input are optional, but at least one of them is required",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "DiffPathsInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "x",
+ "description": "The X postion on which the comment was made",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "y",
+ "description": "The Y position on which the comment was made",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "width",
+ "description": "The total width of the image",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "height",
+ "description": "The total height of the image",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "UpdateNotePayload",
+ "description": "Autogenerated return type of UpdateNote",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Reasons why the mutation failed.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "note",
+ "description": "The note after mutation",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Note",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "UpdateNoteInput",
+ "description": "Autogenerated input type of UpdateNote",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "id",
+ "description": "The global id of the note to update",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "body",
+ "description": "The content note itself",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "DestroyNotePayload",
+ "description": "Autogenerated return type of DestroyNote",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Reasons why the mutation failed.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "note",
+ "description": "The note after mutation",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Note",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "DestroyNoteInput",
+ "description": "Autogenerated input type of DestroyNote",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "id",
+ "description": "The global id of the note to destroy",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "TodoMarkDonePayload",
+ "description": "Autogenerated return type of TodoMarkDone",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Reasons why the mutation failed.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "todo",
+ "description": "The requested todo",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "Todo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "TodoMarkDoneInput",
+ "description": "Autogenerated input type of TodoMarkDone",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "id",
+ "description": "The global id of the todo to mark as done",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "DesignManagementUploadPayload",
+ "description": "Autogenerated return type of DesignManagementUpload",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "designs",
+ "description": "The designs that were uploaded by the mutation",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "Design",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Reasons why the mutation failed.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "skippedDesigns",
+ "description": "Any designs that were skipped from the upload due to there being no change to their content since their last version",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "Design",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "DesignManagementUploadInput",
+ "description": "Autogenerated input type of DesignManagementUpload",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "projectPath",
+ "description": "The project where the issue is to upload designs for",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "iid",
+ "description": "The iid of the issue to modify designs for",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "files",
+ "description": "The files to upload",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Upload",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "SCALAR",
+ "name": "Upload",
+ "description": null,
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "DesignManagementDeletePayload",
+ "description": "Autogenerated return type of DesignManagementDelete",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Reasons why the mutation failed.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "version",
+ "description": "The new version in which the designs are deleted",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "DesignVersion",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "DesignManagementDeleteInput",
+ "description": "Autogenerated input type of DesignManagementDelete",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "projectPath",
+ "description": "The project where the issue is to upload designs for",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "iid",
+ "description": "The iid of the issue to modify designs for",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "filenames",
+ "description": "The filenames of the designs to delete",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "EpicTreeReorderPayload",
+ "description": "Autogenerated return type of EpicTreeReorder",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Reasons why the mutation failed.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "EpicTreeReorderInput",
+ "description": "Autogenerated input type of EpicTreeReorder",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "baseEpicId",
+ "description": "The id of the base epic of the tree",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "moved",
+ "description": "Parameters for updating the tree positions",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "EpicTreeNodeFieldsInputType",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "EpicTreeNodeFieldsInputType",
+ "description": null,
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "id",
+ "description": "The id of the epic_issue or epic that is being moved",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "adjacentReferenceId",
+ "description": "The id of the epic_issue or issue that the actual epic or issue is switched with",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "relativePosition",
+ "description": "The type of the switch, after or before allowed",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "ENUM",
+ "name": "MoveType",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "ENUM",
+ "name": "MoveType",
+ "description": "The position the adjacent object should be moved.",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": [
+ {
+ "name": "before",
+ "description": "The adjacent object will be moved before the object that is being moved.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "after",
+ "description": "The adjacent object will be moved after the object that is being moved.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "UpdateEpicPayload",
+ "description": "Autogenerated return type of UpdateEpic",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "epic",
+ "description": "The epic after mutation",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Epic",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Reasons why the mutation failed.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "UpdateEpicInput",
+ "description": "Autogenerated input type of UpdateEpic",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "groupPath",
+ "description": "The group the epic to mutate is in",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "title",
+ "description": "The title of the epic",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "description",
+ "description": "The description of the epic",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "startDateFixed",
+ "description": "The start date of the epic",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "dueDateFixed",
+ "description": "The end date of the epic",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "startDateIsFixed",
+ "description": "Indicates start date should be sourced from start_date_fixed field not the issue milestones",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "dueDateIsFixed",
+ "description": "Indicates end date should be sourced from due_date_fixed field not the issue milestones",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "addLabelIds",
+ "description": "The IDs of labels to be added to the epic.",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "removeLabelIds",
+ "description": "The IDs of labels to be removed from the epic.",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "iid",
+ "description": "The iid of the epic to mutate",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "stateEvent",
+ "description": "State event for the epic",
+ "type": {
+ "kind": "ENUM",
+ "name": "EpicStateEvent",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "ENUM",
+ "name": "EpicStateEvent",
+ "description": "State event of a GitLab Epic",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": [
+ {
+ "name": "REOPEN",
+ "description": "Reopen the Epic",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "CLOSE",
+ "description": "Close the Epic",
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "CreateEpicPayload",
+ "description": "Autogenerated return type of CreateEpic",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "epic",
+ "description": "The created epic",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Epic",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Reasons why the mutation failed.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "CreateEpicInput",
+ "description": "Autogenerated input type of CreateEpic",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "groupPath",
+ "description": "The group the epic to mutate is in",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "title",
+ "description": "The title of the epic",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "description",
+ "description": "The description of the epic",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "startDateFixed",
+ "description": "The start date of the epic",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "dueDateFixed",
+ "description": "The end date of the epic",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "startDateIsFixed",
+ "description": "Indicates start date should be sourced from start_date_fixed field not the issue milestones",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "dueDateIsFixed",
+ "description": "Indicates end date should be sourced from due_date_fixed field not the issue milestones",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "addLabelIds",
+ "description": "The IDs of labels to be added to the epic.",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "removeLabelIds",
+ "description": "The IDs of labels to be removed from the epic.",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "EpicSetSubscriptionPayload",
+ "description": "Autogenerated return type of EpicSetSubscription",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "epic",
+ "description": "The epic after mutation",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Epic",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Reasons why the mutation failed.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "EpicSetSubscriptionInput",
+ "description": "Autogenerated input type of EpicSetSubscription",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "groupPath",
+ "description": "The group the epic to (un)subscribe is in",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "iid",
+ "description": "The iid of the epic to (un)subscribe",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "subscribedState",
+ "description": "The desired state of the subscription",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "__Schema",
+ "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.",
+ "fields": [
+ {
+ "name": "directives",
+ "description": "A list of all directives supported by this server.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "__Directive",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mutationType",
+ "description": "If this server supports mutation, the type that mutation operations will be rooted at.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "__Type",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "queryType",
+ "description": "The type that query operations will be rooted at.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "__Type",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "subscriptionType",
+ "description": "If this server support subscription, the type that subscription operations will be rooted at.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "__Type",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "types",
+ "description": "A list of all types supported by this server.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "__Type",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "__Type",
+ "description": "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.",
+ "fields": [
+ {
+ "name": "description",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "enumValues",
+ "description": null,
+ "args": [
+ {
+ "name": "includeDeprecated",
+ "description": null,
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": "false"
+ }
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "__EnumValue",
+ "ofType": null
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "fields",
+ "description": null,
+ "args": [
+ {
+ "name": "includeDeprecated",
+ "description": null,
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": "false"
+ }
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "__Field",
+ "ofType": null
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "inputFields",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "__InputValue",
+ "ofType": null
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "interfaces",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "__Type",
+ "ofType": null
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "kind",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "ENUM",
+ "name": "__TypeKind",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "name",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "ofType",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "__Type",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "possibleTypes",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "__Type",
+ "ofType": null
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "__Field",
+ "description": "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.",
+ "fields": [
+ {
+ "name": "args",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "__InputValue",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "deprecationReason",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "description",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "isDeprecated",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "name",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "type",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "__Type",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "__Directive",
+ "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.",
+ "fields": [
+ {
+ "name": "args",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "__InputValue",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "description",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "locations",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "ENUM",
+ "name": "__DirectiveLocation",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "name",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "onField",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": true,
+ "deprecationReason": "Use `locations`."
+ },
+ {
+ "name": "onFragment",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": true,
+ "deprecationReason": "Use `locations`."
+ },
+ {
+ "name": "onOperation",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": true,
+ "deprecationReason": "Use `locations`."
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "__EnumValue",
+ "description": "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.",
+ "fields": [
+ {
+ "name": "deprecationReason",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "description",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "isDeprecated",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "name",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "__InputValue",
+ "description": "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.",
+ "fields": [
+ {
+ "name": "defaultValue",
+ "description": "A GraphQL-formatted string representing the default value for this input value.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "description",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "name",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "type",
+ "description": null,
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "__Type",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "ENUM",
+ "name": "__TypeKind",
+ "description": "An enum describing what kind of type a given `__Type` is.",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": [
+ {
+ "name": "SCALAR",
+ "description": "Indicates this type is a scalar.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "OBJECT",
+ "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "INTERFACE",
+ "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "UNION",
+ "description": "Indicates this type is a union. `possibleTypes` is a valid field.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "ENUM",
+ "description": "Indicates this type is an enum. `enumValues` is a valid field.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "INPUT_OBJECT",
+ "description": "Indicates this type is an input object. `inputFields` is a valid field.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "LIST",
+ "description": "Indicates this type is a list. `ofType` is a valid field.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "NON_NULL",
+ "description": "Indicates this type is a non-null. `ofType` is a valid field.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "possibleTypes": null
+ },
+ {
+ "kind": "ENUM",
+ "name": "__DirectiveLocation",
+ "description": "A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": [
+ {
+ "name": "QUERY",
+ "description": "Location adjacent to a query operation.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "MUTATION",
+ "description": "Location adjacent to a mutation operation.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "SUBSCRIPTION",
+ "description": "Location adjacent to a subscription operation.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "FIELD",
+ "description": "Location adjacent to a field.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "FRAGMENT_DEFINITION",
+ "description": "Location adjacent to a fragment definition.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "FRAGMENT_SPREAD",
+ "description": "Location adjacent to a fragment spread.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "INLINE_FRAGMENT",
+ "description": "Location adjacent to an inline fragment.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "SCHEMA",
+ "description": "Location adjacent to a schema definition.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "SCALAR",
+ "description": "Location adjacent to a scalar definition.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "OBJECT",
+ "description": "Location adjacent to an object type definition.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "FIELD_DEFINITION",
+ "description": "Location adjacent to a field definition.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "ARGUMENT_DEFINITION",
+ "description": "Location adjacent to an argument definition.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "INTERFACE",
+ "description": "Location adjacent to an interface definition.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "UNION",
+ "description": "Location adjacent to a union definition.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "ENUM",
+ "description": "Location adjacent to an enum definition.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "ENUM_VALUE",
+ "description": "Location adjacent to an enum value definition.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "INPUT_OBJECT",
+ "description": "Location adjacent to an input object type definition.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "INPUT_FIELD_DEFINITION",
+ "description": "Location adjacent to an input object field definition.",
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "possibleTypes": null
+ }
+ ],
+ "directives": [
+ {
+ "name": "include",
+ "description": "Directs the executor to include this field or fragment only when the `if` argument is true.",
+ "locations": [
+ "FIELD",
+ "FRAGMENT_SPREAD",
+ "INLINE_FRAGMENT"
+ ],
+ "args": [
+ {
+ "name": "if",
+ "description": "Included when true.",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ]
+ },
+ {
+ "name": "skip",
+ "description": "Directs the executor to skip this field or fragment when the `if` argument is true.",
+ "locations": [
+ "FIELD",
+ "FRAGMENT_SPREAD",
+ "INLINE_FRAGMENT"
+ ],
+ "args": [
+ {
+ "name": "if",
+ "description": "Skipped when true.",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ]
+ },
+ {
+ "name": "deprecated",
+ "description": "Marks an element of a GraphQL schema as no longer supported.",
+ "locations": [
+ "FIELD_DEFINITION",
+ "ENUM_VALUE"
+ ],
+ "args": [
+ {
+ "name": "reason",
+ "description": "Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted in [Markdown](https://daringfireball.net/projects/markdown/).",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": "\"No longer supported\""
+ }
+ ]
+ }
+ ]
+ }
+ }
+} \ No newline at end of file
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 839289cf677..151e43f4cff 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -36,6 +36,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
| `id` | ID! | |
+| `sha` | String! | Last commit sha for entry |
| `name` | String! | |
| `type` | EntryType! | |
| `path` | String! | |
@@ -47,16 +48,17 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
-| `id` | ID! | |
-| `sha` | String! | |
-| `title` | String | |
-| `description` | String | |
-| `message` | String | |
-| `authoredDate` | Time | |
-| `webUrl` | String! | |
-| `signatureHtml` | String | Rendered html for the commit signature |
-| `author` | User | |
-| `latestPipeline` | Pipeline | Latest pipeline for this commit |
+| `id` | ID! | ID (global ID) of the commit |
+| `sha` | String! | SHA1 ID of the commit |
+| `title` | String | Title of the commit message |
+| `description` | String | Description of the commit message |
+| `message` | String | Raw commit message |
+| `authoredDate` | Time | Timestamp of when the commit was authored |
+| `webUrl` | String! | Web URL of the commit |
+| `signatureHtml` | String | Rendered HTML of the commit signature |
+| `authorName` | String | Commit authors name |
+| `author` | User | Author of the commit |
+| `latestPipeline` | Pipeline | Latest pipeline of the commit |
### CreateDiffNotePayload
@@ -66,6 +68,14 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| `errors` | String! => Array | Reasons why the mutation failed. |
| `note` | Note | The note after mutation |
+### CreateEpicPayload
+
+| Name | Type | Description |
+| --- | ---- | ---------- |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `errors` | String! => Array | Reasons why the mutation failed. |
+| `epic` | Epic | The created epic |
+
### CreateImageDiffNotePayload
| Name | Type | Description |
@@ -212,36 +222,47 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| `relationPath` | String | |
| `reference` | String! | |
| `subscribed` | Boolean! | Boolean flag for whether the currently logged in user is subscribed to this epic |
+| `descendantCounts` | EpicDescendantCount | Number of open and closed descendant epics and issues |
+
+### EpicDescendantCount
+
+| Name | Type | Description |
+| --- | ---- | ---------- |
+| `openedEpics` | Int | Number of opened sub-epics |
+| `closedEpics` | Int | Number of closed sub-epics |
+| `openedIssues` | Int | Number of opened epic issues |
+| `closedIssues` | Int | Number of closed epic issues |
### EpicIssue
| Name | Type | Description |
| --- | ---- | ---------- |
| `userPermissions` | IssuePermissions! | Permissions for the current user on the resource |
-| `iid` | ID! | |
-| `title` | String! | |
+| `iid` | ID! | Internal ID of the issue |
+| `title` | String! | Title of the issue |
| `titleHtml` | String | The GitLab Flavored Markdown rendering of `title` |
-| `description` | String | |
+| `description` | String | Description of the issue |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
-| `state` | IssueState! | |
-| `reference` | String! | |
-| `author` | User! | |
-| `milestone` | Milestone | |
-| `dueDate` | Time | |
-| `confidential` | Boolean! | |
-| `discussionLocked` | Boolean! | |
-| `upvotes` | Int! | |
-| `downvotes` | Int! | |
-| `userNotesCount` | Int! | |
-| `webPath` | String! | |
-| `webUrl` | String! | |
-| `relativePosition` | Int | |
-| `timeEstimate` | Int! | The time estimate on the issue |
+| `state` | IssueState! | State of the issue |
+| `reference` | String! | Internal reference of the issue. Returned in shortened format by default |
+| `author` | User! | User that created the issue |
+| `milestone` | Milestone | Milestone of the issue |
+| `dueDate` | Time | Due date of the issue |
+| `confidential` | Boolean! | Indicates the issue is confidential |
+| `discussionLocked` | Boolean! | Indicates discussion is locked on the issue |
+| `upvotes` | Int! | Number of upvotes the issue has received |
+| `downvotes` | Int! | Number of downvotes the issue has received |
+| `userNotesCount` | Int! | Number of user notes of the issue |
+| `webPath` | String! | Web path of the issue |
+| `webUrl` | String! | Web URL of the issue |
+| `relativePosition` | Int | Relative position of the issue (used for positioning in epic tree and issue boards) |
+| `subscribed` | Boolean! | Boolean flag for whether the currently logged in user is subscribed to this issue |
+| `timeEstimate` | Int! | Time estimate of the issue |
| `totalTimeSpent` | Int! | Total time reported as spent on the issue |
-| `closedAt` | Time | |
-| `createdAt` | Time! | |
-| `updatedAt` | Time! | |
-| `taskCompletionStatus` | TaskCompletionStatus! | |
+| `closedAt` | Time | Timestamp of when the issue was closed |
+| `createdAt` | Time! | Timestamp of when the issue was created |
+| `updatedAt` | Time! | Timestamp of when the issue was last updated |
+| `taskCompletionStatus` | TaskCompletionStatus! | Task completion status of the issue |
| `epic` | Epic | The epic to which issue belongs |
| `weight` | Int | |
| `designs` | DesignCollection | |
@@ -263,67 +284,40 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| `createNote` | Boolean! | Whether or not a user can perform `create_note` on this resource |
| `awardEmoji` | Boolean! | Whether or not a user can perform `award_emoji` on this resource |
-### EpicTreeReorderPayload
+### EpicSetSubscriptionPayload
| Name | Type | Description |
| --- | ---- | ---------- |
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Reasons why the mutation failed. |
+| `epic` | Epic | The epic after mutation |
-### ExtendedIssue
+### EpicTreeReorderPayload
| Name | Type | Description |
| --- | ---- | ---------- |
-| `userPermissions` | IssuePermissions! | Permissions for the current user on the resource |
-| `iid` | ID! | |
-| `title` | String! | |
-| `titleHtml` | String | The GitLab Flavored Markdown rendering of `title` |
-| `description` | String | |
-| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
-| `state` | IssueState! | |
-| `reference` | String! | |
-| `author` | User! | |
-| `milestone` | Milestone | |
-| `dueDate` | Time | |
-| `confidential` | Boolean! | |
-| `discussionLocked` | Boolean! | |
-| `upvotes` | Int! | |
-| `downvotes` | Int! | |
-| `userNotesCount` | Int! | |
-| `webPath` | String! | |
-| `webUrl` | String! | |
-| `relativePosition` | Int | |
-| `timeEstimate` | Int! | The time estimate on the issue |
-| `totalTimeSpent` | Int! | Total time reported as spent on the issue |
-| `closedAt` | Time | |
-| `createdAt` | Time! | |
-| `updatedAt` | Time! | |
-| `taskCompletionStatus` | TaskCompletionStatus! | |
-| `epic` | Epic | The epic to which issue belongs |
-| `weight` | Int | |
-| `designs` | DesignCollection | |
-| `designCollection` | DesignCollection | |
-| `subscribed` | Boolean! | Boolean flag for whether the currently logged in user is subscribed to this issue |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `errors` | String! => Array | Reasons why the mutation failed. |
### Group
| Name | Type | Description |
| --- | ---- | ---------- |
-| `id` | ID! | |
-| `name` | String! | |
-| `path` | String! | |
-| `fullName` | String! | |
-| `fullPath` | ID! | |
-| `description` | String | |
+| `id` | ID! | ID of the namespace |
+| `name` | String! | Name of the namespace |
+| `path` | String! | Path of the namespace |
+| `fullName` | String! | Full name of the namespace |
+| `fullPath` | ID! | Full path of the namespace |
+| `description` | String | Description of the namespace |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
-| `visibility` | String | |
-| `lfsEnabled` | Boolean | |
-| `requestAccessEnabled` | Boolean | |
-| `rootStorageStatistics` | RootStorageStatistics | The aggregated storage statistics. Only available for root namespaces |
+| `visibility` | String | Visibility of the namespace |
+| `lfsEnabled` | Boolean | Indicates if Large File Storage (LFS) is enabled for namespace |
+| `requestAccessEnabled` | Boolean | Indicates if users can request access to namespace |
+| `rootStorageStatistics` | RootStorageStatistics | Aggregated storage statistics of the namespace. Only available for root namespaces |
| `userPermissions` | GroupPermissions! | Permissions for the current user on the resource |
-| `webUrl` | String! | |
-| `avatarUrl` | String | |
-| `parent` | Group | |
+| `webUrl` | String! | Web URL of the group |
+| `avatarUrl` | String | Avatar URL of the group |
+| `parent` | Group | Parent group |
| `epicsEnabled` | Boolean | |
| `epic` | Epic | |
@@ -338,30 +332,31 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
| `userPermissions` | IssuePermissions! | Permissions for the current user on the resource |
-| `iid` | ID! | |
-| `title` | String! | |
+| `iid` | ID! | Internal ID of the issue |
+| `title` | String! | Title of the issue |
| `titleHtml` | String | The GitLab Flavored Markdown rendering of `title` |
-| `description` | String | |
+| `description` | String | Description of the issue |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
-| `state` | IssueState! | |
-| `reference` | String! | |
-| `author` | User! | |
-| `milestone` | Milestone | |
-| `dueDate` | Time | |
-| `confidential` | Boolean! | |
-| `discussionLocked` | Boolean! | |
-| `upvotes` | Int! | |
-| `downvotes` | Int! | |
-| `userNotesCount` | Int! | |
-| `webPath` | String! | |
-| `webUrl` | String! | |
-| `relativePosition` | Int | |
-| `timeEstimate` | Int! | The time estimate on the issue |
+| `state` | IssueState! | State of the issue |
+| `reference` | String! | Internal reference of the issue. Returned in shortened format by default |
+| `author` | User! | User that created the issue |
+| `milestone` | Milestone | Milestone of the issue |
+| `dueDate` | Time | Due date of the issue |
+| `confidential` | Boolean! | Indicates the issue is confidential |
+| `discussionLocked` | Boolean! | Indicates discussion is locked on the issue |
+| `upvotes` | Int! | Number of upvotes the issue has received |
+| `downvotes` | Int! | Number of downvotes the issue has received |
+| `userNotesCount` | Int! | Number of user notes of the issue |
+| `webPath` | String! | Web path of the issue |
+| `webUrl` | String! | Web URL of the issue |
+| `relativePosition` | Int | Relative position of the issue (used for positioning in epic tree and issue boards) |
+| `subscribed` | Boolean! | Boolean flag for whether the currently logged in user is subscribed to this issue |
+| `timeEstimate` | Int! | Time estimate of the issue |
| `totalTimeSpent` | Int! | Total time reported as spent on the issue |
-| `closedAt` | Time | |
-| `createdAt` | Time! | |
-| `updatedAt` | Time! | |
-| `taskCompletionStatus` | TaskCompletionStatus! | |
+| `closedAt` | Time | Timestamp of when the issue was closed |
+| `createdAt` | Time! | Timestamp of when the issue was created |
+| `updatedAt` | Time! | Timestamp of when the issue was last updated |
+| `taskCompletionStatus` | TaskCompletionStatus! | Task completion status of the issue |
| `epic` | Epic | The epic to which issue belongs |
| `weight` | Int | |
| `designs` | DesignCollection | |
@@ -384,65 +379,66 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
-| `description` | String | |
+| `id` | ID! | Label ID |
+| `description` | String | Description of the label (markdown rendered as HTML for caching) |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
-| `title` | String! | |
-| `color` | String! | |
-| `textColor` | String! | |
+| `title` | String! | Content of the label |
+| `color` | String! | Background color of the label |
+| `textColor` | String! | Text color of the label |
### MergeRequest
| Name | Type | Description |
| --- | ---- | ---------- |
| `userPermissions` | MergeRequestPermissions! | Permissions for the current user on the resource |
-| `id` | ID! | |
-| `iid` | String! | |
-| `title` | String! | |
+| `id` | ID! | ID of the merge request |
+| `iid` | String! | Internal ID of the merge request |
+| `title` | String! | Title of the merge request |
| `titleHtml` | String | The GitLab Flavored Markdown rendering of `title` |
-| `description` | String | |
+| `description` | String | Description of the merge request (markdown rendered as HTML for caching) |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
-| `state` | MergeRequestState! | |
-| `createdAt` | Time! | |
-| `updatedAt` | Time! | |
-| `sourceProject` | Project | |
-| `targetProject` | Project! | |
-| `diffRefs` | DiffRefs | |
-| `project` | Project! | |
-| `projectId` | Int! | |
-| `sourceProjectId` | Int | |
-| `targetProjectId` | Int! | |
-| `sourceBranch` | String! | |
-| `targetBranch` | String! | |
-| `workInProgress` | Boolean! | |
-| `mergeWhenPipelineSucceeds` | Boolean | |
-| `diffHeadSha` | String | |
-| `mergeCommitSha` | String | |
-| `userNotesCount` | Int | |
-| `shouldRemoveSourceBranch` | Boolean | |
-| `forceRemoveSourceBranch` | Boolean | |
-| `mergeStatus` | String | |
-| `inProgressMergeCommitSha` | String | |
-| `mergeError` | String | |
-| `allowCollaboration` | Boolean | |
-| `shouldBeRebased` | Boolean! | |
-| `rebaseCommitSha` | String | |
-| `rebaseInProgress` | Boolean! | |
-| `mergeCommitMessage` | String | |
-| `defaultMergeCommitMessage` | String | |
-| `mergeOngoing` | Boolean! | |
-| `sourceBranchExists` | Boolean! | |
-| `mergeableDiscussionsState` | Boolean | |
-| `webUrl` | String | |
-| `upvotes` | Int! | |
-| `downvotes` | Int! | |
-| `headPipeline` | Pipeline | |
-| `milestone` | Milestone | The milestone this merge request is linked to |
-| `subscribed` | Boolean! | Boolean flag for whether the currently logged in user is subscribed to this MR |
-| `discussionLocked` | Boolean! | Boolean flag determining if comments on the merge request are locked to members only |
-| `timeEstimate` | Int! | The time estimate for the merge request |
+| `state` | MergeRequestState! | State of the merge request |
+| `createdAt` | Time! | Timestamp of when the merge request was created |
+| `updatedAt` | Time! | Timestamp of when the merge request was last updated |
+| `sourceProject` | Project | Source project of the merge request |
+| `targetProject` | Project! | Target project of the merge request |
+| `diffRefs` | DiffRefs | References of the base SHA, the head SHA, and the start SHA for this merge request |
+| `project` | Project! | Alias for target_project |
+| `projectId` | Int! | ID of the merge request project |
+| `sourceProjectId` | Int | ID of the merge request source project |
+| `targetProjectId` | Int! | ID of the merge request target project |
+| `sourceBranch` | String! | Source branch of the merge request |
+| `targetBranch` | String! | Target branch of the merge request |
+| `workInProgress` | Boolean! | Indicates if the merge request is a work in progress (WIP) |
+| `mergeWhenPipelineSucceeds` | Boolean | Indicates if the merge has been set to be merged when its pipeline succeeds (MWPS) |
+| `diffHeadSha` | String | Diff head SHA of the merge request |
+| `mergeCommitSha` | String | SHA of the merge request commit (set once merged) |
+| `userNotesCount` | Int | User notes count of the merge request |
+| `shouldRemoveSourceBranch` | Boolean | Indicates if the source branch of the merge request will be deleted after merge |
+| `forceRemoveSourceBranch` | Boolean | Indicates if the project settings will lead to source branch deletion after merge |
+| `mergeStatus` | String | Status of the merge request |
+| `inProgressMergeCommitSha` | String | Commit SHA of the merge request if merge is in progress |
+| `mergeError` | String | Error message due to a merge error |
+| `allowCollaboration` | Boolean | Indicates if members of the target project can push to the fork |
+| `shouldBeRebased` | Boolean! | Indicates if the merge request will be rebased |
+| `rebaseCommitSha` | String | Rebase commit SHA of the merge request |
+| `rebaseInProgress` | Boolean! | Indicates if there is a rebase currently in progress for the merge request |
+| `mergeCommitMessage` | String | Deprecated - renamed to defaultMergeCommitMessage |
+| `defaultMergeCommitMessage` | String | Default merge commit message of the merge request |
+| `mergeOngoing` | Boolean! | Indicates if a merge is currently occurring |
+| `sourceBranchExists` | Boolean! | Indicates if the source branch of the merge request exists |
+| `mergeableDiscussionsState` | Boolean | Indicates if all discussions in the merge request have been resolved, allowing the merge request to be merged |
+| `webUrl` | String | Web URL of the merge request |
+| `upvotes` | Int! | Number of upvotes for the merge request |
+| `downvotes` | Int! | Number of downvotes for the merge request |
+| `headPipeline` | Pipeline | The pipeline running on the branch HEAD of the merge request |
+| `milestone` | Milestone | The milestone of the merge request |
+| `subscribed` | Boolean! | Indicates if the currently logged in user is subscribed to this merge request |
+| `discussionLocked` | Boolean! | Indicates if comments on the merge request are locked to members only |
+| `timeEstimate` | Int! | Time estimate of the merge request |
| `totalTimeSpent` | Int! | Total time reported as spent on the merge request |
-| `reference` | String! | Internal merge request reference. Returned in shortened format by default |
-| `taskCompletionStatus` | TaskCompletionStatus! | |
+| `reference` | String! | Internal reference of the merge request. Returned in shortened format by default |
+| `taskCompletionStatus` | TaskCompletionStatus! | Completion status of tasks |
### MergeRequestPermissions
@@ -457,6 +453,46 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| `cherryPickOnCurrentMergeRequest` | Boolean! | Whether or not a user can perform `cherry_pick_on_current_merge_request` on this resource |
| `revertOnCurrentMergeRequest` | Boolean! | Whether or not a user can perform `revert_on_current_merge_request` on this resource |
+### MergeRequestSetAssigneesPayload
+
+| Name | Type | Description |
+| --- | ---- | ---------- |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `errors` | String! => Array | Reasons why the mutation failed. |
+| `mergeRequest` | MergeRequest | The merge request after mutation |
+
+### MergeRequestSetLabelsPayload
+
+| Name | Type | Description |
+| --- | ---- | ---------- |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `errors` | String! => Array | Reasons why the mutation failed. |
+| `mergeRequest` | MergeRequest | The merge request after mutation |
+
+### MergeRequestSetLockedPayload
+
+| Name | Type | Description |
+| --- | ---- | ---------- |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `errors` | String! => Array | Reasons why the mutation failed. |
+| `mergeRequest` | MergeRequest | The merge request after mutation |
+
+### MergeRequestSetMilestonePayload
+
+| Name | Type | Description |
+| --- | ---- | ---------- |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `errors` | String! => Array | Reasons why the mutation failed. |
+| `mergeRequest` | MergeRequest | The merge request after mutation |
+
+### MergeRequestSetSubscriptionPayload
+
+| Name | Type | Description |
+| --- | ---- | ---------- |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `errors` | String! => Array | Reasons why the mutation failed. |
+| `mergeRequest` | MergeRequest | The merge request after mutation |
+
### MergeRequestSetWipPayload
| Name | Type | Description |
@@ -469,36 +505,37 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
-| `version` | String! | |
-| `revision` | String! | |
+| `version` | String! | Version |
+| `revision` | String! | Revision |
### Milestone
| Name | Type | Description |
| --- | ---- | ---------- |
-| `description` | String | |
-| `title` | String! | |
-| `state` | String! | |
-| `dueDate` | Time | |
-| `startDate` | Time | |
-| `createdAt` | Time! | |
-| `updatedAt` | Time! | |
+| `id` | ID! | ID of the milestone |
+| `description` | String | Description of the milestone |
+| `title` | String! | Title of the milestone |
+| `state` | String! | State of the milestone |
+| `dueDate` | Time | Timestamp of the milestone due date |
+| `startDate` | Time | Timestamp of the milestone start date |
+| `createdAt` | Time! | Timestamp of milestone creation |
+| `updatedAt` | Time! | Timestamp of last milestone update |
### Namespace
| Name | Type | Description |
| --- | ---- | ---------- |
-| `id` | ID! | |
-| `name` | String! | |
-| `path` | String! | |
-| `fullName` | String! | |
-| `fullPath` | ID! | |
-| `description` | String | |
+| `id` | ID! | ID of the namespace |
+| `name` | String! | Name of the namespace |
+| `path` | String! | Path of the namespace |
+| `fullName` | String! | Full name of the namespace |
+| `fullPath` | ID! | Full path of the namespace |
+| `description` | String | Description of the namespace |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
-| `visibility` | String | |
-| `lfsEnabled` | Boolean | |
-| `requestAccessEnabled` | Boolean | |
-| `rootStorageStatistics` | RootStorageStatistics | The aggregated storage statistics. Only available for root namespaces |
+| `visibility` | String | Visibility of the namespace |
+| `lfsEnabled` | Boolean | Indicates if Large File Storage (LFS) is enabled for namespace |
+| `requestAccessEnabled` | Boolean | Indicates if users can request access to namespace |
+| `rootStorageStatistics` | RootStorageStatistics | Aggregated storage statistics of the namespace. Only available for root namespaces |
### Note
@@ -570,46 +607,47 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
| `userPermissions` | ProjectPermissions! | Permissions for the current user on the resource |
-| `id` | ID! | |
-| `fullPath` | ID! | |
-| `path` | String! | |
-| `nameWithNamespace` | String! | |
-| `name` | String! | |
-| `description` | String | |
+| `id` | ID! | ID of the project |
+| `fullPath` | ID! | Full path of the project |
+| `path` | String! | Path of the project |
+| `nameWithNamespace` | String! | Full name of the project with its namespace |
+| `name` | String! | Name of the project (without namespace) |
+| `description` | String | Short description of the project |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
-| `tagList` | String | |
-| `sshUrlToRepo` | String | |
-| `httpUrlToRepo` | String | |
-| `webUrl` | String | |
-| `starCount` | Int! | |
-| `forksCount` | Int! | |
-| `createdAt` | Time | |
-| `lastActivityAt` | Time | |
-| `archived` | Boolean | |
-| `visibility` | String | |
-| `containerRegistryEnabled` | Boolean | |
-| `sharedRunnersEnabled` | Boolean | |
-| `lfsEnabled` | Boolean | |
-| `mergeRequestsFfOnlyEnabled` | Boolean | |
-| `avatarUrl` | String | |
-| `issuesEnabled` | Boolean | |
-| `mergeRequestsEnabled` | Boolean | |
-| `wikiEnabled` | Boolean | |
-| `snippetsEnabled` | Boolean | |
-| `jobsEnabled` | Boolean | |
-| `publicJobs` | Boolean | |
-| `openIssuesCount` | Int | |
-| `importStatus` | String | |
-| `onlyAllowMergeIfPipelineSucceeds` | Boolean | |
-| `requestAccessEnabled` | Boolean | |
-| `onlyAllowMergeIfAllDiscussionsAreResolved` | Boolean | |
-| `printingMergeRequestLinkEnabled` | Boolean | |
-| `namespace` | Namespace | |
-| `group` | Group | |
-| `statistics` | ProjectStatistics | |
-| `repository` | Repository | |
-| `mergeRequest` | MergeRequest | |
-| `issue` | ExtendedIssue | |
+| `tagList` | String | List of project tags |
+| `sshUrlToRepo` | String | URL to connect to the project via SSH |
+| `httpUrlToRepo` | String | URL to connect to the project via HTTPS |
+| `webUrl` | String | Web URL of the project |
+| `starCount` | Int! | Number of times the project has been starred |
+| `forksCount` | Int! | Number of times the project has been forked |
+| `createdAt` | Time | Timestamp of the project creation |
+| `lastActivityAt` | Time | Timestamp of the project last activity |
+| `archived` | Boolean | Archived status of the project |
+| `visibility` | String | Visibility of the project |
+| `containerRegistryEnabled` | Boolean | Indicates if the project stores Docker container images in a container registry |
+| `sharedRunnersEnabled` | Boolean | Indicates if shared runners are enabled on the project |
+| `lfsEnabled` | Boolean | Indicates if the project has Large File Storage (LFS) enabled |
+| `mergeRequestsFfOnlyEnabled` | Boolean | Indicates if no merge commits should be created and all merges should instead be fast-forwarded, which means that merging is only allowed if the branch could be fast-forwarded. |
+| `avatarUrl` | String | URL to avatar image file of the project |
+| `issuesEnabled` | Boolean | (deprecated) Does this project have issues enabled?. Use `issues_access_level` instead |
+| `mergeRequestsEnabled` | Boolean | (deprecated) Does this project have merge_requests enabled?. Use `merge_requests_access_level` instead |
+| `wikiEnabled` | Boolean | (deprecated) Does this project have wiki enabled?. Use `wiki_access_level` instead |
+| `snippetsEnabled` | Boolean | (deprecated) Does this project have snippets enabled?. Use `snippets_access_level` instead |
+| `jobsEnabled` | Boolean | (deprecated) Enable jobs for this project. Use `builds_access_level` instead |
+| `publicJobs` | Boolean | Indicates if there is public access to pipelines and job details of the project, including output logs and artifacts |
+| `openIssuesCount` | Int | Number of open issues for the project |
+| `importStatus` | String | Status of project import background job of the project |
+| `onlyAllowMergeIfPipelineSucceeds` | Boolean | Indicates if merge requests of the project can only be merged with successful jobs |
+| `requestAccessEnabled` | Boolean | Indicates if users can request member access to the project |
+| `onlyAllowMergeIfAllDiscussionsAreResolved` | Boolean | Indicates if merge requests of the project can only be merged when all the discussions are resolved |
+| `printingMergeRequestLinkEnabled` | Boolean | Indicates if a link to create or view a merge request should display after a push to Git repositories of the project from the command line |
+| `removeSourceBranchAfterMerge` | Boolean | Indicates if `Delete source branch` option should be enabled by default for all new merge requests of the project |
+| `namespace` | Namespace | Namespace of the project |
+| `group` | Group | Group of the project |
+| `statistics` | ProjectStatistics | Statistics of the project |
+| `repository` | Repository | Git repository of the project |
+| `mergeRequest` | MergeRequest | A single merge request of the project |
+| `issue` | Issue | A single issue of the project |
### ProjectPermissions
@@ -661,13 +699,13 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
-| `commitCount` | Int! | |
-| `storageSize` | Int! | |
-| `repositorySize` | Int! | |
-| `lfsObjectsSize` | Int! | |
-| `buildArtifactsSize` | Int! | |
-| `packagesSize` | Int! | |
-| `wikiSize` | Int | |
+| `commitCount` | Int! | Commit count of the project |
+| `storageSize` | Int! | Storage size of the project |
+| `repositorySize` | Int! | Repository size of the project |
+| `lfsObjectsSize` | Int! | Large File Storage (LFS) object size of the project |
+| `buildArtifactsSize` | Int! | Build artifacts size of the project |
+| `packagesSize` | Int! | Packages size of the project |
+| `wikiSize` | Int | Wiki size of the project |
### RemoveAwardEmojiPayload
@@ -681,10 +719,10 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
-| `rootRef` | String | |
-| `empty` | Boolean! | |
-| `exists` | Boolean! | |
-| `tree` | Tree | |
+| `rootRef` | String | Default branch of the repository |
+| `empty` | Boolean! | Indicates repository has no visible content |
+| `exists` | Boolean! | Indicates a corresponding Git repository exists on disk |
+| `tree` | Tree | Tree of the repository |
### RootStorageStatistics
@@ -702,6 +740,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
| `id` | ID! | |
+| `sha` | String! | Last commit sha for entry |
| `name` | String! | |
| `type` | EntryType! | |
| `path` | String! | |
@@ -713,8 +752,8 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
-| `count` | Int! | |
-| `completedCount` | Int! | |
+| `count` | Int! | Number of total tasks |
+| `completedCount` | Int! | Number of completed tasks |
### Todo
@@ -730,6 +769,14 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| `state` | TodoStateEnum! | State of the todo |
| `createdAt` | Time! | Timestamp this todo was created |
+### TodoMarkDonePayload
+
+| Name | Type | Description |
+| --- | ---- | ---------- |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `errors` | String! => Array | Reasons why the mutation failed. |
+| `todo` | Todo! | The requested todo |
+
### ToggleAwardEmojiPayload
| Name | Type | Description |
@@ -750,6 +797,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
| `id` | ID! | |
+| `sha` | String! | Last commit sha for entry |
| `name` | String! | |
| `type` | EntryType! | |
| `path` | String! | |
@@ -776,7 +824,7 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| Name | Type | Description |
| --- | ---- | ---------- |
-| `name` | String! | |
-| `username` | String! | |
-| `avatarUrl` | String! | |
-| `webUrl` | String! | |
+| `name` | String! | Human-readable name of the user |
+| `username` | String! | Username of the user. Unique within this instance of GitLab |
+| `avatarUrl` | String! | URL of the user's avatar |
+| `webUrl` | String! | Web URL of the user |
diff --git a/doc/api/group_clusters.md b/doc/api/group_clusters.md
index e878bb5fa4d..143f5762811 100644
--- a/doc/api/group_clusters.md
+++ b/doc/api/group_clusters.md
@@ -53,6 +53,16 @@ Example response:
"api_url":"https://104.197.68.152",
"authorization_type":"rbac",
"ca_cert":"-----BEGIN CERTIFICATE-----\r\nhFiK1L61owwDQYJKoZIhvcNAQELBQAw\r\nLzEtMCsGA1UEAxMkZDA1YzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM4ZDBj\r\nMB4XDTE4MTIyNzIwMDM1MVoXDTIzMTIyNjIxMDM1MVowLzEtMCsGA1UEAxMkZDA1\r\nYzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM.......-----END CERTIFICATE-----"
+ },
+ "management_project":
+ {
+ "id":2,
+ "description":null,
+ "name":"project2",
+ "name_with_namespace":"John Doe8 / project2",
+ "path":"project2",
+ "path_with_namespace":"namespace2/project2",
+ "created_at":"2019-10-11T02:55:54.138Z"
}
},
{
@@ -111,6 +121,16 @@ Example response:
"authorization_type":"rbac",
"ca_cert":"-----BEGIN CERTIFICATE-----\r\nhFiK1L61owwDQYJKoZIhvcNAQELBQAw\r\nLzEtMCsGA1UEAxMkZDA1YzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM4ZDBj\r\nMB4XDTE4MTIyNzIwMDM1MVoXDTIzMTIyNjIxMDM1MVowLzEtMCsGA1UEAxMkZDA1\r\nYzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM.......-----END CERTIFICATE-----"
},
+ "management_project":
+ {
+ "id":2,
+ "description":null,
+ "name":"project2",
+ "name_with_namespace":"John Doe8 / project2",
+ "path":"project2",
+ "path_with_namespace":"namespace2/project2",
+ "created_at":"2019-10-11T02:55:54.138Z"
+ },
"group":
{
"id":26,
@@ -135,6 +155,7 @@ Parameters:
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) |
| `name` | String | yes | The name of the cluster |
| `domain` | String | no | The [base domain](../user/group/clusters/index.md#base-domain) of the cluster |
+| `management_project_id` | integer | no | The ID of the [management project](../user/clusters/management_project.md) for the cluster |
| `enabled` | Boolean | no | Determines if cluster is active or not, defaults to true |
| `managed` | Boolean | no | Determines if GitLab will manage namespaces and service accounts for this cluster, defaults to true |
| `platform_kubernetes_attributes[api_url]` | String | yes | The URL to access the Kubernetes API |
@@ -178,6 +199,7 @@ Example response:
"authorization_type":"rbac",
"ca_cert":"-----BEGIN CERTIFICATE-----\r\nhFiK1L61owwDQYJKoZIhvcNAQELBQAw\r\nLzEtMCsGA1UEAxMkZDA1YzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM4ZDBj\r\nMB4XDTE4MTIyNzIwMDM1MVoXDTIzMTIyNjIxMDM1MVowLzEtMCsGA1UEAxMkZDA1\r\nYzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM.......-----END CERTIFICATE-----"
},
+ "management_project":null,
"group":
{
"id":26,
@@ -210,7 +232,7 @@ Parameters:
NOTE: **Note:**
`name`, `api_url`, `ca_cert` and `token` can only be updated if the cluster was added
-through the ["Add existing Kubernetes cluster"](../user/project/clusters/index.md#add-existing-kubernetes-cluster) option or
+through the ["Add existing Kubernetes cluster"](../user/project/clusters/add_remove_clusters.md#add-existing-cluster) option or
through the ["Add existing cluster to group"](#add-existing-cluster-to-group) endpoint.
Example request:
@@ -248,6 +270,16 @@ Example response:
"authorization_type":"rbac",
"ca_cert":null
},
+ "management_project":
+ {
+ "id":2,
+ "description":null,
+ "name":"project2",
+ "name_with_namespace":"John Doe8 / project2",
+ "path":"project2",
+ "path_with_namespace":"namespace2/project2",
+ "created_at":"2019-10-11T02:55:54.138Z"
+ },
"group":
{
"id":26,
diff --git a/doc/api/groups.md b/doc/api/groups.md
index 312bd04e24c..94f46b11a0f 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -611,6 +611,10 @@ GET /groups?search=foobar
]
```
+## Group Audit Events **(STARTER)**
+
+Group audit events can be accessed via the [Group Audit Events API](audit_events.md#group-audit-events-starter)
+
## Sync group with LDAP **(CORE ONLY)**
Syncs the group with its linked LDAP group. Only available to group owners and administrators.
diff --git a/doc/api/issues.md b/doc/api/issues.md
index 0ddbb18ce92..54b27370741 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -577,14 +577,22 @@ the `weight` parameter:
```
Users on GitLab [Ultimate](https://about.gitlab.com/pricing/) will additionally see
-the `epic_iid` property:
+the `epic` property:
-```json
+```javascript
{
"project_id" : 4,
"description" : "Omnis vero earum sunt corporis dolor et placeat.",
- "epic_iid" : 42,
- ...
+ "epic": {
+ "epic_iid" : 5, //deprecated, use `iid` of the `epic` attribute
+ "epic": {
+ "id" : 42,
+ "iid" : 5,
+ "title": "My epic epic",
+ "url" : "/groups/h5bp/-/epics/5",
+ "group_id": 8
+ },
+ // ...
}
```
@@ -592,6 +600,9 @@ the `epic_iid` property:
**Note**: The `closed_by` attribute was [introduced in GitLab 10.6][ce-17042]. This value will only be present for issues which were closed after GitLab 10.6 and when the user account that closed the issue still exists.
+**Note**: The `epic_iid` attribute is deprecated and [will be removed in 13.0](https://gitlab.com/gitlab-org/gitlab/issues/35157).
+Please use `iid` of the `epic` attribute instead.
+
## New issue
Creates a new project issue.
@@ -1416,6 +1427,7 @@ Example response:
"merge_status": "cannot_be_merged",
"sha": "3b7b528e9353295c1c125dad281ac5b5deae5f12",
"merge_commit_sha": null,
+ "squash_commit_sha": null,
"discussion_locked": null,
"should_remove_source_branch": null,
"force_remove_source_branch": false,
@@ -1546,6 +1558,7 @@ Example response:
"merge_status": "unchecked",
"sha": "5a62481d563af92b8e32d735f2fa63b94e806835",
"merge_commit_sha": null,
+ "squash_commit_sha": null,
"user_notes_count": 1,
"should_remove_source_branch": null,
"force_remove_source_branch": false,
diff --git a/doc/api/license.md b/doc/api/license.md
index 12f1d03d576..c56a5fee95a 100644
--- a/doc/api/license.md
+++ b/doc/api/license.md
@@ -17,6 +17,7 @@ GET /license
"starts_at": "2018-01-27",
"expires_at": "2022-01-27",
"historical_max": 300,
+ "maximum_user_count": 300,
"expired": false,
"overage": 200,
"user_limit": 100,
@@ -46,6 +47,7 @@ GET /licenses
"starts_at": "2018-01-27",
"expires_at": "2022-01-27",
"historical_max": 300,
+ "maximum_user_count": 300,
"expired": false,
"overage": 200,
"user_limit": 100,
@@ -64,6 +66,7 @@ GET /licenses
"starts_at": "2018-01-27",
"expires_at": "2022-01-27",
"historical_max": 300,
+ "maximum_user_count": 300,
"expired": false,
"overage": 200,
"user_limit": 100,
@@ -112,6 +115,7 @@ Example response:
"starts_at": "2018-01-27",
"expires_at": "2022-01-27",
"historical_max": 300,
+ "maximum_user_count": 300,
"expired": false,
"overage": 200,
"user_limit": 100,
@@ -155,6 +159,7 @@ Example response:
"starts_at": "2018-01-27",
"expires_at": "2022-01-27",
"historical_max": 300,
+ "maximum_user_count": 300,
"expired": false,
"overage": 200,
"user_limit": 100,
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 4bc46c3030d..7074d0249ef 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -126,6 +126,7 @@ Parameters:
"merge_status": "can_be_merged",
"sha": "8888888888888888888888888888888888888888",
"merge_commit_sha": null,
+ "squash_commit_sha": null,
"user_notes_count": 1,
"discussion_locked": null,
"should_remove_source_branch": true,
@@ -287,6 +288,7 @@ Parameters:
"merge_status": "can_be_merged",
"sha": "8888888888888888888888888888888888888888",
"merge_commit_sha": null,
+ "squash_commit_sha": null,
"user_notes_count": 1,
"discussion_locked": null,
"should_remove_source_branch": true,
@@ -304,7 +306,9 @@ Parameters:
"task_completion_status":{
"count":0,
"completed_count":0
- }
+ },
+ "has_conflicts": false,
+ "blocking_discussions_resolved": true
}
]
```
@@ -438,6 +442,7 @@ Parameters:
"merge_status": "can_be_merged",
"sha": "8888888888888888888888888888888888888888",
"merge_commit_sha": null,
+ "squash_commit_sha": null,
"user_notes_count": 1,
"discussion_locked": null,
"should_remove_source_branch": true,
@@ -453,7 +458,9 @@ Parameters:
"task_completion_status":{
"count":0,
"completed_count":0
- }
+ },
+ "has_conflicts": false,
+ "blocking_discussions_resolved": true
}
]
```
@@ -559,6 +566,7 @@ Parameters:
"merge_error": null,
"sha": "8888888888888888888888888888888888888888",
"merge_commit_sha": null,
+ "squash_commit_sha": null,
"user_notes_count": 1,
"discussion_locked": null,
"should_remove_source_branch": true,
@@ -606,7 +614,9 @@ Parameters:
"task_completion_status":{
"count":0,
"completed_count":0
- }
+ },
+ "has_conflicts": false,
+ "blocking_discussions_resolved": true
}
```
@@ -763,6 +773,7 @@ Parameters:
"subscribed" : true,
"sha": "8888888888888888888888888888888888888888",
"merge_commit_sha": null,
+ "squash_commit_sha": null,
"user_notes_count": 1,
"changes_count": "1",
"should_remove_source_branch": true,
@@ -970,6 +981,7 @@ order for it to take effect:
"merge_error": null,
"sha": "8888888888888888888888888888888888888888",
"merge_commit_sha": null,
+ "squash_commit_sha": null,
"user_notes_count": 1,
"discussion_locked": null,
"should_remove_source_branch": true,
@@ -1123,6 +1135,7 @@ Must include at least one non-required attribute from above.
"merge_error": null,
"sha": "8888888888888888888888888888888888888888",
"merge_commit_sha": null,
+ "squash_commit_sha": null,
"user_notes_count": 1,
"discussion_locked": null,
"should_remove_source_branch": true,
@@ -1292,6 +1305,7 @@ Parameters:
"merge_error": null,
"sha": "8888888888888888888888888888888888888888",
"merge_commit_sha": null,
+ "squash_commit_sha": null,
"user_notes_count": 1,
"discussion_locked": null,
"should_remove_source_branch": true,
@@ -1464,6 +1478,7 @@ Parameters:
"merge_error": null,
"sha": "8888888888888888888888888888888888888888",
"merge_commit_sha": null,
+ "squash_commit_sha": null,
"user_notes_count": 1,
"discussion_locked": null,
"should_remove_source_branch": true,
@@ -1749,6 +1764,7 @@ Example response:
"merge_status": "can_be_merged",
"sha": "8888888888888888888888888888888888888888",
"merge_commit_sha": null,
+ "squash_commit_sha": null,
"user_notes_count": 1,
"discussion_locked": null,
"should_remove_source_branch": true,
@@ -1894,6 +1910,7 @@ Example response:
"merge_status": "can_be_merged",
"sha": "8888888888888888888888888888888888888888",
"merge_commit_sha": null,
+ "squash_commit_sha": null,
"user_notes_count": 1,
"discussion_locked": null,
"should_remove_source_branch": true,
@@ -2055,6 +2072,7 @@ Example response:
"subscribed": true,
"sha": "8888888888888888888888888888888888888888",
"merge_commit_sha": null,
+ "squash_commit_sha": null,
"user_notes_count": 7,
"changes_count": "1",
"should_remove_source_branch": true,
diff --git a/doc/api/packages.md b/doc/api/packages.md
index 13d773e4f99..bab3f91bc40 100644
--- a/doc/api/packages.md
+++ b/doc/api/packages.md
@@ -2,7 +2,9 @@
This is the API docs of [GitLab Packages](../administration/packages/index.md).
-## List project packages
+## List packages
+
+### Within a project
> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/9259) in GitLab 11.8.
@@ -42,6 +44,47 @@ Example response:
By default, the `GET` request will return 20 results, since the API is [paginated](README.md#pagination).
+### Within a group
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/18871) in GitLab 12.5.
+
+Get a list of project packages at the group level.
+When accessed without authentication, only packages of public projects are returned.
+
+```
+GET /groups/:id/packages
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | ID or [URL-encoded path of the group](README.md#namespaced-path-encoding). |
+| `exclude_subgroups` | boolean | false | If the param is included as true, packages from projects from subgroups are not listed. Default is `false`. |
+
+```bash
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/:id/packages?exclude_subgroups=true
+```
+
+Example response:
+
+```json
+[
+ {
+ "id": 1,
+ "name": "com/mycompany/my-app",
+ "version": "1.0-SNAPSHOT",
+ "package_type": "maven"
+ },
+ {
+ "id": 2,
+ "name": "@foo/bar",
+ "version": "1.0.3",
+ "package_type": "npm"
+ }
+]
+```
+
+By default, the `GET` request will return 20 results, since the API is [paginated](README.md#pagination).
+
## Get a project package
> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/9667) in GitLab 11.9.
diff --git a/doc/api/pages_domains.md b/doc/api/pages_domains.md
index 9678203eb40..9d482781cde 100644
--- a/doc/api/pages_domains.md
+++ b/doc/api/pages_domains.md
@@ -22,6 +22,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/ap
"domain": "ssl.domain.example",
"url": "https://ssl.domain.example",
"project_id": 1337,
+ "auto_ssl_enabled": false,
"certificate": {
"expired": false,
"expiration": "2020-04-12T14:32:00.000Z"
@@ -55,6 +56,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/ap
{
"domain": "ssl.domain.example",
"url": "https://ssl.domain.example",
+ "auto_ssl_enabled": false,
"certificate": {
"subject": "/O=Example, Inc./OU=Example Origin CA/CN=Example Origin Certificate",
"expired": false,
@@ -76,7 +78,7 @@ GET /projects/:id/pages/domains/:domain
| Attribute | Type | Required | Description |
| --------- | -------------- | -------- | ---------------------------------------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
-| `domain` | string | yes | The domain |
+| `domain` | string | yes | The custom domain indicated by the user |
```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/pages/domains/www.domain.example
@@ -97,6 +99,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/ap
{
"domain": "ssl.domain.example",
"url": "https://ssl.domain.example",
+ "auto_ssl_enabled": false,
"certificate": {
"subject": "/O=Example, Inc./OU=Example Origin CA/CN=Example Origin Certificate",
"expired": false,
@@ -114,12 +117,13 @@ Creates a new pages domain. The user must have permissions to create new pages d
POST /projects/:id/pages/domains
```
-| Attribute | Type | Required | Description |
-| ------------- | -------------- | -------- | ---------------------------------------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
-| `domain` | string | yes | The domain |
-| `certificate` | file/string | no | The certificate in PEM format with intermediates following in most specific to least specific order.|
-| `key` | file/string | no | The certificate key in PEM format. |
+| Attribute | Type | Required | Description |
+| -------------------| -------------- | -------- | ---------------------------------------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `domain` | string | yes | The custom domain indicated by the user |
+| `auto_ssl_enabled` | boolean | no | Enables [automatic generation](../user/project/pages/custom_domains_ssl_tls_certification/lets_encrypt_integration.md) of SSL certificates issued by Let's Encrypt for custom domains. |
+| `certificate` | file/string | no | The certificate in PEM format with intermediates following in most specific to least specific order.|
+| `key` | file/string | no | The certificate key in PEM format. |
```bash
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form "domain=ssl.domain.example" --form "certificate=@/path/to/cert.pem" --form "key=@/path/to/key.pem" https://gitlab.example.com/api/v4/projects/5/pages/domains
@@ -129,10 +133,15 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form "domain
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form "domain=ssl.domain.example" --form "certificate=$CERT_PEM" --form "key=$KEY_PEM" https://gitlab.example.com/api/v4/projects/5/pages/domains
```
+```bash
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form "domain=ssl.domain.example" --form "auto_ssl_enabled=true" https://gitlab.example.com/api/v4/projects/5/pages/domains
+```
+
```json
{
"domain": "ssl.domain.example",
"url": "https://ssl.domain.example",
+ "auto_ssl_enabled": true,
"certificate": {
"subject": "/O=Example, Inc./OU=Example Origin CA/CN=Example Origin Certificate",
"expired": false,
@@ -150,12 +159,15 @@ Updates an existing project pages domain. The user must have permissions to chan
PUT /projects/:id/pages/domains/:domain
```
-| Attribute | Type | Required | Description |
-| ------------- | -------------- | -------- | ---------------------------------------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
-| `domain` | string | yes | The domain |
-| `certificate` | file/string | no | The certificate in PEM format with intermediates following in most specific to least specific order.|
-| `key` | file/string | no | The certificate key in PEM format. |
+| Attribute | Type | Required | Description |
+| ------------------ | -------------- | -------- | ---------------------------------------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `domain` | string | yes | The custom domain indicated by the user |
+| `auto_ssl_enabled` | boolean | no | Enables [automatic generation](../user/project/pages/custom_domains_ssl_tls_certification/lets_encrypt_integration.md) of SSL certificates issued by Let's Encrypt for custom domains. |
+| `certificate` | file/string | no | The certificate in PEM format with intermediates following in most specific to least specific order.|
+| `key` | file/string | no | The certificate key in PEM format. |
+
+### Adding certificate
```bash
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --form "certificate=@/path/to/cert.pem" --form "key=@/path/to/key.pem" https://gitlab.example.com/api/v4/projects/5/pages/domains/ssl.domain.example
@@ -169,6 +181,7 @@ curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --form "certifi
{
"domain": "ssl.domain.example",
"url": "https://ssl.domain.example",
+ "auto_ssl_enabled": false,
"certificate": {
"subject": "/O=Example, Inc./OU=Example Origin CA/CN=Example Origin Certificate",
"expired": false,
@@ -178,6 +191,36 @@ curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --form "certifi
}
```
+### Enabling Let's Encrypt integration for Pages custom domains
+
+```bash
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --form "auto_ssl_enabled=true" https://gitlab.example.com/api/v4/projects/5/pages/domains/ssl.domain.example
+```
+
+```json
+{
+ "domain": "ssl.domain.example",
+ "url": "https://ssl.domain.example",
+ "auto_ssl_enabled": true
+}
+```
+
+### Removing certificate
+
+To remove the SSL certificate attached to the Pages domain, run:
+
+```bash
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --form "certificate=" --form "key=" https://gitlab.example.com/api/v4/projects/5/pages/domains/ssl.domain.example
+```
+
+```json
+{
+ "domain": "ssl.domain.example",
+ "url": "https://ssl.domain.example",
+ "auto_ssl_enabled": false
+}
+```
+
## Delete pages domain
Deletes an existing project pages domain.
@@ -189,7 +232,7 @@ DELETE /projects/:id/pages/domains/:domain
| Attribute | Type | Required | Description |
| --------- | -------------- | -------- | ---------------------------------------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
-| `domain` | string | yes | The domain |
+| `domain` | string | yes | The custom domain indicated by the user |
```bash
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/pages/domains/ssl.domain.example
diff --git a/doc/api/project_clusters.md b/doc/api/project_clusters.md
index 633ef20deb4..1aa225d30ab 100644
--- a/doc/api/project_clusters.md
+++ b/doc/api/project_clusters.md
@@ -1,7 +1,6 @@
# Project clusters API
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/23922)
-in GitLab 11.7.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/23922) in GitLab 11.7.
NOTE: **Note:**
User will need at least maintainer access to use these endpoints.
@@ -54,6 +53,16 @@ Example response:
"namespace":"cluster-1-namespace",
"authorization_type":"rbac",
"ca_cert":"-----BEGIN CERTIFICATE-----\r\nhFiK1L61owwDQYJKoZIhvcNAQELBQAw\r\nLzEtMCsGA1UEAxMkZDA1YzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM4ZDBj\r\nMB4XDTE4MTIyNzIwMDM1MVoXDTIzMTIyNjIxMDM1MVowLzEtMCsGA1UEAxMkZDA1\r\nYzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM.......-----END CERTIFICATE-----"
+ },
+ "management_project":
+ {
+ "id":2,
+ "description":null,
+ "name":"project2",
+ "name_with_namespace":"John Doe8 / project2",
+ "path":"project2",
+ "path_with_namespace":"namespace2/project2",
+ "created_at":"2019-10-11T02:55:54.138Z"
}
},
{
@@ -113,6 +122,16 @@ Example response:
"authorization_type":"rbac",
"ca_cert":"-----BEGIN CERTIFICATE-----\r\nhFiK1L61owwDQYJKoZIhvcNAQELBQAw\r\nLzEtMCsGA1UEAxMkZDA1YzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM4ZDBj\r\nMB4XDTE4MTIyNzIwMDM1MVoXDTIzMTIyNjIxMDM1MVowLzEtMCsGA1UEAxMkZDA1\r\nYzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM.......-----END CERTIFICATE-----"
},
+ "management_project":
+ {
+ "id":2,
+ "description":null,
+ "name":"project2",
+ "name_with_namespace":"John Doe8 / project2",
+ "path":"project2",
+ "path_with_namespace":"namespace2/project2",
+ "created_at":"2019-10-11T02:55:54.138Z"
+ },
"project":
{
"id":26,
@@ -205,6 +224,7 @@ Example response:
"authorization_type":"rbac",
"ca_cert":"-----BEGIN CERTIFICATE-----\r\nhFiK1L61owwDQYJKoZIhvcNAQELBQAw\r\nLzEtMCsGA1UEAxMkZDA1YzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM4ZDBj\r\nMB4XDTE4MTIyNzIwMDM1MVoXDTIzMTIyNjIxMDM1MVowLzEtMCsGA1UEAxMkZDA1\r\nYzQ1YjctNzdiMS00NDY0LThjNmEtMTQ0ZDJkZjM.......-----END CERTIFICATE-----"
},
+ "management_project":null,
"project":
{
"id":26,
@@ -253,6 +273,7 @@ Parameters:
| `cluster_id` | integer | yes | The ID of the cluster |
| `name` | String | no | The name of the cluster |
| `domain` | String | no | The [base domain](../user/project/clusters/index.md#base-domain) of the cluster |
+| `management_project_id` | integer | no | The ID of the [management project](../user/clusters/management_project.md) for the cluster |
| `platform_kubernetes_attributes[api_url]` | String | no | The URL to access the Kubernetes API |
| `platform_kubernetes_attributes[token]` | String | no | The token to authenticate against Kubernetes |
| `platform_kubernetes_attributes[ca_cert]` | String | no | TLS certificate (needed if API is using a self-signed TLS certificate |
@@ -261,7 +282,7 @@ Parameters:
NOTE: **Note:**
`name`, `api_url`, `ca_cert` and `token` can only be updated if the cluster was added
-through the ["Add existing Kubernetes cluster"](../user/project/clusters/index.md#add-existing-kubernetes-cluster) option or
+through the ["Add existing Kubernetes cluster"](../user/project/clusters/add_remove_clusters.md#add-existing-cluster) option or
through the ["Add existing cluster to project"](#add-existing-cluster-to-project) endpoint.
Example request:
@@ -300,6 +321,16 @@ Example response:
"authorization_type":"rbac",
"ca_cert":null
},
+ "management_project":
+ {
+ "id":2,
+ "description":null,
+ "name":"project2",
+ "name_with_namespace":"John Doe8 / project2",
+ "path":"project2",
+ "path_with_namespace":"namespace2/project2",
+ "created_at":"2019-10-11T02:55:54.138Z"
+ },
"project":
{
"id":26,
@@ -351,5 +382,5 @@ Parameters:
Example request:
```bash
-curl --header 'Private-Token: <your_access_token>' https://gitlab.example.com/api/v4/projects/26/clusters/23'
+curl --request DELETE --header 'Private-Token: <your_access_token>' https://gitlab.example.com/api/v4/projects/26/clusters/23
```
diff --git a/doc/api/projects.md b/doc/api/projects.md
index c352b972b17..222ab729810 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -58,6 +58,8 @@ GET /projects
| `wiki_checksum_failed` | boolean | no | **(PREMIUM)** Limit projects where the wiki checksum calculation has failed ([Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/6137) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.2) |
| `repository_checksum_failed` | boolean | no | **(PREMIUM)** Limit projects where the repository checksum calculation has failed ([Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/6137) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.2) |
| `min_access_level` | integer | no | Limit by current user minimal [access level](members.md) |
+| `id_after` | integer | no | Limit results to projects with IDs greater than the specified ID |
+| `id_before` | integer | no | Limit results to projects with IDs less than the specified ID |
When `simple=true` or the user is unauthenticated this returns something like:
@@ -148,6 +150,7 @@ When the user is authenticated and `simple` is not set this returns something li
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
"only_allow_merge_if_all_discussions_are_resolved": false,
+ "remove_source_branch_after_merge": false,
"request_access_enabled": false,
"merge_method": "merge",
"statistics": {
@@ -232,6 +235,7 @@ When the user is authenticated and `simple` is not set this returns something li
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
"only_allow_merge_if_all_discussions_are_resolved": false,
+ "remove_source_branch_after_merge": false,
"request_access_enabled": false,
"merge_method": "merge",
"statistics": {
@@ -302,6 +306,8 @@ GET /users/:user_id/projects
| `with_merge_requests_enabled` | boolean | no | Limit by enabled merge requests feature |
| `with_programming_language` | string | no | Limit by projects which use the given programming language |
| `min_access_level` | integer | no | Limit by current user minimal [access level](members.md) |
+| `id_after` | integer | no | Limit results to projects with IDs greater than the specified ID |
+| `id_before` | integer | no | Limit results to projects with IDs less than the specified ID |
```json
[
@@ -357,6 +363,7 @@ GET /users/:user_id/projects
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
"only_allow_merge_if_all_discussions_are_resolved": false,
+ "remove_source_branch_after_merge": false,
"request_access_enabled": false,
"merge_method": "merge",
"statistics": {
@@ -441,6 +448,7 @@ GET /users/:user_id/projects
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
"only_allow_merge_if_all_discussions_are_resolved": false,
+ "remove_source_branch_after_merge": false,
"request_access_enabled": false,
"merge_method": "merge",
"statistics": {
@@ -550,6 +558,7 @@ Example response:
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
"only_allow_merge_if_all_discussions_are_resolved": false,
+ "remove_source_branch_after_merge": false,
"request_access_enabled": false,
"merge_method": "merge",
"statistics": {
@@ -631,6 +640,7 @@ Example response:
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
"only_allow_merge_if_all_discussions_are_resolved": false,
+ "remove_source_branch_after_merge": false,
"request_access_enabled": false,
"merge_method": "merge",
"statistics": {
@@ -757,6 +767,7 @@ GET /projects/:id
"repository_storage": "default",
"only_allow_merge_if_pipeline_succeeds": false,
"only_allow_merge_if_all_discussions_are_resolved": false,
+ "remove_source_branch_after_merge": false,
"printing_merge_requests_link_enabled": true,
"request_access_enabled": false,
"merge_method": "merge",
@@ -917,6 +928,7 @@ POST /projects
| `only_allow_merge_if_pipeline_succeeds` | boolean | no | Set whether merge requests can only be merged with successful jobs |
| `only_allow_merge_if_all_discussions_are_resolved` | boolean | no | Set whether merge requests can only be merged when all the discussions are resolved |
| `merge_method` | string | no | Set the [merge method](#project-merge-method) used |
+| `remove_source_branch_after_merge` | boolean | no | Enable `Delete source branch` option by default for all new merge requests |
| `lfs_enabled` | boolean | no | Enable LFS |
| `request_access_enabled` | boolean | no | Allow users to request member access |
| `tag_list` | array | no | The list of tags for a project; put array of tags, that should be finally assigned to a project |
@@ -936,6 +948,7 @@ POST /projects
| `mirror_trigger_builds` | boolean | no | **(STARTER)** Pull mirroring triggers builds |
| `initialize_with_readme` | boolean | no | `false` by default |
| `template_name` | string | no | When used without `use_custom_template`, name of a [built-in project template](../gitlab-basics/create-project.md#built-in-templates). When used with `use_custom_template`, name of a custom project template |
+| `template_project_id` | integer | no | **(PREMIUM)** When used with `use_custom_template`, project ID of a custom project template. This is preferable to using `template_name` since `template_name` may be ambiguous. |
| `use_custom_template` | boolean | no | **(PREMIUM)** Use either custom [instance](../user/admin_area/custom_project_templates.md) or [group](../user/group/custom_project_templates.md) (with `group_with_project_templates_id`) project template |
| `group_with_project_templates_id` | integer | no | **(PREMIUM)** For group-level custom templates, specifies ID of group from which all the custom project templates are sourced. Leave empty for instance-level templates. Requires `use_custom_template` to be true |
@@ -978,6 +991,7 @@ POST /projects/user/:user_id
| `only_allow_merge_if_pipeline_succeeds` | boolean | no | Set whether merge requests can only be merged with successful jobs |
| `only_allow_merge_if_all_discussions_are_resolved` | boolean | no | Set whether merge requests can only be merged when all the discussions are resolved |
| `merge_method` | string | no | Set the [merge method](#project-merge-method) used |
+| `remove_source_branch_after_merge` | boolean | no | Enable `Delete source branch` option by default for all new merge requests |
| `lfs_enabled` | boolean | no | Enable LFS |
| `request_access_enabled` | boolean | no | Allow users to request member access |
| `tag_list` | array | no | The list of tags for a project; put array of tags, that should be finally assigned to a project |
@@ -1039,6 +1053,7 @@ PUT /projects/:id
| `only_allow_merge_if_pipeline_succeeds` | boolean | no | Set whether merge requests can only be merged with successful jobs |
| `only_allow_merge_if_all_discussions_are_resolved` | boolean | no | Set whether merge requests can only be merged when all the discussions are resolved |
| `merge_method` | string | no | Set the [merge method](#project-merge-method) used |
+| `remove_source_branch_after_merge` | boolean | no | Enable `Delete source branch` option by default for all new merge requests |
| `lfs_enabled` | boolean | no | Enable LFS |
| `request_access_enabled` | boolean | no | Allow users to request member access |
| `tag_list` | array | no | The list of tags for a project; put array of tags, that should be finally assigned to a project |
@@ -1165,6 +1180,7 @@ Example responses:
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
"only_allow_merge_if_all_discussions_are_resolved": false,
+ "remove_source_branch_after_merge": false,
"request_access_enabled": false,
"merge_method": "merge",
"_links": {
@@ -1252,6 +1268,7 @@ Example response:
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
"only_allow_merge_if_all_discussions_are_resolved": false,
+ "remove_source_branch_after_merge": false,
"request_access_enabled": false,
"merge_method": "merge",
"_links": {
@@ -1338,6 +1355,7 @@ Example response:
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
"only_allow_merge_if_all_discussions_are_resolved": false,
+ "remove_source_branch_after_merge": false,
"request_access_enabled": false,
"merge_method": "merge",
"_links": {
@@ -1511,6 +1529,7 @@ Example response:
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
"only_allow_merge_if_all_discussions_are_resolved": false,
+ "remove_source_branch_after_merge": false,
"request_access_enabled": false,
"merge_method": "merge",
"_links": {
@@ -1616,6 +1635,7 @@ Example response:
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
"only_allow_merge_if_all_discussions_are_resolved": false,
+ "remove_source_branch_after_merge": false,
"request_access_enabled": false,
"merge_method": "merge",
"_links": {
diff --git a/doc/api/releases/index.md b/doc/api/releases/index.md
index ee2df3e4c5d..7f41e237401 100644
--- a/doc/api/releases/index.md
+++ b/doc/api/releases/index.md
@@ -303,7 +303,7 @@ POST /projects/:id/releases
| Attribute | Type | Required | Description |
| -------------------| --------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../README.md#namespaced-path-encoding). |
-| `name` | string | yes | The release name. |
+| `name` | string | no | The release name. |
| `tag_name` | string | yes | The tag where the release will be created from. |
| `description` | string | yes | The description of the release. You can use [markdown](../../user/markdown.md). |
| `ref` | string | yes, if `tag_name` doesn't exist | If `tag_name` doesn't exist, the release will be created from `ref`. It can be a commit SHA, another tag name, or a branch name. |
diff --git a/doc/api/scim.md b/doc/api/scim.md
index 8cbd6103e88..cf9d8ebbec2 100644
--- a/doc/api/scim.md
+++ b/doc/api/scim.md
@@ -5,8 +5,7 @@
The SCIM API implements the [the RFC7644 protocol](https://tools.ietf.org/html/rfc7644).
NOTE: **Note:**
-[Group SSO](../user/group/saml_sso/index.md) and the feature
-flag `:group_scim` must be enabled for the group. For more information, see [SCIM setup documentation](../user/group/saml_sso/scim_setup.md#requirements).
+[Group SSO](../user/group/saml_sso/index.md) must be enabled for the group. For more information, see [SCIM setup documentation](../user/group/saml_sso/scim_setup.md#requirements).
## Get a list of SAML users
@@ -22,7 +21,7 @@ Parameters:
| Attribute | Type | Required | Description |
|:----------|:--------|:---------|:----------------------------------------------------------------------------------------------------------------------------------------|
-| `filter` | string | yes | A [filter](#available-filters) expression. |
+| `filter` | string | no | A [filter](#available-filters) expression. |
| `group_path` | string | yes | Full path to the group. |
| `startIndex` | integer | no | The 1-based index indicating where to start returning results from. A value of less than one will be interpreted as 1. |
| `count` | integer | no | Desired maximum number of query results. |
diff --git a/doc/api/search.md b/doc/api/search.md
index ca08f5ca0d7..8e20722052e 100644
--- a/doc/api/search.md
+++ b/doc/api/search.md
@@ -181,6 +181,7 @@ Example response:
"merge_status": "can_be_merged",
"sha": "78765a2d5e0a43585945c58e61ba2f822e4d090b",
"merge_commit_sha": null,
+ "squash_commit_sha": null,
"user_notes_count": 0,
"discussion_locked": null,
"should_remove_source_branch": null,
@@ -299,6 +300,7 @@ Example response:
{
"basename": "home",
"data": "hello\n\nand bye\n\nend",
+ "path": "home.md",
"filename": "home.md",
"id": null,
"ref": "master",
@@ -308,6 +310,8 @@ Example response:
]
```
+**Note:** `filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` will be only the file name and not the full path (see [this issue][gitlab-34521]).
+
### Scope: commits **(STARTER)**
This scope is available only if [Elasticsearch](../integration/elasticsearch.md) is enabled.
@@ -367,6 +371,7 @@ Example response:
{
"basename": "README",
"data": "```\n\n## Installation\n\nQuick start using the [pre-built",
+ "path": "README.md",
"filename": "README.md",
"id": null,
"ref": "master",
@@ -376,6 +381,8 @@ Example response:
]
```
+**Note:** `filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` will be only the file name and not the full path (see [this issue][gitlab-34521]).
+
### Scope: users
```bash
@@ -577,6 +584,7 @@ Example response:
"merge_status": "can_be_merged",
"sha": "78765a2d5e0a43585945c58e61ba2f822e4d090b",
"merge_commit_sha": null,
+ "squash_commit_sha": null,
"user_notes_count": 0,
"discussion_locked": null,
"should_remove_source_branch": null,
@@ -633,6 +641,7 @@ Example response:
{
"basename": "home",
"data": "hello\n\nand bye\n\nend",
+ "path": "home.md",
"filename": "home.md",
"id": null,
"ref": "master",
@@ -642,6 +651,8 @@ Example response:
]
```
+**Note:** `filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` will be only the file name and not the full path (see [this issue][gitlab-34521]).
+
### Scope: commits **(STARTER)**
This scope is available only if [Elasticsearch](../integration/elasticsearch.md) is enabled.
@@ -701,6 +712,7 @@ Example response:
{
"basename": "README",
"data": "```\n\n## Installation\n\nQuick start using the [pre-built",
+ "path": "README.md",
"filename": "README.md",
"id": null,
"ref": "master",
@@ -710,6 +722,8 @@ Example response:
]
```
+**Note:** `filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` will be only the file name and not the full path (see [this issue][gitlab-34521]).
+
### Scope: users
```bash
@@ -878,6 +892,7 @@ Example response:
"merge_status": "can_be_merged",
"sha": "78765a2d5e0a43585945c58e61ba2f822e4d090b",
"merge_commit_sha": null,
+ "squash_commit_sha": null,
"user_notes_count": 0,
"discussion_locked": null,
"should_remove_source_branch": null,
@@ -981,6 +996,7 @@ Example response:
{
"basename": "home",
"data": "hello\n\nand bye\n\nend",
+ "path": "home.md",
"filename": "home.md",
"id": null,
"ref": "master",
@@ -990,6 +1006,8 @@ Example response:
]
```
+**Note:** `filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` will be only the file name and not the full path (see [this issue][gitlab-34521]).
+
### Scope: commits
```bash
@@ -1051,6 +1069,7 @@ Example response:
{
"basename": "README",
"data": "```\n\n## Installation\n\nQuick start using the [pre-built",
+ "path": "README.md",
"filename": "README.md",
"id": null,
"ref": "master",
@@ -1060,6 +1079,8 @@ Example response:
]
```
+**Note:** `filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` will be only the file name and not the full path (see [this issue][gitlab-34521]).
+
### Scope: users
```bash
@@ -1082,3 +1103,4 @@ Example response:
```
[ce-41763]: https://gitlab.com/gitlab-org/gitlab-foss/issues/41763
+[gitlab-34521]: https://gitlab.com/gitlab-org/gitlab/issues/34521
diff --git a/doc/api/services.md b/doc/api/services.md
index 4abc02dec3c..609c7e62e36 100644
--- a/doc/api/services.md
+++ b/doc/api/services.md
@@ -605,7 +605,7 @@ Set Jira service for a project.
> Starting with GitLab 8.14, `api_url`, `issues_url`, `new_issue_url` and
> `project_url` are replaced by `url`. If you are using an
-> older version, [follow this documentation][old-jira-api].
+> older version, [follow this documentation](https://gitlab.com/gitlab-org/gitlab/blob/8-13-stable-ee/doc/api/services.md#jira).
```
PUT /projects/:id/services/jira
@@ -1224,9 +1224,6 @@ Get Jenkins CI (Deprecated) service settings for a project.
GET /projects/:id/services/jenkins-deprecated
```
-[jira-doc]: ../user/project/integrations/jira.md
-[old-jira-api]: https://gitlab.com/gitlab-org/gitlab/blob/8-13-stable/doc/api/services.md#jira
-
## MockCI
Mock an external CI. See [`gitlab-org/gitlab-mock-ci-service`](https://gitlab.com/gitlab-org/gitlab-mock-ci-service) for an example of a companion mock service.
diff --git a/doc/api/settings.md b/doc/api/settings.md
index 2d9e435bbb6..51d5e5f35d7 100644
--- a/doc/api/settings.md
+++ b/doc/api/settings.md
@@ -40,6 +40,7 @@ Example response:
"domain_blacklist_enabled" : false,
"domain_blacklist" : [],
"created_at" : "2016-01-04T15:44:55.176Z",
+ "default_ci_config_path" : null,
"default_project_visibility" : "private",
"default_group_visibility" : "private",
"gravatar_enabled" : true,
@@ -113,6 +114,7 @@ Example response:
"restricted_visibility_levels": [],
"max_attachment_size": 10,
"session_expire_delay": 10080,
+ "default_ci_config_path" : null,
"default_project_visibility": "internal",
"default_snippet_visibility": "private",
"default_group_visibility": "private",
@@ -198,6 +200,7 @@ are listed in the descriptions of the relevant settings.
| `container_registry_token_expire_delay` | integer | no | Container Registry token duration in minutes. |
| `default_artifacts_expire_in` | string | no | Set the default expiration time for each job's artifacts. |
| `default_branch_protection` | integer | no | Determine if developers can push to master. Can take: `0` _(not protected, both developers and maintainers can push new commits, force push, or delete the branch)_, `1` _(partially protected, developers and maintainers can push new commits, but cannot force push or delete the branch)_ or `2` _(fully protected, developers cannot push new commits, but maintainers can; no-one can force push or delete the branch)_ as a parameter. Default is `2`. |
+| `default_ci_config_path` | string | no | Default CI configuration path for new projects (`.gitlab-ci.yml` if not set). |
| `default_group_visibility` | string | no | What visibility level new groups receive. Can take `private`, `internal` and `public` as a parameter. Default is `private`. |
| `default_project_creation` | integer | no | Default project creation protection. Can take: `0` _(No one)_, `1` _(Maintainers)_ or `2` _(Developers + Maintainers)_|
| `default_projects_limit` | integer | no | Project limit per user. Default is `100000`. |
@@ -212,6 +215,10 @@ are listed in the descriptions of the relevant settings.
| `dsa_key_restriction` | integer | no | The minimum allowed bit length of an uploaded DSA key. Default is `0` (no restriction). `-1` disables DSA keys. |
| `ecdsa_key_restriction` | integer | no | The minimum allowed curve size (in bits) of an uploaded ECDSA key. Default is `0` (no restriction). `-1` disables ECDSA keys. |
| `ed25519_key_restriction` | integer | no | The minimum allowed curve size (in bits) of an uploaded ED25519 key. Default is `0` (no restriction). `-1` disables ED25519 keys. |
+| `eks_integration_enabled` | boolean | no | Enable integration with Amazon EKS |
+| `eks_account_id` | string | no | Amazon account ID |
+| `eks_access_key_id` | string | no | AWS IAM access key ID |
+| `eks_secret_access_key` | string | no | AWS IAM secret access key |
| `elasticsearch_aws_access_key` | string | no | **(PREMIUM)** AWS IAM access key |
| `elasticsearch_aws` | boolean | no | **(PREMIUM)** Enable the use of AWS hosted Elasticsearch |
| `elasticsearch_aws_region` | string | no | **(PREMIUM)** The AWS region the Elasticsearch domain is configured |
@@ -257,7 +264,6 @@ are listed in the descriptions of the relevant settings.
| `housekeeping_incremental_repack_period` | integer | required by: `housekeeping_enabled` | Number of Git pushes after which an incremental `git repack` is run. |
| `html_emails_enabled` | boolean | no | Enable HTML emails. |
| `import_sources` | array of strings | no | Sources to allow project import from, possible values: `github`, `bitbucket`, `bitbucket_server`, `gitlab`, `google_code`, `fogbugz`, `git`, `gitlab_project`, `gitea`, `manifest`, and `phabricator`. |
-
| `instance_statistics_visibility_private` | boolean | no | When set to `true` Instance statistics will only be available to admins. |
| `local_markdown_version` | integer | no | Increase this value when any cached markdown should be invalidated. |
| `max_artifacts_size` | integer | no | Maximum artifacts size in MB |
@@ -271,7 +277,7 @@ are listed in the descriptions of the relevant settings.
| `metrics_port` | integer | required by: `metrics_enabled` | The UDP port to use for connecting to InfluxDB. |
| `metrics_sample_interval` | integer | required by: `metrics_enabled` | The sampling interval in seconds. |
| `metrics_timeout` | integer | required by: `metrics_enabled` | The amount of seconds after which InfluxDB will time out. |
-| `mirror_available` | boolean | no | Allow mirrors to be set up for projects. If disabled, only admins will be able to set up mirrors in projects. |
+| `mirror_available` | boolean | no | Allow repository mirroring to configured by project Maintainers. If disabled, only Admins will be able to configure repository mirroring. |
| `mirror_capacity_threshold` | integer | no | **(PREMIUM)** Minimum capacity to be available before scheduling more mirrors preemptively |
| `mirror_max_capacity` | integer | no | **(PREMIUM)** Maximum number of mirrors that can be synchronizing at the same time. |
| `mirror_max_delay` | integer | no | **(PREMIUM)** Maximum time (in minutes) between updates that a mirror can have when scheduled to synchronize. |
@@ -316,7 +322,11 @@ are listed in the descriptions of the relevant settings.
| `snowplow_collector_hostname` | string | required by: `snowplow_enabled` | The Snowplow collector hostname. (e.g. `snowplow.trx.gitlab.net`) |
| `snowplow_cookie_domain` | string | no | The Snowplow cookie domain. (e.g. `.gitlab.com`) |
| `snowplow_enabled` | boolean | no | Enable snowplow tracking. |
-| `snowplow_site_id` | string | no | The Snowplow site name / application id. (e.g. `gitlab`) |
+| `snowplow_app_id` | string | no | The Snowplow site name / application id. (e.g. `gitlab`) |
+| `snowplow_iglu_registry_url` | string | no | The Snowplow base Iglu Schema Registry URL to use for custom context and self describing events'|
+| `sourcegraph_enabled` | boolean | no | Enables Sourcegraph integration. Default is `false`. **If enabled, requires** `sourcegraph_url`. |
+| `sourcegraph_url` | string | required by: `sourcegraph_enabled` | The Sourcegraph instance URL for integration. |
+| `sourcegraph_public_only` | boolean | no | Blocks Sourcegraph from being loaded on private and internal projects. Defaul is `true`. |
| `terminal_max_session_time` | integer | no | Maximum time for web terminal websocket connection (in seconds). Set to `0` for unlimited time. |
| `terms` | text | required by: `enforce_terms` | (**Required by:** `enforce_terms`) Markdown content for the ToS. |
| `throttle_authenticated_api_enabled` | boolean | no | (**If enabled, requires:** `throttle_authenticated_api_period_in_seconds` and `throttle_authenticated_api_requests_per_period`) Enable authenticated API request rate limit. Helps reduce request volume (e.g. from crawlers or abusive bots). |
diff --git a/doc/api/sidekiq_metrics.md b/doc/api/sidekiq_metrics.md
index 5f2202fa51d..95449d1ff77 100644
--- a/doc/api/sidekiq_metrics.md
+++ b/doc/api/sidekiq_metrics.md
@@ -92,7 +92,8 @@ Example response:
"jobs": {
"processed": 2,
"failed": 0,
- "enqueued": 0
+ "enqueued": 0,
+ "dead": 0
}
}
```
@@ -145,7 +146,8 @@ Example response:
"jobs": {
"processed": 2,
"failed": 0,
- "enqueued": 0
+ "enqueued": 0,
+ "dead": 0
}
}
```
diff --git a/doc/api/tags.md b/doc/api/tags.md
index 56143969e3c..13c4b83dda8 100644
--- a/doc/api/tags.md
+++ b/doc/api/tags.md
@@ -17,7 +17,7 @@ Parameters:
| `id` | integer/string| yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user|
| `order_by` | string | no | Return tags ordered by `name` or `updated` fields. Default is `updated` |
| `sort` | string | no | Return tags sorted in `asc` or `desc` order. Default is `desc` |
-| `search` | string | no | Return list of tags matching the search criteria |
+| `search` | string | no | Return list of tags matching the search criteria. You can use `^term` and `term$` to find tags that begin and end with `term` respectively. |
> Support for `search` was [introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/54401) in GitLab 11.8.
diff --git a/doc/api/users.md b/doc/api/users.md
index f95ad7b62ba..c82a5e23c8e 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -1124,7 +1124,7 @@ Parameters:
## Block user
-Blocks the specified user. Available only for admin.
+Blocks the specified user. Available only for admin.
```
POST /users/:id/block
@@ -1139,7 +1139,7 @@ Will return `201 OK` on success, `404 User Not Found` is user cannot be found or
## Unblock user
-Unblocks the specified user. Available only for admin.
+Unblocks the specified user. Available only for admin.
```
POST /users/:id/unblock
diff --git a/doc/api/visual_review_discussions.md b/doc/api/visual_review_discussions.md
new file mode 100644
index 00000000000..385c1bf201d
--- /dev/null
+++ b/doc/api/visual_review_discussions.md
@@ -0,0 +1,40 @@
+# Visual Review discussions API **(STARTER)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/18710) in [GitLab Starter](https://about.gitlab.com/pricing/) 12.5.
+
+Visual Review discussions are notes on Merge Requests sent as
+feedback from [Visual Reviews](../ci/review_apps/index.md#visual-reviews-starter).
+
+## Create new merge request thread
+
+Creates a new thread to a single project merge request. This is similar to creating
+a note but other comments (replies) can be added to it later.
+
+```
+POST /projects/:id/merge_requests/:merge_request_iid/visual_review_discussions
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| ------------------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `merge_request_iid` | integer | yes | The IID of a merge request |
+| `body` | string | yes | The content of the thread |
+| `position` | hash | no | Position when creating a diff note |
+| `position[base_sha]` | string | yes | Base commit SHA in the source branch |
+| `position[start_sha]` | string | yes | SHA referencing commit in target branch |
+| `position[head_sha]` | string | yes | SHA referencing HEAD of this merge request |
+| `position[position_type]` | string | yes | Type of the position reference. Either `text` or `image`. |
+| `position[new_path]` | string | no | File path after change |
+| `position[new_line]` | integer | no | Line number after change (Only stored for `text` diff notes) |
+| `position[old_path]` | string | no | File path before change |
+| `position[old_line]` | integer | no | Line number before change (Only stored for `text` diff notes) |
+| `position[width]` | integer | no | Width of the image (Only stored for `image` diff notes) |
+| `position[height]` | integer | no | Height of the image (Only stored for `image` diff notes) |
+| `position[x]` | integer | no | X coordinate (Only stored for `image` diff notes) |
+| `position[y]` | integer | no | Y coordinate (Only stored for `image` diff notes) |
+
+```bash
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/11/visual_review_discussions?body=comment
+```
diff --git a/doc/api/vulnerabilities.md b/doc/api/vulnerabilities.md
index eaa4c13de55..21b3a6f4c96 100644
--- a/doc/api/vulnerabilities.md
+++ b/doc/api/vulnerabilities.md
@@ -1,115 +1,3 @@
# Vulnerabilities API **(ULTIMATE)**
-Every API call to vulnerabilities must be authenticated.
-
-If a user is not a member of a project and the project is private, a `GET`
-request on that project will result in a `404` status code.
-
-CAUTION: **Caution:**
-This API is in an alpha stage and considered unstable.
-The response payload may be subject to change or breakage
-across GitLab releases.
-
-## Vulnerabilities pagination
-
-By default, `GET` requests return 20 results at a time because the API results
-are paginated.
-
-Read more on [pagination](README.md#pagination).
-
-## List project vulnerabilities
-
-List all of a project's vulnerabilities.
-
-```
-GET /projects/:id/vulnerabilities
-GET /projects/:id/vulnerabilities?report_type=sast
-GET /projects/:id/vulnerabilities?report_type=container_scanning
-GET /projects/:id/vulnerabilities?report_type=sast,dast
-GET /projects/:id/vulnerabilities?scope=all
-GET /projects/:id/vulnerabilities?scope=dismissed
-GET /projects/:id/vulnerabilities?severity=high
-GET /projects/:id/vulnerabilities?confidence=unknown,experimental
-GET /projects/:id/vulnerabilities?pipeline_id=42
-```
-
-| Attribute | Type | Required | Description |
-| ------------- | -------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user. |
-| `report_type` | string array | no | Returns vulnerabilities belonging to specified report type. Valid values: `sast`, `dast`, `dependency_scanning`, or `container_scanning`. |
-| `scope` | string | no | Returns vulnerabilities for the given scope: `all` or `dismissed`. Defaults to `dismissed` |
-| `severity` | string array | no | Returns vulnerabilities belonging to specified severity level: `undefined`, `info`, `unknown`, `low`, `medium`, `high`, or `critical`. Defaults to all' |
-| `confidence` | string array | no | Returns vulnerabilities belonging to specified confidence level: `undefined`, `ignore`, `unknown`, `experimental`, `low`, `medium`, `high`, or `confirmed`. Defaults to all |
-| `pipeline_id` | integer/string | no | Returns vulnerabilities belonging to specified pipeline. |
-
-```bash
-curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/4/vulnerabilities
-```
-
-Example response:
-
-```json
-[
- {
- "id": null,
- "report_type": "dependency_scanning",
- "name": "Authentication bypass via incorrect DOM traversal and canonicalization in saml2-js",
- "severity": "unknown",
- "confidence": "undefined",
- "scanner": {
- "external_id": "gemnasium",
- "name": "Gemnasium"
- },
- "identifiers": [
- {
- "external_type": "gemnasium",
- "external_id": "9952e574-7b5b-46fa-a270-aeb694198a98",
- "name": "Gemnasium-9952e574-7b5b-46fa-a270-aeb694198a98",
- "url": "https://deps.sec.gitlab.com/packages/npm/saml2-js/versions/1.5.0/advisories"
- },
- {
- "external_type": "cve",
- "external_id": "CVE-2017-11429",
- "name": "CVE-2017-11429",
- "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-11429"
- }
- ],
- "project_fingerprint": "fa6f5b6c5d240b834ac5e901dc69f9484cef89ec",
- "create_vulnerability_feedback_issue_path": "/tests/yarn-remediation-test/vulnerability_feedback",
- "create_vulnerability_feedback_merge_request_path": "/tests/yarn-remediation-test/vulnerability_feedback",
- "create_vulnerability_feedback_dismissal_path": "/tests/yarn-remediation-test/vulnerability_feedback",
- "project": {
- "id": 31,
- "name": "yarn-remediation-test",
- "full_path": "/tests/yarn-remediation-test",
- "full_name": "tests / yarn-remediation-test"
- },
- "dismissal_feedback": null,
- "issue_feedback": null,
- "merge_request_feedback": null,
- "description": "Some XML DOM traversal and canonicalization APIs may be inconsistent in handling of comments within XML nodes. Incorrect use of these APIs by some SAML libraries results in incorrect parsing of the inner text of XML nodes such that any inner text after the comment is lost prior to cryptographically signing the SAML message. Text after the comment therefore has no impact on the signature on the SAML message.\r\n\r\nA remote attacker can modify SAML content for a SAML service provider without invalidating the cryptographic signature, which may allow attackers to bypass primary authentication for the affected SAML service provider.",
- "links": [
- {
- "url": "https://github.com/Clever/saml2/commit/3546cb61fd541f219abda364c5b919633609ef3d#diff-af730f9f738de1c9ad87596df3f6de84R279"
- },
- {
- "url": "https://www.kb.cert.org/vuls/id/475445"
- },
- {
- "url": "https://github.com/Clever/saml2/issues/127"
- }
- ],
- "location": {
- "file": "yarn.lock",
- "dependency": {
- "package": {
- "name": "saml2-js"
- },
- "version": "1.5.0"
- }
- },
- "solution": "Upgrade to fixed version.\r\n",
- "blob_path": "/tests/yarn-remediation-test/blob/cc6c4a0778460455ae5d16ca7025ca9ca1ca75ac/yarn.lock"
- }
-]
-```
+This document was moved to [another location](vulnerability_findings.md).
diff --git a/doc/api/vulnerability_findings.md b/doc/api/vulnerability_findings.md
new file mode 100644
index 00000000000..3d3f12aeef5
--- /dev/null
+++ b/doc/api/vulnerability_findings.md
@@ -0,0 +1,128 @@
+# Vulnerability Findings API **(ULTIMATE)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/19029) in GitLab Ultimate 12.5.
+
+NOTE: **Note:**
+This API resource is renamed from Vulnerabilities to Vulnerability Findings because the Vulnerabilities are reserved
+for serving the upcoming [Standalone Vulnerability objects](https://gitlab.com/gitlab-org/gitlab/issues/13561).
+To fix any broken integrations with the former Vulnerabilities API, change the `vulnerabilities` URL part to be
+`vulnerability_findings`.
+
+Every API call to vulnerability findings must be [authenticated](README.md#authentication).
+
+Vulnerability findings are project-bound entities. If a user is not
+a member of a project and the project is private, a request on
+that project will result in a `404` status code.
+
+If a user is able to access the project but does not have permission to
+[use the Project Security Dashboard](../user/permissions.md#project-members-permissions),
+any request for vulnerability findings of this project will result in a `403` status code.
+
+CAUTION: **Caution:**
+This API is in an alpha stage and considered unstable.
+The response payload may be subject to change or breakage
+across GitLab releases.
+
+## Vulnerability findings pagination
+
+By default, `GET` requests return 20 results at a time because the API results
+are paginated.
+
+Read more on [pagination](README.md#pagination).
+
+## List project vulnerability findings
+
+List all of a project's vulnerability findings.
+
+```
+GET /projects/:id/vulnerability_findings
+GET /projects/:id/vulnerability_findings?report_type=sast
+GET /projects/:id/vulnerability_findings?report_type=container_scanning
+GET /projects/:id/vulnerability_findings?report_type=sast,dast
+GET /projects/:id/vulnerability_findings?scope=all
+GET /projects/:id/vulnerability_findings?scope=dismissed
+GET /projects/:id/vulnerability_findings?severity=high
+GET /projects/:id/vulnerability_findings?confidence=unknown,experimental
+GET /projects/:id/vulnerability_findings?pipeline_id=42
+```
+
+| Attribute | Type | Required | Description |
+| ------------- | -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) which the authenticated user is a member of. |
+| `report_type` | string array | no | Returns vulnerability findings belonging to specified report type. Valid values: `sast`, `dast`, `dependency_scanning`, or `container_scanning`. Defaults to all. |
+| `scope` | string | no | Returns vulnerability findings for the given scope: `all` or `dismissed`. Defaults to `dismissed`. |
+| `severity` | string array | no | Returns vulnerability findings belonging to specified severity level: `undefined`, `info`, `unknown`, `low`, `medium`, `high`, or `critical`. Defaults to all. |
+| `confidence` | string array | no | Returns vulnerability findings belonging to specified confidence level: `undefined`, `ignore`, `unknown`, `experimental`, `low`, `medium`, `high`, or `confirmed`. Defaults to all. |
+| `pipeline_id` | integer/string | no | Returns vulnerability findings belonging to specified pipeline. |
+
+```bash
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/4/vulnerability_findings
+```
+
+Example response:
+
+```json
+[
+ {
+ "id": null,
+ "report_type": "dependency_scanning",
+ "name": "Authentication bypass via incorrect DOM traversal and canonicalization in saml2-js",
+ "severity": "unknown",
+ "confidence": "undefined",
+ "scanner": {
+ "external_id": "gemnasium",
+ "name": "Gemnasium"
+ },
+ "identifiers": [
+ {
+ "external_type": "gemnasium",
+ "external_id": "9952e574-7b5b-46fa-a270-aeb694198a98",
+ "name": "Gemnasium-9952e574-7b5b-46fa-a270-aeb694198a98",
+ "url": "https://deps.sec.gitlab.com/packages/npm/saml2-js/versions/1.5.0/advisories"
+ },
+ {
+ "external_type": "cve",
+ "external_id": "CVE-2017-11429",
+ "name": "CVE-2017-11429",
+ "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-11429"
+ }
+ ],
+ "project_fingerprint": "fa6f5b6c5d240b834ac5e901dc69f9484cef89ec",
+ "create_vulnerability_feedback_issue_path": "/tests/yarn-remediation-test/vulnerability_feedback",
+ "create_vulnerability_feedback_merge_request_path": "/tests/yarn-remediation-test/vulnerability_feedback",
+ "create_vulnerability_feedback_dismissal_path": "/tests/yarn-remediation-test/vulnerability_feedback",
+ "project": {
+ "id": 31,
+ "name": "yarn-remediation-test",
+ "full_path": "/tests/yarn-remediation-test",
+ "full_name": "tests / yarn-remediation-test"
+ },
+ "dismissal_feedback": null,
+ "issue_feedback": null,
+ "merge_request_feedback": null,
+ "description": "Some XML DOM traversal and canonicalization APIs may be inconsistent in handling of comments within XML nodes. Incorrect use of these APIs by some SAML libraries results in incorrect parsing of the inner text of XML nodes such that any inner text after the comment is lost prior to cryptographically signing the SAML message. Text after the comment therefore has no impact on the signature on the SAML message.\r\n\r\nA remote attacker can modify SAML content for a SAML service provider without invalidating the cryptographic signature, which may allow attackers to bypass primary authentication for the affected SAML service provider.",
+ "links": [
+ {
+ "url": "https://github.com/Clever/saml2/commit/3546cb61fd541f219abda364c5b919633609ef3d#diff-af730f9f738de1c9ad87596df3f6de84R279"
+ },
+ {
+ "url": "https://www.kb.cert.org/vuls/id/475445"
+ },
+ {
+ "url": "https://github.com/Clever/saml2/issues/127"
+ }
+ ],
+ "location": {
+ "file": "yarn.lock",
+ "dependency": {
+ "package": {
+ "name": "saml2-js"
+ },
+ "version": "1.5.0"
+ }
+ },
+ "solution": "Upgrade to fixed version.\r\n",
+ "blob_path": "/tests/yarn-remediation-test/blob/cc6c4a0778460455ae5d16ca7025ca9ca1ca75ac/yarn.lock"
+ }
+]
+```
diff --git a/doc/ci/README.md b/doc/ci/README.md
index 5286764d178..d1cf7e63c63 100644
--- a/doc/ci/README.md
+++ b/doc/ci/README.md
@@ -132,7 +132,7 @@ Its feature set is listed on the table below according to DevOps stages.
| [Container Scanning](../user/application_security/container_scanning/index.md) **(ULTIMATE)** | Check your Docker containers for known vulnerabilities.|
| [Dependency Scanning](../user/application_security/dependency_scanning/index.md) **(ULTIMATE)** | Analyze your dependencies for known vulnerabilities. |
| [License Compliance](../user/application_security/license_compliance/index.md) **(ULTIMATE)** | Search your project dependencies for their licenses. |
-| [Security Test reports](../user/project/merge_requests/index.md#security-reports-ultimate) **(ULTIMATE)** | Check for app vulnerabilities. |
+| [Security Test reports](../user/application_security/index.md) **(ULTIMATE)** | Check for app vulnerabilities. |
## Examples
diff --git a/doc/ci/chatops/README.md b/doc/ci/chatops/README.md
index 234e7f4ed80..d9236b47a9a 100644
--- a/doc/ci/chatops/README.md
+++ b/doc/ci/chatops/README.md
@@ -58,6 +58,11 @@ ls:
- echo -e "section_start:$( date +%s ):chat_reply\r\033[0K\n$( ls -la )\nsection_end:$( date +%s ):chat_reply\r\033[0K"
```
+## GitLab ChatOps Examples
+
+The GitLab.com team created a repository of [common ChatOps scripts they use to interact with our Production instance of GitLab](https://gitlab.com/gitlab-com/chatops). They are likely useful
+to other adminstrators of GitLab instances and can serve as inspiration for ChatOps scripts you can write to interact with your own applications.
+
## GitLab ChatOps icon
Say Hi to our ChatOps bot.
diff --git a/doc/ci/ci_cd_for_external_repos/bitbucket_integration.md b/doc/ci/ci_cd_for_external_repos/bitbucket_integration.md
index 54b21939116..dd474b09a9c 100644
--- a/doc/ci/ci_cd_for_external_repos/bitbucket_integration.md
+++ b/doc/ci/ci_cd_for_external_repos/bitbucket_integration.md
@@ -151,7 +151,7 @@ To use GitLab CI/CD with a Bitbucket Cloud repository:
GitLab is now configured to mirror changes from Bitbucket, run CI/CD pipelines
configured in `.gitlab-ci.yml` and push the status to Bitbucket.
-[pull-mirroring]: ../../workflow/repository_mirroring.md#pulling-from-a-remote-repository-starter
+[pull-mirroring]: ../../user/project/repository/repository_mirroring.md#pulling-from-a-remote-repository-starter
<!-- ## Troubleshooting
diff --git a/doc/ci/ci_cd_for_external_repos/github_integration.md b/doc/ci/ci_cd_for_external_repos/github_integration.md
index 08660b014b0..3df47d4cd4f 100644
--- a/doc/ci/ci_cd_for_external_repos/github_integration.md
+++ b/doc/ci/ci_cd_for_external_repos/github_integration.md
@@ -26,7 +26,7 @@ To perform a one-off authorization with GitHub to grant GitLab access your
repositories:
1. Open <https://github.com/settings/tokens/new> to create a **Personal Access
- Token**. This token with be used to access your repository and push commit
+ Token**. This token will be used to access your repository and push commit
statuses to GitHub.
The `repo` and `admin:repo_hook` should be enable to allow GitLab access to
@@ -46,7 +46,7 @@ repositories:
GitLab will:
1. Import the project.
-1. Enable [Pull Mirroring](../../workflow/repository_mirroring.md#pulling-from-a-remote-repository-starter)
+1. Enable [Pull Mirroring](../../user/project/repository/repository_mirroring.md#pulling-from-a-remote-repository-starter)
1. Enable [GitHub project integration](../../user/project/integrations/github.md)
1. Create a web hook on GitHub to notify GitLab of new commits.
diff --git a/doc/ci/ci_cd_for_external_repos/index.md b/doc/ci/ci_cd_for_external_repos/index.md
index 35e2117c285..b5878e70c53 100644
--- a/doc/ci/ci_cd_for_external_repos/index.md
+++ b/doc/ci/ci_cd_for_external_repos/index.md
@@ -20,7 +20,7 @@ Instead of moving your entire project to GitLab, you can connect your
external repository to get the benefits of GitLab CI/CD.
Connecting an external repository will set up [repository mirroring][mirroring]
-and create a lightweight project where issues, merge requests, wiki, and
+and create a lightweight project with issues, merge requests, wiki, and
snippets disabled. These features
[can be re-enabled later][settings].
@@ -101,5 +101,5 @@ requests and not on branches you can add `except: [branches]` to the job specs.
[ee-4642]: https://gitlab.com/gitlab-org/gitlab/merge_requests/4642
[eep]: https://about.gitlab.com/pricing/
-[mirroring]: ../../workflow/repository_mirroring.md
+[mirroring]: ../../user/project/repository/repository_mirroring.md
[settings]: ../../user/project/settings/index.md#sharing-and-permissions
diff --git a/doc/ci/docker/using_docker_build.md b/doc/ci/docker/using_docker_build.md
index f4bb7cd7d9f..c892320327b 100644
--- a/doc/ci/docker/using_docker_build.md
+++ b/doc/ci/docker/using_docker_build.md
@@ -174,7 +174,7 @@ support this.
The above command will register a new Runner to use the special
`docker:19.03.1` image, which is provided by Docker. **Notice that it's
using the `privileged` mode to start the build and service
- containers.** If you want to use [docker-in-docker] mode, you always
+ containers.** If you want to use [docker-in-docker](https://www.docker.com/blog/docker-can-now-run-within-docker/) mode, you always
have to use `privileged = true` in your Docker containers.
This will also mount `/certs/client` for the service and build
@@ -723,19 +723,22 @@ or [Kubernetes](https://docs.gitlab.com/runner/executors/kubernetes.html) execut
make sure that [`pull_policy`](https://docs.gitlab.com/runner/executors/docker.html#how-pull-policies-work)
is set to `always`.
-[docker-in-docker]: https://blog.docker.com/2013/09/docker-can-now-run-within-docker/
[docker-cap]: https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities
[2fa]: ../../user/profile/account/two_factor_authentication.md
[pat]: ../../user/profile/personal_access_tokens.md
-<!-- ## Troubleshooting
+## Troubleshooting
-Include any troubleshooting steps that you can foresee. If you know beforehand what issues
-one might have when setting this up, or when something is changed, or on upgrading, it's
-important to describe those, too. Think of things that may go wrong and include them here.
-This is important to minimize requests for support, and to avoid doc comments with
-questions that you know someone might ask.
+### docker: Cannot connect to the Docker daemon at tcp://docker:2375. Is the docker daemon running?
-Each scenario can be a third-level heading, e.g. `### Getting error message X`.
-If you have none to add when creating a doc, leave this section in place
-but commented out to help encourage others to add to it in the future. -->
+This is a common error when you are using
+[Docker in Docker](#use-docker-in-docker-workflow-with-docker-executor)
+v19.03 or higher.
+
+This occurs because Docker starts on TLS automatically, so you need to do some set up.
+If:
+
+- This is the first time setting it up, carefully read
+ [using Docker in Docker workflow](#use-docker-in-docker-workflow-with-docker-executor).
+- You are upgrading from v18.09 or earlier, read our
+ [upgrade guide](https://about.gitlab.com/blog/2019/07/31/docker-in-docker-with-docker-19-dot-03/).
diff --git a/doc/ci/environments.md b/doc/ci/environments.md
index cef95c8e22a..6d620722608 100644
--- a/doc/ci/environments.md
+++ b/doc/ci/environments.md
@@ -292,10 +292,10 @@ For the value of:
the web server to serve these requests is based on your setup.
We have used `$CI_ENVIRONMENT_SLUG` here because it is guaranteed to be unique. If
- you're using a workflow like [GitLab Flow](../workflow/gitlab_flow.md), collisions
+ you're using a workflow like [GitLab Flow](../topics/gitlab_flow.md), collisions
are unlikely and you may prefer environment names to be more closely based on the
- branch name. In that case, you could use `$CI_COMMIT_REF_SLUG` in `environment:url` in
- the example above: `https://$CI_COMMIT_REF_SLUG.example.com`, which would give a URL
+ branch name. In that case, you could use `$CI_COMMIT_REF_NAME` in `environment:url` in
+ the example above: `https://$CI_COMMIT_REF_NAME.example.com`, which would give a URL
of `https://100-do-the-thing.example.com`.
NOTE: **Note:**
diff --git a/doc/ci/examples/deployment/README.md b/doc/ci/examples/deployment/README.md
index afe02e0a7d8..7af797f1851 100644
--- a/doc/ci/examples/deployment/README.md
+++ b/doc/ci/examples/deployment/README.md
@@ -35,8 +35,8 @@ apt-get install ruby-dev
The Dpl provides support for vast number of services, including: Heroku, Cloud Foundry, AWS/S3, and more.
To use it simply define provider and any additional parameters required by the provider.
-For example if you want to use it to deploy your application to heroku, you need to specify `heroku` as provider, specify `api-key` and `app`.
-There's more and all possible parameters can be found here: <https://github.com/travis-ci/dpl#heroku>.
+For example if you want to use it to deploy your application to Heroku, you need to specify `heroku` as provider, specify `api-key` and `app`.
+All possible parameters can be found here: <https://github.com/travis-ci/dpl#heroku-api>.
```yaml
staging:
diff --git a/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/index.md b/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/index.md
index e1c59f3b025..ffcc8195395 100644
--- a/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/index.md
+++ b/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/index.md
@@ -38,7 +38,7 @@ that's tested and deployed on every push to the `master` branch of the [codebase
This will also provide
boilerplate code for starting a browser-based game with the following components:
-- Written in [Typescript](https://www.typescriptlang.org/) and [PhaserJs](https://phaser.io)
+- Written in [TypeScript](https://www.typescriptlang.org/) and [PhaserJs](https://phaser.io)
- Building, running, and testing with [Gulp](https://gulpjs.com)
- Unit tests with [Chai](https://www.chaijs.com) and [Mocha](https://mochajs.org/)
- CI/CD with GitLab
@@ -508,7 +508,7 @@ deploy:
## Conclusion
Within the [demo repository](https://gitlab.com/blitzgren/gitlab-game-demo) you can also find a handful of boilerplate code to get
-[Typescript](https://www.typescriptlang.org/), [Mocha](https://mochajs.org/), [Gulp](https://gulpjs.com/) and [Phaser](https://phaser.io) all playing
+[TypeScript](https://www.typescriptlang.org/), [Mocha](https://mochajs.org/), [Gulp](https://gulpjs.com/) and [Phaser](https://phaser.io) all playing
together nicely with GitLab CI/CD, which is the result of lessons learned while making [Dark Nova](https://www.darknova.io).
Using a combination of free and open source software, we have a full CI/CD pipeline, a game foundation,
and unit tests, all running and deployed at every push to master - with shockingly little code.
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md b/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md
index a7ed4ca3514..5acdd273548 100644
--- a/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md
+++ b/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md
@@ -379,7 +379,7 @@ These are persistent data and will be shared to every new release.
Now, we would need to deploy our app by running `envoy run deploy`, but it won't be necessary since GitLab can handle that for us with CI's [environments](../../environments.md), which will be described [later](#setting-up-gitlab-cicd) in this tutorial.
Now it's time to commit [Envoy.blade.php](https://gitlab.com/mehranrasulian/laravel-sample/blob/master/Envoy.blade.php) and push it to the `master` branch.
-To keep things simple, we commit directly to `master`, without using [feature-branches](../../../workflow/gitlab_flow.md#github-flow-as-a-simpler-alternative) since collaboration is beyond the scope of this tutorial.
+To keep things simple, we commit directly to `master`, without using [feature-branches](../../../topics/gitlab_flow.md#github-flow-as-a-simpler-alternative) since collaboration is beyond the scope of this tutorial.
In a real world project, teams may use [Issue Tracker](../../../user/project/issues/index.md) and [Merge Requests](../../../user/project/merge_requests/index.md) to move their code across branches:
```bash
diff --git a/doc/ci/img/pipelines_junit_test_report_ui_v12_5.png b/doc/ci/img/pipelines_junit_test_report_ui_v12_5.png
new file mode 100644
index 00000000000..5b1e3254f8b
--- /dev/null
+++ b/doc/ci/img/pipelines_junit_test_report_ui_v12_5.png
Binary files differ
diff --git a/doc/ci/interactive_web_terminal/index.md b/doc/ci/interactive_web_terminal/index.md
index 361e526ed96..f7e8a0e412c 100644
--- a/doc/ci/interactive_web_terminal/index.md
+++ b/doc/ci/interactive_web_terminal/index.md
@@ -59,7 +59,7 @@ the terminal and type commands like a normal shell.
If you have the terminal open and the job has finished with its tasks, the
terminal will block the job from finishing for the duration configured in
-[`[session_server].terminal_max_retention_time`](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-session_server-section) until you
+[`[session_server].session_timeout`](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-session_server-section) until you
close the terminal window.
![finished job with terminal open](img/finished_job_with_terminal_open.png)
diff --git a/doc/ci/introduction/index.md b/doc/ci/introduction/index.md
index a644a89eee4..a07252f4803 100644
--- a/doc/ci/introduction/index.md
+++ b/doc/ci/introduction/index.md
@@ -5,7 +5,7 @@ type: concepts
# Introduction to CI/CD with GitLab
-In this document we'll present an overview of the concepts of Continuous Integration,
+In this document, we'll present an overview of the concepts of Continuous Integration,
Continuous Delivery, and Continuous Deployment, as well as an introduction to
GitLab CI/CD.
@@ -31,7 +31,7 @@ to be applied according to what best suits your strategy.
### Continuous Integration
-Consider an application which has its code stored in a Git
+Consider an application that has its code stored in a Git
repository in GitLab. Developers push code changes every day,
multiple times a day. For every push to the repository, you
can create a set of scripts to build and test your application
@@ -94,7 +94,7 @@ To add scripts to that file, you'll need to organize them in a
sequence that suits your application and are in accordance with
the tests you wish to perform. To visualize the process, imagine
that all the scripts you add to the configuration file are the
-same as the commands you run on a terminal in your computer.
+same as the commands you run on a terminal on your computer.
Once you've added your `.gitlab-ci.yml` configuration file to your
repository, GitLab will detect it and run your scripts with the
@@ -121,7 +121,7 @@ Both of them compose a **pipeline** triggered at every push
to any branch of the repository.
GitLab CI/CD not only executes the jobs you've
-set, but also shows you what's happening during execution, as you
+set but also shows you what's happening during execution, as you
would see in your terminal:
![job running](img/job_running.png)
@@ -164,7 +164,7 @@ Once you're happy with your implementation:
GitLab CI/CD is capable of doing a lot more, but this workflow
exemplifies GitLab's ability to track the entire process,
-without the need of any external tool to deliver your software.
+without the need for an external tool to deliver your software.
And, most usefully, you can visualize all the steps through
the GitLab UI.
@@ -172,7 +172,7 @@ the GitLab UI.
If we take a deeper look into the basic workflow, we can see
the features available in GitLab at each stage of the DevOps
-lifecycle, as shown on the illustration below.
+lifecycle, as shown in the illustration below.
![Deeper look into the basic CI/CD workflow](img/gitlab_workflow_example_extended_v12_3.png)
@@ -207,7 +207,7 @@ With GitLab CI/CD you can also:
- Deploy your app to different [environments](../environments.md).
- Install your own [GitLab Runner](https://docs.gitlab.com/runner/).
- [Schedule pipelines](../../user/project/pipelines/schedules.md).
-- Check for app vulnerabilities with [Security Test reports](../../user/project/merge_requests/index.md#security-reports-ultimate). **(ULTIMATE)**
+- Check for app vulnerabilities with [Security Test reports](../../user/application_security/index.md). **(ULTIMATE)**
To see all CI/CD features, navigate back to the [CI/CD index](../README.md).
diff --git a/doc/ci/junit_test_reports.md b/doc/ci/junit_test_reports.md
index bc30e007393..c03d1798ae1 100644
--- a/doc/ci/junit_test_reports.md
+++ b/doc/ci/junit_test_reports.md
@@ -178,3 +178,27 @@ Currently, the following tools might not work because their XML formats are unsu
|Case|Tool|Issue|
|---|---|---|
|`<testcase>` does not have `classname` attribute|ESlint, sass-lint|<https://gitlab.com/gitlab-org/gitlab-foss/issues/50964>|
+
+## Viewing JUnit test reports on GitLab
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/24792) in GitLab 12.5.
+
+If JUnit XML files are generated and uploaded as part of a pipeline, these reports
+can be viewed inside the pipelines details page. The **Tests** tab on this page will
+display a list of test suites and cases reported from the XML file.
+
+![Test Reports Widget](img/pipelines_junit_test_report_ui_v12_5.png)
+
+You can view all the known test suites and click on each of these to see further
+details, including the cases that makeup the suite. Cases are ordered by status,
+with failed showing at the top, skipped next and successful cases last.
+
+### Enabling the feature
+
+This feature comes with the `:junit_pipeline_view` feature flag disabled by default.
+To enable this feature, ask a GitLab administrator with Rails console access to run the
+following command:
+
+```ruby
+Feature.enable(:junit_pipeline_view)
+```
diff --git a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md
index f2a7902c9ca..b8976ffae7f 100644
--- a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md
+++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md
@@ -32,8 +32,8 @@ Merge trains have the following requirements and limitations:
- This feature requires that
[pipelines for merged results](../index.md#pipelines-for-merged-results-premium) are
**configured properly**.
-- Each merge train can run a maximum of **four** pipelines in parallel.
- If more than four merge requests are added to the merge train, the merge requests
+- Each merge train can run a maximum of **twenty** pipelines in parallel.
+ If more than twenty merge requests are added to the merge train, the merge requests
will be queued until a slot in the merge train is free. There is no limit to the
number of merge requests that can be queued.
- This feature does not support [squash and merge](../../../../user/project/merge_requests/squash_and_merge.md).
diff --git a/doc/ci/multi_project_pipelines.md b/doc/ci/multi_project_pipelines.md
index 093d334e937..f13d05716f1 100644
--- a/doc/ci/multi_project_pipelines.md
+++ b/doc/ci/multi_project_pipelines.md
@@ -87,10 +87,9 @@ not be found, or a user does not have access rights to create pipeline there,
the `staging` job is going to be marked as _failed_.
CAUTION: **Caution:**
-`staging` will succeed as soon as a downstream pipeline gets created.
-GitLab does not support status attribution yet, however adding first-class
-`trigger` configuration syntax is ground work for implementing
-[status attribution](https://gitlab.com/gitlab-org/gitlab-foss/issues/39640).
+In the example, `staging` will be marked as succeeded as soon as a downstream pipeline
+gets created. If you want to display the downstream pipeline's status instead, see
+[Mirroring status from triggered pipeline](#mirroring-status-from-triggered-pipeline).
NOTE: **Note:**
Bridge jobs do not support every configuration entry that a user can use
diff --git a/doc/ci/pipelines.md b/doc/ci/pipelines.md
index e5f2701c6ae..590a02b306c 100644
--- a/doc/ci/pipelines.md
+++ b/doc/ci/pipelines.md
@@ -28,7 +28,7 @@ If all the jobs in a stage:
- Fail, the next stage is not (usually) executed and the pipeline ends early.
NOTE: **Note:**
-If you have a [mirrored repository that GitLab pulls from](../workflow/repository_mirroring.md#pulling-from-a-remote-repository-starter),
+If you have a [mirrored repository that GitLab pulls from](../user/project/repository/repository_mirroring.md#pulling-from-a-remote-repository-starter),
you may need to enable pipeline triggering in your project's
**Settings > Repository > Pull from a remote repository > Trigger pipelines for mirror updates**.
@@ -269,6 +269,38 @@ To execute a pipeline manually:
The pipeline will execute the jobs as configured.
+#### Using a query string
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/24146) in GitLab 12.5.
+
+Variables on the **Run Pipeline** page can be pre-populated by passing variable keys and values
+in a query string appended to the `pipelines/new` URL. The format is:
+
+```plaintext
+.../pipelines/new?ref=<branch>&var[<variable_key>]=<value>&file_var[<file_key>]=<value>
+```
+
+The following parameters are supported:
+
+- `ref`: specify the branch to populate the **Run for** field with.
+- `var`: specify a `Variable` variable.
+- `file_var`: specify a `File` variable.
+
+For each `var` or `file_var`, a key and value are required.
+
+For example, the query string
+`.../pipelines/new?ref=my_branch&var[foo]=bar&file_var[file_foo]=file_bar` will pre-populate the
+**Run Pipeline** page as follows:
+
+- **Run for** field: `my_branch`.
+- **Variables** section:
+ - Variable:
+ - Key: `foo`
+ - Value: `bar`
+ - File:
+ - Key: `file_foo`
+ - Value: `file_bar`
+
### Accessing pipelines
You can find the current and historical pipeline runs under your project's
diff --git a/doc/ci/quick_start/README.md b/doc/ci/quick_start/README.md
index 10a898be900..68e977c1c98 100644
--- a/doc/ci/quick_start/README.md
+++ b/doc/ci/quick_start/README.md
@@ -50,7 +50,7 @@ project's **Pipelines** page.
This guide assumes that you have:
-- A working GitLab instance of version 8.0+r or are using
+- A working GitLab instance of version 8.0+ or are using
[GitLab.com](https://gitlab.com).
- A project in GitLab that you would like to use CI for.
- Maintainer or owner access to the project
@@ -143,7 +143,7 @@ Now if you go to the **Pipelines** page you will see that the pipeline is
pending.
NOTE: **Note:**
-If you have a [mirrored repository where GitLab pulls from](../../workflow/repository_mirroring.md#pulling-from-a-remote-repository-starter),
+If you have a [mirrored repository where GitLab pulls from](../../user/project/repository/repository_mirroring.md#pulling-from-a-remote-repository-starter),
you may need to enable pipeline triggering in your project's
**Settings > Repository > Pull from a remote repository > Trigger pipelines for mirror updates**.
diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md
index 5d86d382aa8..cff797549ba 100644
--- a/doc/ci/variables/README.md
+++ b/doc/ci/variables/README.md
@@ -54,25 +54,37 @@ or directly in the `.gitlab-ci.yml` file and reuse them as you wish.
That can be very powerful as it can be used for scripting without
the need to specify the value itself.
-#### Variable types
+#### Types of variables
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/46806) in GitLab 11.11.
There are two types of variables supported by GitLab:
-- "Variable": the Runner will create an environment variable named same as the variable key and set its value to the variable value.
-- "File": the Runner will write the variable value to a temporary file and set the path to this file as the value of an environment variable named same as the variable key.
+- [Variable type](#variable-type): The Runner will create an environment variable named the same as the
+ variable key and set its value to the variable value.
+- [File type](#file-type): The Runner will write the variable value to a temporary file and set the
+ path to this file as the value of an environment variable, named the same as the variable key.
-Many tools (like [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html) and [kubectl](https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/#the-kubeconfig-environment-variable)) provide the ability to customise configuration using files by either providing the file path as a command line argument or an environment variable. Prior to the introduction of variable types, the common pattern was to use the value of a CI variable, save it in a file, and then use the newly created file in your script:
+##### Variable type
+
+Many tools (like [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html)
+and [kubectl](https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/#the-kubeconfig-environment-variable))
+provide the ability to customise configuration using files by either providing the
+file path as a command line argument or an environment variable. In the past, the
+common pattern was to read the value of a CI variable, save it in a file, and then
+use the newly created file in your script:
```bash
-# Save the content of variable in a file
+# Read certificate stored in $KUBE_CA_PEM variable and save it in a new file
echo "$KUBE_CA_PEM" > "$(pwd)/kube.ca.pem"
- # Use the newly created file
+# Pass the newly created file to kubectl
kubectl config set-cluster e2e --server="$KUBE_URL" --certificate-authority="$(pwd)/kube.ca.pem"
```
-This can be simplified by creating a variable of type "File" and using it directly. For example, let's say we have the following variables.
+##### File type
+
+The example above can now be simplified by creating a "File" type variable, and using
+it directly. For example, let's say we have the following variables:
![CI/CD settings - variable types usage example](img/variable_types_usage_example.png)
@@ -345,7 +357,12 @@ Group-level variables can be added by:
1. Inputing variable types, keys, and values in the **Variables** section.
Any variables of [subgroups](../../user/group/subgroups/index.md) will be inherited recursively.
-Once you set them, they will be available for all subsequent pipelines.
+Once you set them, they will be available for all subsequent pipelines. Any group-level user defined variables can be viewed in projects by:
+
+1. Navigating to the project's **Settings > CI/CD** page.
+1. Expanding the **Variables** section.
+
+![CI/CD settings - inherited variables](img/inherited_group_variables_v12_5.png)
## Priority of environment variables
diff --git a/doc/ci/variables/deprecated_variables.md b/doc/ci/variables/deprecated_variables.md
index cdca5bf27fc..543da481938 100644
--- a/doc/ci/variables/deprecated_variables.md
+++ b/doc/ci/variables/deprecated_variables.md
@@ -20,15 +20,15 @@ future GitLab releases.**
| 8.x name | 9.0+ name |
| --------------------- |------------------------ |
+| `CI_BUILD_BEFORE_SHA` | `CI_COMMIT_BEFORE_SHA` |
| `CI_BUILD_ID` | `CI_JOB_ID` |
+| `CI_BUILD_MANUAL` | `CI_JOB_MANUAL` |
+| `CI_BUILD_NAME` | `CI_JOB_NAME` |
| `CI_BUILD_REF` | `CI_COMMIT_SHA` |
-| `CI_BUILD_TAG` | `CI_COMMIT_TAG` |
-| `CI_BUILD_BEFORE_SHA` | `CI_COMMIT_BEFORE_SHA` |
| `CI_BUILD_REF_NAME` | `CI_COMMIT_REF_NAME` |
| `CI_BUILD_REF_SLUG` | `CI_COMMIT_REF_SLUG` |
-| `CI_BUILD_NAME` | `CI_JOB_NAME` |
-| `CI_BUILD_STAGE` | `CI_JOB_STAGE` |
| `CI_BUILD_REPO` | `CI_REPOSITORY_URL` |
-| `CI_BUILD_TRIGGERED` | `CI_PIPELINE_TRIGGERED` |
-| `CI_BUILD_MANUAL` | `CI_JOB_MANUAL` |
+| `CI_BUILD_STAGE` | `CI_JOB_STAGE` |
+| `CI_BUILD_TAG` | `CI_COMMIT_TAG` |
| `CI_BUILD_TOKEN` | `CI_JOB_TOKEN` |
+| `CI_BUILD_TRIGGERED` | `CI_PIPELINE_TRIGGERED` |
diff --git a/doc/ci/variables/img/inherited_group_variables_v12_5.png b/doc/ci/variables/img/inherited_group_variables_v12_5.png
new file mode 100644
index 00000000000..f9043df051c
--- /dev/null
+++ b/doc/ci/variables/img/inherited_group_variables_v12_5.png
Binary files differ
diff --git a/doc/ci/variables/predefined_variables.md b/doc/ci/variables/predefined_variables.md
index 20e70d212b0..b93ff62cc21 100644
--- a/doc/ci/variables/predefined_variables.md
+++ b/doc/ci/variables/predefined_variables.md
@@ -21,111 +21,111 @@ future GitLab releases.**
## Variables reference
-| Variable | GitLab | Runner | Description |
-|-------------------------------------------|--------|--------|-------------|
-| `ARTIFACT_DOWNLOAD_ATTEMPTS` | 8.15 | 1.9 | Number of attempts to download artifacts running a job |
-| `CHAT_INPUT` | 10.6 | all | Additional arguments passed in the [ChatOps](../chatops/README.md) command |
-| `CHAT_CHANNEL` | 10.6 | all | Source chat channel which triggered the [ChatOps](../chatops/README.md) command |
-| `CI` | all | 0.4 | Mark that job is executed in CI environment |
-| `CI_BUILDS_DIR` | all | 11.10 | Top-level directory where builds are executed. |
-| `CI_CONCURRENT_ID` | all | 11.10 | Unique ID of build execution within a single executor. |
-| `CI_CONCURRENT_PROJECT_ID` | all | 11.10 | Unique ID of build execution within a single executor and project. |
-| `CI_COMMIT_BEFORE_SHA` | 11.2 | all | The previous latest commit present on a branch before a merge request. Only populated when there is a merge request associated with the pipeline. |
-| `CI_COMMIT_DESCRIPTION` | 10.8 | all | The description of the commit: the message without first line, if the title is shorter than 100 characters; full message in other case. |
-| `CI_COMMIT_MESSAGE` | 10.8 | all | The full commit message. |
-| `CI_COMMIT_REF_NAME` | 9.0 | all | The branch or tag name for which project is built |
-| `CI_COMMIT_REF_SLUG` | 9.0 | all | `$CI_COMMIT_REF_NAME` lowercased, shortened to 63 bytes, and with everything except `0-9` and `a-z` replaced with `-`. No leading / trailing `-`. Use in URLs, host names and domain names. |
-| `CI_COMMIT_SHA` | 9.0 | all | The commit revision for which project is built |
-| `CI_COMMIT_SHORT_SHA` | 11.7 | all | The first eight characters of `CI_COMMIT_SHA` |
-| `CI_COMMIT_TAG` | 9.0 | 0.5 | The commit tag name. Present only when building tags. |
-| `CI_COMMIT_TITLE` | 10.8 | all | The title of the commit - the full first line of the message |
-| `CI_CONFIG_PATH` | 9.4 | 0.5 | The path to CI config file. Defaults to `.gitlab-ci.yml` |
-| `CI_DEBUG_TRACE` | all | 1.7 | Whether [debug logging (tracing)](README.md#debug-logging) is enabled |
-| `CI_DEPLOY_PASSWORD` | 10.8 | all | Authentication password of the [GitLab Deploy Token][gitlab-deploy-token], only present if the Project has one related.|
-| `CI_DEPLOY_USER` | 10.8 | all | Authentication username of the [GitLab Deploy Token][gitlab-deploy-token], only present if the Project has one related.|
-| `CI_DISPOSABLE_ENVIRONMENT` | all | 10.1 | Marks that the job is executed in a disposable environment (something that is created only for this job and disposed of/destroyed after the execution - all executors except `shell` and `ssh`). If the environment is disposable, it is set to true, otherwise it is not defined at all. |
-| `CI_ENVIRONMENT_NAME` | 8.15 | all | The name of the environment for this job. Only present if [`environment:name`](../yaml/README.md#environmentname) is set. |
-| `CI_ENVIRONMENT_SLUG` | 8.15 | all | A simplified version of the environment name, suitable for inclusion in DNS, URLs, Kubernetes labels, etc. Only present if [`environment:name`](../yaml/README.md#environmentname) is set. |
-| `CI_ENVIRONMENT_URL` | 9.3 | all | The URL of the environment for this job. Only present if [`environment:url`](../yaml/README.md#environmenturl) is set. |
-| `CI_DEFAULT_BRANCH` | 12.4 | all | The name of the default branch for the project. |
-| `CI_JOB_ID` | 9.0 | all | The unique id of the current job that GitLab CI uses internally |
-| `CI_JOB_MANUAL` | 8.12 | all | The flag to indicate that job was manually started |
-| `CI_JOB_NAME` | 9.0 | 0.5 | The name of the job as defined in `.gitlab-ci.yml` |
-| `CI_JOB_STAGE` | 9.0 | 0.5 | The name of the stage as defined in `.gitlab-ci.yml` |
-| `CI_JOB_TOKEN` | 9.0 | 1.2 | Token used for authenticating with the [GitLab Container Registry][registry] and downloading [dependent repositories][dependent-repositories] |
-| `CI_JOB_URL` | 11.1 | 0.5 | Job details URL |
-| `CI_MERGE_REQUEST_ID` | 11.6 | all | The ID of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. |
-| `CI_MERGE_REQUEST_IID` | 11.6 | all | The IID of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. |
-| `CI_MERGE_REQUEST_PROJECT_ID` | 11.6 | all | The ID of the project of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. |
-| `CI_MERGE_REQUEST_PROJECT_PATH` | 11.6 | all | The path of the project of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md) (e.g. `namespace/awesome-project`). Available only if `only: [merge_requests]` is used and the merge request is created. |
-| `CI_MERGE_REQUEST_PROJECT_URL` | 11.6 | all | The URL of the project of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md) (e.g. `http://192.168.10.15:3000/namespace/awesome-project`). Available only if `only: [merge_requests]` is used and the merge request is created. |
-| `CI_MERGE_REQUEST_REF_PATH` | 11.6 | all | The ref path of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). (e.g. `refs/merge-requests/1/head`). Available only if `only: [merge_requests]` is used and the merge request is created. |
-| `CI_MERGE_REQUEST_SOURCE_BRANCH_NAME` | 11.6 | all | The source branch name of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. |
-| `CI_MERGE_REQUEST_SOURCE_BRANCH_SHA` | 11.9 | all | The HEAD SHA of the source branch of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used, the merge request is created, and the pipeline is a [merged result pipeline](../merge_request_pipelines/pipelines_for_merged_results/index.md). **(PREMIUM)** |
-| `CI_MERGE_REQUEST_SOURCE_PROJECT_ID` | 11.6 | all | The ID of the source project of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. |
-| `CI_MERGE_REQUEST_SOURCE_PROJECT_PATH` | 11.6 | all | The path of the source project of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. |
-| `CI_MERGE_REQUEST_SOURCE_PROJECT_URL` | 11.6 | all | The URL of the source project of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. |
-| `CI_MERGE_REQUEST_TARGET_BRANCH_NAME` | 11.6 | all | The target branch name of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. |
-| `CI_MERGE_REQUEST_TARGET_BRANCH_SHA` | 11.9 | all | The HEAD SHA of the target branch of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used, the merge request is created, and the pipeline is a [merged result pipeline](../merge_request_pipelines/pipelines_for_merged_results/index.md). **(PREMIUM)** |
-| `CI_MERGE_REQUEST_TITLE` | 11.9 | all | The title of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. |
-| `CI_MERGE_REQUEST_ASSIGNEES` | 11.9 | all | Comma-separated list of username(s) of assignee(s) for the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. |
-| `CI_MERGE_REQUEST_MILESTONE` | 11.9 | all | The milestone title of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. |
-| `CI_MERGE_REQUEST_LABELS` | 11.9 | all | Comma-separated label names of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. |
-| `CI_EXTERNAL_PULL_REQUEST_IID` | 12.3 | all | Pull Request ID from GitHub if the [pipelines are for external pull requests](../ci_cd_for_external_repos/index.md#pipelines-for-external-pull-requests). Available only if `only: [external_pull_requests]` is used and the pull request is open. |
-| `CI_EXTERNAL_PULL_REQUEST_SOURCE_BRANCH_SHA` | 12.3 | all | The HEAD SHA of the source branch of the pull request if [the pipelines are for external pull requests](../ci_cd_for_external_repos/index.md#pipelines-for-external-pull-requests). Available only if `only: [external_pull_requests]` is used and the pull request is open. |
-| `CI_EXTERNAL_PULL_REQUEST_TARGET_BRANCH_SHA` | 12.3 | all | The HEAD SHA of the target branch of the pull request if [the pipelines are for external pull requests](../ci_cd_for_external_repos/index.md#pipelines-for-external-pull-requests). Available only if `only: [external_pull_requests]` is used and the pull request is open. |
-| `CI_EXTERNAL_PULL_REQUEST_SOURCE_BRANCH_NAME` | 12.3 | all | The source branch name of the pull request if [the pipelines are for external pull requests](../ci_cd_for_external_repos/index.md#pipelines-for-external-pull-requests). Available only if `only: [external_pull_requests]` is used and the pull request is open. |
-| `CI_EXTERNAL_PULL_REQUEST_TARGET_BRANCH_NAME` | 12.3 | all | The target branch name of the pull request if [the pipelines are for external pull requests](../ci_cd_for_external_repos/index.md#pipelines-for-external-pull-requests). Available only if `only: [external_pull_requests]` is used and the pull request is open. |
-| `CI_NODE_INDEX` | 11.5 | all | Index of the job in the job set. If the job is not parallelized, this variable is not set. |
-| `CI_NODE_TOTAL` | 11.5 | all | Total number of instances of this job running in parallel. If the job is not parallelized, this variable is set to `1`. |
-| `CI_API_V4_URL` | 11.7 | all | The GitLab API v4 root URL |
-| `CI_PAGES_DOMAIN` | 11.8 | all | The configured domain that hosts GitLab Pages. |
-| `CI_PAGES_URL` | 11.8 | all | URL to GitLab Pages-built pages. Always belongs to a subdomain of `CI_PAGES_DOMAIN`. |
-| `CI_PIPELINE_ID` | 8.10 | all | The unique id of the current pipeline that GitLab CI uses internally |
-| `CI_PIPELINE_IID` | 11.0 | all | The unique id of the current pipeline scoped to project |
-| `CI_PIPELINE_SOURCE` | 10.0 | all | Indicates how the pipeline was triggered. Possible options are: `push`, `web`, `trigger`, `schedule`, `api`, and `pipeline`. For pipelines created before GitLab 9.5, this will show as `unknown` |
-| `CI_PIPELINE_TRIGGERED` | all | all | The flag to indicate that job was [triggered](../triggers/README.md) |
-| `CI_PIPELINE_URL` | 11.1 | 0.5 | Pipeline details URL |
-| `CI_PROJECT_DIR` | all | all | The full path where the repository is cloned and where the job is run. If the GitLab Runner `builds_dir` parameter is set, this variable is set relative to the value of `builds_dir`. For more information, see [Advanced configuration](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section) for GitLab Runner. |
-| `CI_PROJECT_ID` | all | all | The unique id of the current project that GitLab CI uses internally |
-| `CI_PROJECT_NAME` | 8.10 | 0.5 | The name of the directory for the project that is currently being built. For example, if the project URL is `gitlab.example.com/group-name/project-1`, the `CI_PROJECT_NAME` would be `project-1`. |
-| `CI_PROJECT_TITLE` | 12.4 | all | The human-readable project name as displayed in the GitLab web interface. |
-| `CI_PROJECT_NAMESPACE` | 8.10 | 0.5 | The project namespace (username or groupname) that is currently being built |
-| `CI_PROJECT_PATH` | 8.10 | 0.5 | The namespace with project name |
-| `CI_PROJECT_PATH_SLUG` | 9.3 | all | `$CI_PROJECT_PATH` lowercased and with everything except `0-9` and `a-z` replaced with `-`. Use in URLs and domain names. |
-| `CI_PROJECT_URL` | 8.10 | 0.5 | The HTTP(S) address to access project |
-| `CI_PROJECT_VISIBILITY` | 10.3 | all | The project visibility (internal, private, public) |
-| `CI_PROJECT_REPOSITORY_LANGUAGES` | 12.3 | all | Comma-separated, lowercased list of the languages used in the repository (e.g. `ruby,javascript,html,css`) |
-| `CI_COMMIT_REF_PROTECTED` | 11.11 | all | If the job is running on a protected branch |
-| `CI_REGISTRY` | 8.10 | 0.5 | If the Container Registry is enabled it returns the address of GitLab's Container Registry |
-| `CI_REGISTRY_IMAGE` | 8.10 | 0.5 | If the Container Registry is enabled for the project it returns the address of the registry tied to the specific project |
-| `CI_REGISTRY_PASSWORD` | 9.0 | all | The password to use to push containers to the GitLab Container Registry |
-| `CI_REGISTRY_USER` | 9.0 | all | The username to use to push containers to the GitLab Container Registry |
-| `CI_REPOSITORY_URL` | 9.0 | all | The URL to clone the Git repository |
-| `CI_RUNNER_DESCRIPTION` | 8.10 | 0.5 | The description of the runner as saved in GitLab |
-| `CI_RUNNER_EXECUTABLE_ARCH` | all | 10.6 | The OS/architecture of the GitLab Runner executable (note that this is not necessarily the same as the environment of the executor) |
-| `CI_RUNNER_ID` | 8.10 | 0.5 | The unique id of runner being used |
-| `CI_RUNNER_REVISION` | all | 10.6 | GitLab Runner revision that is executing the current job |
-| `CI_RUNNER_TAGS` | 8.10 | 0.5 | The defined runner tags |
-| `CI_RUNNER_VERSION` | all | 10.6 | GitLab Runner version that is executing the current job |
-| `CI_RUNNER_SHORT_TOKEN` | all | 12.3 | First eight characters of GitLab Runner's token used to authenticate new job requests. Used as Runner's unique ID |
-| `CI_SERVER` | all | all | Mark that job is executed in CI environment |
-| `CI_SERVER_HOST` | 12.1 | all | Host component of the GitLab instance URL, without protocol and port (like `gitlab.example.com`) |
-| `CI_SERVER_NAME` | all | all | The name of CI server that is used to coordinate jobs |
-| `CI_SERVER_REVISION` | all | all | GitLab revision that is used to schedule jobs |
-| `CI_SERVER_VERSION` | all | all | GitLab version that is used to schedule jobs |
-| `CI_SERVER_VERSION_MAJOR` | 11.4 | all | GitLab version major component |
-| `CI_SERVER_VERSION_MINOR` | 11.4 | all | GitLab version minor component |
-| `CI_SERVER_VERSION_PATCH` | 11.4 | all | GitLab version patch component |
-| `CI_SHARED_ENVIRONMENT` | all | 10.1 | Marks that the job is executed in a shared environment (something that is persisted across CI invocations like `shell` or `ssh` executor). If the environment is shared, it is set to true, otherwise it is not defined at all. |
-| `GET_SOURCES_ATTEMPTS` | 8.15 | 1.9 | Number of attempts to fetch sources running a job |
-| `GITLAB_CI` | all | all | Mark that job is executed in GitLab CI environment |
-| `GITLAB_USER_EMAIL` | 8.12 | all | The email of the user who started the job |
-| `GITLAB_USER_ID` | 8.12 | all | The id of the user who started the job |
-| `GITLAB_USER_LOGIN` | 10.0 | all | The login username of the user who started the job |
-| `GITLAB_USER_NAME` | 10.0 | all | The real name of the user who started the job |
-| `RESTORE_CACHE_ATTEMPTS` | 8.15 | 1.9 | Number of attempts to restore the cache running a job |
-| `GITLAB_FEATURES` | 10.6 | all | The comma separated list of licensed features available for your instance and plan |
+| Variable | GitLab | Runner | Description |
+|-----------------------------------------------|--------|--------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `ARTIFACT_DOWNLOAD_ATTEMPTS` | 8.15 | 1.9 | Number of attempts to download artifacts running a job |
+| `CHAT_CHANNEL` | 10.6 | all | Source chat channel which triggered the [ChatOps](../chatops/README.md) command |
+| `CHAT_INPUT` | 10.6 | all | Additional arguments passed in the [ChatOps](../chatops/README.md) command |
+| `CI` | all | 0.4 | Mark that job is executed in CI environment |
+| `CI_API_V4_URL` | 11.7 | all | The GitLab API v4 root URL |
+| `CI_BUILDS_DIR` | all | 11.10 | Top-level directory where builds are executed. |
+| `CI_COMMIT_BEFORE_SHA` | 11.2 | all | The previous latest commit present on a branch before a merge request. Only populated when there is a merge request associated with the pipeline. |
+| `CI_COMMIT_DESCRIPTION` | 10.8 | all | The description of the commit: the message without first line, if the title is shorter than 100 characters; full message in other case. |
+| `CI_COMMIT_MESSAGE` | 10.8 | all | The full commit message. |
+| `CI_COMMIT_REF_NAME` | 9.0 | all | The branch or tag name for which project is built |
+| `CI_COMMIT_REF_PROTECTED` | 11.11 | all | If the job is running on a protected branch |
+| `CI_COMMIT_REF_SLUG` | 9.0 | all | `$CI_COMMIT_REF_NAME` lowercased, shortened to 63 bytes, and with everything except `0-9` and `a-z` replaced with `-`. No leading / trailing `-`. Use in URLs, host names and domain names. |
+| `CI_COMMIT_SHA` | 9.0 | all | The commit revision for which project is built |
+| `CI_COMMIT_SHORT_SHA` | 11.7 | all | The first eight characters of `CI_COMMIT_SHA` |
+| `CI_COMMIT_TAG` | 9.0 | 0.5 | The commit tag name. Present only when building tags. |
+| `CI_COMMIT_TITLE` | 10.8 | all | The title of the commit - the full first line of the message |
+| `CI_CONCURRENT_ID` | all | 11.10 | Unique ID of build execution within a single executor. |
+| `CI_CONCURRENT_PROJECT_ID` | all | 11.10 | Unique ID of build execution within a single executor and project. |
+| `CI_CONFIG_PATH` | 9.4 | 0.5 | The path to CI config file. Defaults to `.gitlab-ci.yml` |
+| `CI_DEBUG_TRACE` | all | 1.7 | Whether [debug logging (tracing)](README.md#debug-logging) is enabled |
+| `CI_DEFAULT_BRANCH` | 12.4 | all | The name of the default branch for the project. |
+| `CI_DEPLOY_PASSWORD` | 10.8 | all | Authentication password of the [GitLab Deploy Token][gitlab-deploy-token], only present if the Project has one related. |
+| `CI_DEPLOY_USER` | 10.8 | all | Authentication username of the [GitLab Deploy Token][gitlab-deploy-token], only present if the Project has one related. |
+| `CI_DISPOSABLE_ENVIRONMENT` | all | 10.1 | Marks that the job is executed in a disposable environment (something that is created only for this job and disposed of/destroyed after the execution - all executors except `shell` and `ssh`). If the environment is disposable, it is set to true, otherwise it is not defined at all. |
+| `CI_ENVIRONMENT_NAME` | 8.15 | all | The name of the environment for this job. Only present if [`environment:name`](../yaml/README.md#environmentname) is set. |
+| `CI_ENVIRONMENT_SLUG` | 8.15 | all | A simplified version of the environment name, suitable for inclusion in DNS, URLs, Kubernetes labels, etc. Only present if [`environment:name`](../yaml/README.md#environmentname) is set. |
+| `CI_ENVIRONMENT_URL` | 9.3 | all | The URL of the environment for this job. Only present if [`environment:url`](../yaml/README.md#environmenturl) is set. |
+| `CI_EXTERNAL_PULL_REQUEST_IID` | 12.3 | all | Pull Request ID from GitHub if the [pipelines are for external pull requests](../ci_cd_for_external_repos/index.md#pipelines-for-external-pull-requests). Available only if `only: [external_pull_requests]` is used and the pull request is open. |
+| `CI_EXTERNAL_PULL_REQUEST_SOURCE_BRANCH_NAME` | 12.3 | all | The source branch name of the pull request if [the pipelines are for external pull requests](../ci_cd_for_external_repos/index.md#pipelines-for-external-pull-requests). Available only if `only: [external_pull_requests]` is used and the pull request is open. |
+| `CI_EXTERNAL_PULL_REQUEST_SOURCE_BRANCH_SHA` | 12.3 | all | The HEAD SHA of the source branch of the pull request if [the pipelines are for external pull requests](../ci_cd_for_external_repos/index.md#pipelines-for-external-pull-requests). Available only if `only: [external_pull_requests]` is used and the pull request is open. |
+| `CI_EXTERNAL_PULL_REQUEST_TARGET_BRANCH_NAME` | 12.3 | all | The target branch name of the pull request if [the pipelines are for external pull requests](../ci_cd_for_external_repos/index.md#pipelines-for-external-pull-requests). Available only if `only: [external_pull_requests]` is used and the pull request is open. |
+| `CI_EXTERNAL_PULL_REQUEST_TARGET_BRANCH_SHA` | 12.3 | all | The HEAD SHA of the target branch of the pull request if [the pipelines are for external pull requests](../ci_cd_for_external_repos/index.md#pipelines-for-external-pull-requests). Available only if `only: [external_pull_requests]` is used and the pull request is open. |
+| `CI_JOB_ID` | 9.0 | all | The unique id of the current job that GitLab CI uses internally |
+| `CI_JOB_MANUAL` | 8.12 | all | The flag to indicate that job was manually started |
+| `CI_JOB_NAME` | 9.0 | 0.5 | The name of the job as defined in `.gitlab-ci.yml` |
+| `CI_JOB_STAGE` | 9.0 | 0.5 | The name of the stage as defined in `.gitlab-ci.yml` |
+| `CI_JOB_TOKEN` | 9.0 | 1.2 | Token used for authenticating with the [GitLab Container Registry][registry] and downloading [dependent repositories][dependent-repositories] |
+| `CI_JOB_URL` | 11.1 | 0.5 | Job details URL |
+| `CI_MERGE_REQUEST_ASSIGNEES` | 11.9 | all | Comma-separated list of username(s) of assignee(s) for the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. |
+| `CI_MERGE_REQUEST_ID` | 11.6 | all | The ID of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. |
+| `CI_MERGE_REQUEST_IID` | 11.6 | all | The IID of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. |
+| `CI_MERGE_REQUEST_LABELS` | 11.9 | all | Comma-separated label names of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. |
+| `CI_MERGE_REQUEST_MILESTONE` | 11.9 | all | The milestone title of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. |
+| `CI_MERGE_REQUEST_PROJECT_ID` | 11.6 | all | The ID of the project of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. |
+| `CI_MERGE_REQUEST_PROJECT_PATH` | 11.6 | all | The path of the project of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md) (e.g. `namespace/awesome-project`). Available only if `only: [merge_requests]` is used and the merge request is created. |
+| `CI_MERGE_REQUEST_PROJECT_URL` | 11.6 | all | The URL of the project of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md) (e.g. `http://192.168.10.15:3000/namespace/awesome-project`). Available only if `only: [merge_requests]` is used and the merge request is created. |
+| `CI_MERGE_REQUEST_REF_PATH` | 11.6 | all | The ref path of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). (e.g. `refs/merge-requests/1/head`). Available only if `only: [merge_requests]` is used and the merge request is created. |
+| `CI_MERGE_REQUEST_SOURCE_BRANCH_NAME` | 11.6 | all | The source branch name of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. |
+| `CI_MERGE_REQUEST_SOURCE_BRANCH_SHA` | 11.9 | all | The HEAD SHA of the source branch of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used, the merge request is created, and the pipeline is a [merged result pipeline](../merge_request_pipelines/pipelines_for_merged_results/index.md). **(PREMIUM)** |
+| `CI_MERGE_REQUEST_SOURCE_PROJECT_ID` | 11.6 | all | The ID of the source project of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. |
+| `CI_MERGE_REQUEST_SOURCE_PROJECT_PATH` | 11.6 | all | The path of the source project of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. |
+| `CI_MERGE_REQUEST_SOURCE_PROJECT_URL` | 11.6 | all | The URL of the source project of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. |
+| `CI_MERGE_REQUEST_TARGET_BRANCH_NAME` | 11.6 | all | The target branch name of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. |
+| `CI_MERGE_REQUEST_TARGET_BRANCH_SHA` | 11.9 | all | The HEAD SHA of the target branch of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used, the merge request is created, and the pipeline is a [merged result pipeline](../merge_request_pipelines/pipelines_for_merged_results/index.md). **(PREMIUM)** |
+| `CI_MERGE_REQUEST_TITLE` | 11.9 | all | The title of the merge request if [the pipelines are for merge requests](../merge_request_pipelines/index.md). Available only if `only: [merge_requests]` is used and the merge request is created. |
+| `CI_NODE_INDEX` | 11.5 | all | Index of the job in the job set. If the job is not parallelized, this variable is not set. |
+| `CI_NODE_TOTAL` | 11.5 | all | Total number of instances of this job running in parallel. If the job is not parallelized, this variable is set to `1`. |
+| `CI_PAGES_DOMAIN` | 11.8 | all | The configured domain that hosts GitLab Pages. |
+| `CI_PAGES_URL` | 11.8 | all | URL to GitLab Pages-built pages. Always belongs to a subdomain of `CI_PAGES_DOMAIN`. |
+| `CI_PIPELINE_ID` | 8.10 | all | The unique id of the current pipeline that GitLab CI uses internally |
+| `CI_PIPELINE_IID` | 11.0 | all | The unique id of the current pipeline scoped to project |
+| `CI_PIPELINE_SOURCE` | 10.0 | all | Indicates how the pipeline was triggered. Possible options are: `push`, `web`, `trigger`, `schedule`, `api`, and `pipeline`. For pipelines created before GitLab 9.5, this will show as `unknown` |
+| `CI_PIPELINE_TRIGGERED` | all | all | The flag to indicate that job was [triggered](../triggers/README.md) |
+| `CI_PIPELINE_URL` | 11.1 | 0.5 | Pipeline details URL |
+| `CI_PROJECT_DIR` | all | all | The full path where the repository is cloned and where the job is run. If the GitLab Runner `builds_dir` parameter is set, this variable is set relative to the value of `builds_dir`. For more information, see [Advanced configuration](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section) for GitLab Runner. |
+| `CI_PROJECT_ID` | all | all | The unique id of the current project that GitLab CI uses internally |
+| `CI_PROJECT_NAME` | 8.10 | 0.5 | The name of the directory for the project that is currently being built. For example, if the project URL is `gitlab.example.com/group-name/project-1`, the `CI_PROJECT_NAME` would be `project-1`. |
+| `CI_PROJECT_NAMESPACE` | 8.10 | 0.5 | The project namespace (username or groupname) that is currently being built |
+| `CI_PROJECT_PATH` | 8.10 | 0.5 | The namespace with project name |
+| `CI_PROJECT_PATH_SLUG` | 9.3 | all | `$CI_PROJECT_PATH` lowercased and with everything except `0-9` and `a-z` replaced with `-`. Use in URLs and domain names. |
+| `CI_PROJECT_REPOSITORY_LANGUAGES` | 12.3 | all | Comma-separated, lowercased list of the languages used in the repository (e.g. `ruby,javascript,html,css`) |
+| `CI_PROJECT_TITLE` | 12.4 | all | The human-readable project name as displayed in the GitLab web interface. |
+| `CI_PROJECT_URL` | 8.10 | 0.5 | The HTTP(S) address to access project |
+| `CI_PROJECT_VISIBILITY` | 10.3 | all | The project visibility (internal, private, public) |
+| `CI_REGISTRY` | 8.10 | 0.5 | If the Container Registry is enabled it returns the address of GitLab's Container Registry. This variable will include a `:port` value if one has been specified in the registry configuration. |
+| `CI_REGISTRY_IMAGE` | 8.10 | 0.5 | If the Container Registry is enabled for the project it returns the address of the registry tied to the specific project |
+| `CI_REGISTRY_PASSWORD` | 9.0 | all | The password to use to push containers to the GitLab Container Registry |
+| `CI_REGISTRY_USER` | 9.0 | all | The username to use to push containers to the GitLab Container Registry |
+| `CI_REPOSITORY_URL` | 9.0 | all | The URL to clone the Git repository |
+| `CI_RUNNER_DESCRIPTION` | 8.10 | 0.5 | The description of the runner as saved in GitLab |
+| `CI_RUNNER_EXECUTABLE_ARCH` | all | 10.6 | The OS/architecture of the GitLab Runner executable (note that this is not necessarily the same as the environment of the executor) |
+| `CI_RUNNER_ID` | 8.10 | 0.5 | The unique id of runner being used |
+| `CI_RUNNER_REVISION` | all | 10.6 | GitLab Runner revision that is executing the current job |
+| `CI_RUNNER_SHORT_TOKEN` | all | 12.3 | First eight characters of GitLab Runner's token used to authenticate new job requests. Used as Runner's unique ID |
+| `CI_RUNNER_TAGS` | 8.10 | 0.5 | The defined runner tags |
+| `CI_RUNNER_VERSION` | all | 10.6 | GitLab Runner version that is executing the current job |
+| `CI_SERVER` | all | all | Mark that job is executed in CI environment |
+| `CI_SERVER_HOST` | 12.1 | all | Host component of the GitLab instance URL, without protocol and port (like `gitlab.example.com`) |
+| `CI_SERVER_NAME` | all | all | The name of CI server that is used to coordinate jobs |
+| `CI_SERVER_REVISION` | all | all | GitLab revision that is used to schedule jobs |
+| `CI_SERVER_VERSION` | all | all | GitLab version that is used to schedule jobs |
+| `CI_SERVER_VERSION_MAJOR` | 11.4 | all | GitLab version major component |
+| `CI_SERVER_VERSION_MINOR` | 11.4 | all | GitLab version minor component |
+| `CI_SERVER_VERSION_PATCH` | 11.4 | all | GitLab version patch component |
+| `CI_SHARED_ENVIRONMENT` | all | 10.1 | Marks that the job is executed in a shared environment (something that is persisted across CI invocations like `shell` or `ssh` executor). If the environment is shared, it is set to true, otherwise it is not defined at all. |
+| `GET_SOURCES_ATTEMPTS` | 8.15 | 1.9 | Number of attempts to fetch sources running a job |
+| `GITLAB_CI` | all | all | Mark that job is executed in GitLab CI environment |
+| `GITLAB_FEATURES` | 10.6 | all | The comma separated list of licensed features available for your instance and plan |
+| `GITLAB_USER_EMAIL` | 8.12 | all | The email of the user who started the job |
+| `GITLAB_USER_ID` | 8.12 | all | The id of the user who started the job |
+| `GITLAB_USER_LOGIN` | 10.0 | all | The login username of the user who started the job |
+| `GITLAB_USER_NAME` | 10.0 | all | The real name of the user who started the job |
+| `RESTORE_CACHE_ATTEMPTS` | 8.15 | 1.9 | Number of attempts to restore the cache running a job |
[gitlab-deploy-token]: ../../user/project/deploy_tokens/index.md#gitlab-deploy-token
[registry]: ../../user/packages/container_registry/index.md
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 4569e9ff9b6..62644e78872 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -23,7 +23,7 @@ We have complete examples of configuring pipelines:
- To see a large `.gitlab-ci.yml` file used in an enterprise, see the [`.gitlab-ci.yml` file for `gitlab`](https://gitlab.com/gitlab-org/gitlab/blob/master/.gitlab-ci.yml).
NOTE: **Note:**
-If you have a [mirrored repository where GitLab pulls from](../../workflow/repository_mirroring.md#pulling-from-a-remote-repository-starter),
+If you have a [mirrored repository where GitLab pulls from](../../user/project/repository/repository_mirroring.md#pulling-from-a-remote-repository-starter),
you may need to enable pipeline triggering in your project's
**Settings > Repository > Pull from a remote repository > Trigger pipelines for mirror updates**.
@@ -106,7 +106,7 @@ The following table lists available parameters for jobs:
| [`when`](#when) | When to run job. Also available: `when:manual` and `when:delayed`. |
| [`environment`](#environment) | Name of an environment to which the job deploys. Also available: `environment:name`, `environment:url`, `environment:on_stop`, and `environment:action`. |
| [`cache`](#cache) | List of files that should be cached between subsequent runs. Also available: `cache:paths`, `cache:key`, `cache:untracked`, and `cache:policy`. |
-| [`artifacts`](#artifacts) | List of files and directories to attach to a job on success. Also available: `artifacts:paths`, `artifacts:name`, `artifacts:untracked`, `artifacts:when`, `artifacts:expire_in`, `artifacts:reports`, and `artifacts:reports:junit`.<br><br>In GitLab [Enterprise Edition](https://about.gitlab.com/pricing/), these are available: `artifacts:reports:codequality`, `artifacts:reports:sast`, `artifacts:reports:dependency_scanning`, `artifacts:reports:container_scanning`, `artifacts:reports:dast`, `artifacts:reports:license_management`, `artifacts:reports:performance` and `artifacts:reports:metrics`. |
+| [`artifacts`](#artifacts) | List of files and directories to attach to a job on success. Also available: `artifacts:paths`, `artifacts:expose_as`, `artifacts:name`, `artifacts:untracked`, `artifacts:when`, `artifacts:expire_in`, `artifacts:reports`, and `artifacts:reports:junit`.<br><br>In GitLab [Enterprise Edition](https://about.gitlab.com/pricing/), these are available: `artifacts:reports:codequality`, `artifacts:reports:sast`, `artifacts:reports:dependency_scanning`, `artifacts:reports:container_scanning`, `artifacts:reports:dast`, `artifacts:reports:license_management`, `artifacts:reports:performance` and `artifacts:reports:metrics`. |
| [`dependencies`](#dependencies) | Restrict which artifacts are passed to a specific job by providing a list of jobs to fetch artifacts from. |
| [`coverage`](#coverage) | Code coverage settings for a given job. |
| [`retry`](#retry) | When and how many times a job can be auto-retried in case of a failure. |
@@ -135,6 +135,7 @@ The following job parameters can be defined inside a `default:` block:
- [`before_script`](#before_script-and-after_script)
- [`after_script`](#before_script-and-after_script)
- [`cache`](#cache)
+- [`interruptible`](#interruptible)
In the following example, the `ruby:2.5` image is set as the default for all
jobs except the `rspec 2.6` job, which uses the `ruby:2.6` image:
@@ -181,6 +182,25 @@ that the YAML parser knows to interpret the whole thing as a string rather than
a "key: value" pair. Be careful when using special characters:
`:`, `{`, `}`, `[`, `]`, `,`, `&`, `*`, `#`, `?`, `|`, `-`, `<`, `>`, `=`, `!`, `%`, `@`, `` ` ``.
+#### YAML anchors for `script`
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/23005) in GitLab 12.5.
+
+You can use [YAML anchors](#anchors) with scripts, which makes it possible to
+include a predefined list of commands in multiple jobs.
+
+Example:
+
+```yaml
+.something: &something
+- echo 'something'
+
+job_name:
+ script:
+ - *something
+ - echo 'this is the script'
+```
+
### `image`
Used to specify [a Docker image](../docker/using_docker_images.md#what-is-an-image) to use for the job.
@@ -240,34 +260,26 @@ For more information, see see [Available settings for `services`](../docker/usin
> Introduced in GitLab 8.7 and requires GitLab Runner v1.2.
-`before_script` is used to define the command that should be run before all
-jobs, including deploy jobs, but after the restoration of [artifacts](#artifacts).
+`before_script` is used to define a command that should be run before each
+job, including deploy jobs, but after the restoration of any [artifacts](#artifacts).
This must be an an array.
-`after_script` is used to define the command that will be run after all
-jobs, including failed ones. This must be an an array.
-
-Scripts specified in `before_script` are:
+Scripts specified in `before_script` are concatenated with any scripts specified
+in the main [`script`](#script), and executed together in a single shell.
-- Concatenated with scripts specified in the main `script`. Job-level
- `before_script` definition override global-level `before_script` definition
- when concatenated with `script` definition.
-- Executed together with main `script` script as one script in a single shell
- context.
+`after_script` is used to define the command that will be run after each
+job, including failed ones. This must be an an array.
-Scripts specified in `after_script`:
+Scripts specified in `after_script` are executed in a new shell, separate from any
+`before_script` or `script` scripts. As a result, they:
- Have a current working directory set back to the default.
-- Are executed in a shell context separated from `before_script` and `script`
- scripts.
-- Because of separated context, cannot see changes done by scripts defined
- in `before_script` or `script` scripts, either:
- - In shell. For example, command aliases and variables exported in `script`
- scripts.
- - Outside of the working tree (depending on the Runner executor). For example,
- software installed by a `before_script` or `script` scripts.
-
-It's possible to overwrite the globally defined `before_script` and `after_script`
+- Have no access to changes done by scripts defined in `before_script` or `script`, including:
+ - Command aliases and variables exported in `script` scripts.
+ - Changes outside of the working tree (depending on the Runner executor), like
+ software installed by a `before_script` or `script` script.
+
+It's possible to overwrite a globally defined `before_script` or `after_script`
if you set it per-job:
```yaml
@@ -284,6 +296,33 @@ job:
- execute this after my script
```
+#### YAML anchors for `before_script` and `after_script`
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/23005) in GitLab 12.5.
+
+You can use [YAML anchors](#anchors) with `before_script` and `after_script`,
+which makes it possible to include a predefined list of commands in multiple
+jobs.
+
+Example:
+
+```yaml
+.something_before: &something_before
+- echo 'something before'
+
+.something_after: &something_after
+- echo 'something after'
+
+
+job_name:
+ before_script:
+ - *something_before
+ script:
+ - echo 'this is the script'
+ after_script:
+ - *something_after
+```
+
### `stages`
`stages` is used to define stages that can be used by jobs and is defined
@@ -329,6 +368,37 @@ The following stages are available to every pipeline:
User-defined stages are executed after `.pre` and before `.post`.
+The order of `.pre` and `.post` cannot be changed, even if defined out of order in `.gitlab-ci.yml`.
+For example, the following are equivalent configuration:
+
+- Configured in order:
+
+ ```yml
+ stages:
+ - .pre
+ - a
+ - b
+ - .post
+ ```
+
+- Configured out of order:
+
+ ```yml
+ stages:
+ - a
+ - .pre
+ - b
+ - .post
+ ```
+
+- Not explicitly configured:
+
+ ```yml
+ stages:
+ - a
+ - b
+ ```
+
### `stage`
`stage` is defined per-job and relies on [`stages`](#stages) which is defined
@@ -379,6 +449,9 @@ Jobs will run on your own Runners in parallel only if:
### `only`/`except` (basic)
+NOTE: **Note:**
+These parameters will soon be [deprecated](https://gitlab.com/gitlab-org/gitlab/issues/27449) in favor of [`rules`](#rules) as it offers a more powerful syntax.
+
`only` and `except` are two parameters that set a job policy to limit when
jobs are created:
@@ -926,12 +999,11 @@ docker build:
when: delayed
start_in: '3 hours'
- when: on_success # Otherwise include the job and set to run normally
-
```
Additional job configuration may be added to rules in the future. If something
useful isn't available, please
-[open an issue](https://www.gitlab.com/gitlab-org/gitlab/issues).
+[open an issue](https://gitlab.com/gitlab-org/gitlab/issues).
### `tags`
@@ -1463,6 +1535,50 @@ cache:
- binaries/
```
+##### `cache:key:files`
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/18986) in GitLab v12.5.
+
+If `cache:key:files` is added, one or two files must be defined with it. The cache `key`
+will be a SHA computed from the most recent commits (one or two) that changed the
+given files. If neither file was changed in any commits, the key will be `default`.
+
+```yaml
+cache:
+ key:
+ files:
+ - Gemfile.lock
+ - package.json
+ paths:
+ - vendor/ruby
+ - node_modules
+```
+
+##### `cache:key:prefix`
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/18986) in GitLab v12.5.
+
+The `prefix` parameter adds extra functionality to `key:files` by allowing the key to
+be composed of the given `prefix` combined with the SHA computed for `cache:key:files`.
+For example, adding a `prefix` of `rspec`, will
+cause keys to look like: `rspec-feef9576d21ee9b6a32e30c5c79d0a0ceb68d1e5`. If neither
+file was changed in any commits, the prefix is added to `default`, so the key in the
+example would be `rspec-default`.
+
+`prefix` follows the same restrictions as `key`, so it can use any of the
+[predefined variables](../variables/README.md). Similarly, the `/` character or the
+equivalent URI-encoded `%2F`, or a value made only of `.` or `%2E`, is not allowed.
+
+```yaml
+cache:
+ key:
+ files:
+ - Gemfile.lock
+ prefix: ${CI_JOB_NAME}
+ paths:
+ - vendor/ruby
+```
+
#### `cache:untracked`
Set `untracked: true` to cache all files that are untracked in your Git
@@ -1596,6 +1712,47 @@ release-job:
- tags
```
+#### `artifacts:expose_as`
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/15018) in GitLab 12.5.
+
+The `expose_as` keyword can be used to expose [job artifacts](../../user/project/pipelines/job_artifacts.md)
+in the [merge request](../../user/project/merge_requests/index.md) UI.
+
+For example, to match a single file:
+
+```yml
+test:
+ script: [ 'echo 1' ]
+ artifacts:
+ expose_as: 'artifact 1'
+ paths: ['path/to/file.txt']
+```
+
+With this configuration, GitLab will add a link **artifact 1** to the relevant merge request
+that points to `file1.txt`.
+
+An example that will match an entire directory:
+
+```yml
+test:
+ script: [ 'echo 1' ]
+ artifacts:
+ expose_as: 'artifact 1'
+ paths: ['path/to/directory/']
+```
+
+Note the following:
+
+- A maximum of 10 job artifacts per merge request can be exposed.
+- Glob patterns are unsupported.
+- If a directory is specified, the link will be to the job [artifacts browser](../../user/project/pipelines/job_artifacts.md#browsing-artifacts) if there is more than
+ one file in the directory.
+- For exposed single file artifacts with `.html`, `.htm`, `.txt`, `.json`, `.xml`,
+ and `.log` extensions, if [GitLab Pages](../../administration/pages/index.md) is:
+ - Enabled, GitLab will automatically render the artifact.
+ - Not enabled, you will see the file in the artifacts browser.
+
#### `artifacts:name`
> Introduced in GitLab 8.6 and GitLab Runner v1.1.0.
@@ -1910,8 +2067,6 @@ Defining an empty array will skip downloading any artifacts for that job.
The status of the previous job is not considered when using `dependencies`, so
if it failed or it is a manual job that was not run, no error occurs.
----
-
In the following example, we define two jobs with artifacts, `build:osx` and
`build:linux`. When the `test:osx` is executed, the artifacts from `build:osx`
will be downloaded and extracted in the context of the build. The same happens
@@ -2249,6 +2404,24 @@ staging:
branch: stable
```
+It is possible to mirror the status from a triggered pipeline:
+
+```
+trigger_job:
+ trigger:
+ project: my/project
+ strategy: depend
+```
+
+It is possible to mirror the status from an upstream pipeline:
+
+```
+upstream_bridge:
+ stage: test
+ needs:
+ pipeline: other/project
+```
+
### `interruptible`
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/23464) in GitLab 12.3.
diff --git a/doc/development/README.md b/doc/development/README.md
index 16b073045cc..66df6f46e86 100644
--- a/doc/development/README.md
+++ b/doc/development/README.md
@@ -99,7 +99,7 @@ description: 'Learn how to contribute to GitLab.'
- [Post deployment migrations](post_deployment_migrations.md)
- [Background migrations](background_migrations.md)
- [Swapping tables](swapping_tables.md)
-- [Deleting exiting migrations](deleting_migrations.md)
+- [Deleting migrations](deleting_migrations.md)
### Best practices
@@ -118,6 +118,7 @@ description: 'Learn how to contribute to GitLab.'
- [Query Count Limits](query_count_limits.md)
- [Database helper modules](database_helpers.md)
- [Code comments](code_comments.md)
+- [Creating enums](creating_enums.md)
### Case studies
diff --git a/doc/development/api_graphql_styleguide.md b/doc/development/api_graphql_styleguide.md
index cdd0e9b2a7b..b0d94511c6e 100644
--- a/doc/development/api_graphql_styleguide.md
+++ b/doc/development/api_graphql_styleguide.md
@@ -43,14 +43,14 @@ a new presenter specifically for GraphQL.
The presenter is initialized using the object resolved by a field, and
the context.
-### Exposing Global ids
+### Exposing Global IDs
-When exposing an `id` field on a type, we will by default try to
-expose a global id by calling `to_global_id` on the resource being
+When exposing an `ID` field on a type, we will by default try to
+expose a global ID by calling `to_global_id` on the resource being
rendered.
To override this behaviour, you can implement an `id` method on the
-type for which you are exposing an id. Please make sure that when
+type for which you are exposing an ID. Please make sure that when
exposing a `GraphQL::ID_TYPE` using a custom method that it is
globally unique.
@@ -146,6 +146,10 @@ query($project_path: ID!) {
}
```
+To ensure that we get consistent ordering, we will append an ordering on the primary
+key, in descending order. This is usually `id`, so basically we will add `order(id: :desc)`
+to the end of the relation. A primary key _must_ be available on the underlying table.
+
### Exposing permissions for a type
To expose permissions the current user has on a resource, you can call
@@ -236,6 +240,47 @@ end
```
+## Descriptions
+
+All fields and arguments
+[must have descriptions](https://gitlab.com/gitlab-org/gitlab/merge_requests/16438).
+
+A description of a field or argument is given using the `description:`
+keyword. For example:
+
+```ruby
+field :id, GraphQL::ID_TYPE, description: 'ID of the resource'
+```
+
+Descriptions of fields and arguments are viewable to users through:
+
+- The [GraphiQL explorer](../api/graphql/#graphiql).
+- The [static GraphQL API reference](../api/graphql/#reference).
+
+### Description styleguide
+
+To ensure consistency, the following should be followed whenever adding or updating
+descriptions:
+
+- Mention the name of the resource in the description. Example:
+ `'Labels of the issue'` (issue being the resource).
+- Use `"{x} of the {y}"` where possible. Example: `'Title of the issue'`.
+ Do not start descriptions with `The`.
+- Descriptions of `GraphQL::BOOLEAN_TYPE` fields should answer the question: "What does
+ this field do?". Example: `'Indicates project has a Git repository'`.
+- Always include the word `"timestamp"` when describing an argument or
+ field of type `Types::TimeType`. This lets the reader know that the
+ format of the property will be `Time`, rather than just `Date`.
+- No `.` at end of strings.
+
+Example:
+
+```ruby
+field :id, GraphQL::ID_TYPE, description: 'ID of the Issue'
+field :confidential, GraphQL::BOOLEAN_TYPE, description: 'Indicates the issue is confidential'
+field :closed_at, Types::TimeType, description: 'Timestamp of when the issue was closed'
+```
+
## Authorization
Authorizations can be applied to both types and fields using the same
@@ -350,7 +395,10 @@ To find objects to display in a field, we can add resolvers to
`app/graphql/resolvers`.
Arguments can be defined within the resolver, those arguments will be
-made available to the fields using the resolver.
+made available to the fields using the resolver. When exposing a model
+that had an internal ID (`iid`), prefer using that in combination with
+the namespace path as arguments in a resolver over a database
+ID. Othewise use a [globally unique ID](#exposing-global-ids).
We already have a `FullPathLoader` that can be included in other
resolvers to quickly find Projects and Namespaces which will have a
@@ -365,6 +413,10 @@ actions. In the same way a GET-request should not modify data, we
cannot modify data in a regular GraphQL-query. We can however in a
mutation.
+To find objects for a mutation, arguments need to be specified. As with
+[resolvers](#resolvers), prefer using internal ID or, if needed, a
+global ID rather than the database ID.
+
### Fields
In the most common situations, a mutation would return 2 fields:
@@ -496,6 +548,32 @@ found, we should raise a
`Gitlab::Graphql::Errors::ResourceNotAvailable` error. Which will be
correctly rendered to the clients.
+## Gitlab's custom scalars
+
+### `Types::TimeType`
+
+[`Types::TimeType`](https://gitlab.com/gitlab-org/gitlab/blob/master/app%2Fgraphql%2Ftypes%2Ftime_type.rb)
+must be used as the type for all fields and arguments that deal with Ruby
+`Time` and `DateTime` objects.
+
+The type is
+[a custom scalar](https://github.com/rmosolgo/graphql-ruby/blob/master/guides/type_definitions/scalars.md#custom-scalars)
+that:
+
+- Converts Ruby's `Time` and `DateTime` objects into standardized
+ ISO-8601 formatted strings, when used as the type for our GraphQL fields.
+- Converts ISO-8601 formatted time strings into Ruby `Time` objects,
+ when used as the type for our GraphQL arguments.
+
+This allows our GraphQL API to have a standardized way that it presents time
+and handles time inputs.
+
+Example:
+
+```ruby
+field :created_at, Types::TimeType, null: false, description: 'Timestamp of when the issue was created'
+```
+
## Testing
_full stack_ tests for a graphql query or mutation live in
@@ -540,7 +618,7 @@ it 'returns a successful response' do
end
```
-## Documentation
+## Documentation and Schema
-For information on generating GraphQL documentation, see
-[Rake tasks related to GraphQL](rake_tasks.md#update-graphql-documentation).
+For information on generating GraphQL documentation and schema files, see
+[Rake tasks related to GraphQL](rake_tasks.md#update-graphql-documentation-and-schema-definitions).
diff --git a/doc/development/architecture.md b/doc/development/architecture.md
index ccedb96d27d..b579f812d99 100644
--- a/doc/development/architecture.md
+++ b/doc/development/architecture.md
@@ -59,10 +59,10 @@ graph TB
Unicorn --> Gitaly
Sidekiq --> Redis
Sidekiq --> PgBouncer
+ Sidekiq --> Gitaly
GitLabWorkhorse[GitLab Workhorse] --> Unicorn
GitLabWorkhorse --> Redis
GitLabWorkhorse --> Gitaly
- Gitaly --> Redis
NGINX --> GitLabWorkhorse
NGINX -- TCP 8090 --> GitLabPages[GitLab Pages]
NGINX --> Grafana[Grafana]
diff --git a/doc/development/changelog.md b/doc/development/changelog.md
index 8ded3f393ee..af2c540cca5 100644
--- a/doc/development/changelog.md
+++ b/doc/development/changelog.md
@@ -41,7 +41,10 @@ the `author` field. GitLab team members **should not**.
a changelog entry regardless of these guidelines if the contributor wants one.
Example: "Fixed a typo on the search results page."
- Any docs-only changes **should not** have a changelog entry.
-- Any change behind a feature flag **should not** have a changelog entry. The entry should be added [in the merge request removing the feature flags](feature_flags/development.md).
+- Any change behind a feature flag **should not** have a changelog entry. The
+ entry should be added [in the merge request removing the feature flags](feature_flags/development.md).
+ If the change includes a database migration, there should be a changelog entry
+ for the migration change.
- A fix for a regression introduced and then fixed in the same release (i.e.,
fixing a bug introduced during a monthly release candidate) **should not**
have a changelog entry.
diff --git a/doc/development/chatops_on_gitlabcom.md b/doc/development/chatops_on_gitlabcom.md
index 8a313a120f1..456dd1d4b4b 100644
--- a/doc/development/chatops_on_gitlabcom.md
+++ b/doc/development/chatops_on_gitlabcom.md
@@ -14,7 +14,7 @@ tasks such as:
To request access to Chatops on GitLab.com:
1. Log into <https://ops.gitlab.net/users/sign_in> **using the same username** as for GitLab.com (you may have to rename it).
-1. Ask [an owner/maintainer in the `chatops` project](https://gitlab.com/gitlab-com/chatops/-/project_members?search=&sort=access_level_desc) to add you by running `/chatops run member add <username> gitlab-com/chatops --ops`.
+1. Ask [a project member in the `chatops` project](https://ops.gitlab.net/gitlab-com/chatops/-/project_members) to add you by running `/chatops run member add <username> gitlab-com/chatops --ops`.
## See also
diff --git a/doc/development/code_review.md b/doc/development/code_review.md
index 421b70bd2db..77c57bb332d 100644
--- a/doc/development/code_review.md
+++ b/doc/development/code_review.md
@@ -170,8 +170,8 @@ Maintainers should check before merging if the merge request is approved by the
required approvers.
Maintainers must check before merging if the merge request is introducing new
-vulnerabilities, by inspecting the list in the Merge Request [Security
-Widget](../user/project/merge_requests/index.md#security-reports-ultimate).
+vulnerabilities, by inspecting the list in the Merge Request
+[Security Widget](../user/application_security/index.md).
When in doubt, a [Security Engineer](https://about.gitlab.com/company/team/) can be involved. The list of detected
vulnerabilities must be either empty or containing:
@@ -368,7 +368,7 @@ Enterprise Edition instance. This has some implications:
- [Background migrations](background_migrations.md) run in Sidekiq, and
should only be done for migrations that would take an extreme amount of
time at GitLab.com scale.
-1. **Sidekiq workers** [cannot change in a backwards-incompatible way](sidekiq_style_guide.md#removing-or-renaming-queues):
+1. **Sidekiq workers** [cannot change in a backwards-incompatible way](sidekiq_style_guide.md#sidekiq-compatibility-across-updates):
1. Sidekiq queues are not drained before a deploy happens, so there will be
workers in the queue from the previous version of GitLab.
1. If you need to change a method signature, try to do so across two releases,
diff --git a/doc/development/contributing/index.md b/doc/development/contributing/index.md
index 92dd040a2bd..481a18aac3d 100644
--- a/doc/development/contributing/index.md
+++ b/doc/development/contributing/index.md
@@ -118,6 +118,10 @@ This [documentation](merge_request_workflow.md) outlines the current merge reque
This [documentation](style_guides.md) outlines the current style guidelines.
+## Getting an Enterprise Edition License
+
+If you need a license for contributing to an EE-feature, please [follow these instructions](https://about.gitlab.com/handbook/marketing/community-relations/code-contributor-program/#for-contributors-to-the-gitlab-enterprise-edition-ee).
+
---
[Return to Development documentation](../README.md)
diff --git a/doc/development/contributing/issue_workflow.md b/doc/development/contributing/issue_workflow.md
index 349bb371835..f32400d44a2 100644
--- a/doc/development/contributing/issue_workflow.md
+++ b/doc/development/contributing/issue_workflow.md
@@ -268,7 +268,7 @@ Each issue scheduled for the current milestone should be labeled ~Deliverable
or ~"Stretch". Any open issue for a previous milestone should be labeled
~"Next Patch Release", or otherwise rescheduled to a different milestone.
-#### Priority labels
+### Priority labels
Priority labels help us define the time a ~bug fix should be completed. Priority determines how quickly the defect turnaround time must be.
If there are multiple defects, the priority decides which defect has to be fixed immediately versus later.
diff --git a/doc/development/contributing/merge_request_workflow.md b/doc/development/contributing/merge_request_workflow.md
index 86f17f4ecdb..510e90524ed 100644
--- a/doc/development/contributing/merge_request_workflow.md
+++ b/doc/development/contributing/merge_request_workflow.md
@@ -36,7 +36,7 @@ include a regression test are merged quickly, while new features without proper
tests might be slower to receive feedback. The workflow to make a merge
request is as follows:
-1. [Fork](../../workflow/forking_workflow.md#creating-a-fork) the project into
+1. [Fork](../../user/project/repository/forking_workflow.md) the project into
your personal namespace (or group) on GitLab.com.
1. Create a feature branch in your fork (don't work off `master`).
1. Write [tests](../rake_tasks.md#run-tests) and code.
@@ -69,7 +69,7 @@ request is as follows:
the issue(s) once the merge request is merged.
1. If you're allowed to (Core team members, for example), set a relevant milestone
and [labels](issue_workflow.md).
-1. If the MR changes the UI, it should include *Before* and *After* screenshots.
+1. If the MR changes the UI, you'll need approval from a Product Designer (UX), based on the appropriate [product category](https://about.gitlab.com/handbook/product/categories/). UI changes should use available components from the GitLab Design System, [Pajamas](https://design.gitlab.com/). The MR must include *Before* and *After* screenshots.
1. If the MR changes CSS classes, please include the list of affected pages, which
can be found by running `grep css-class ./app -R`.
1. Be prepared to answer questions and incorporate feedback into your MR with new
@@ -222,7 +222,7 @@ requirements.
on the CI server.
1. Regressions and bugs are covered with tests that reduce the risk of the issue happening
again.
-1. Performance/scalability implications have been considered, addressed, and tested.
+1. [Performance guidelines](../merge_request_performance_guidelines.md) have been followed.
1. [Documented](../documentation/index.md) in the `/doc` directory.
1. [Changelog entry added](../changelog.md), if necessary.
1. Reviewed by relevant (UX/FE/BE/tech writing) reviewers and all concerns are addressed.
diff --git a/doc/development/creating_enums.md b/doc/development/creating_enums.md
new file mode 100644
index 00000000000..64385a2ea79
--- /dev/null
+++ b/doc/development/creating_enums.md
@@ -0,0 +1,15 @@
+# Creating enums
+
+When creating a new enum, it should use the database type `SMALLINT`.
+The `SMALLINT` type size is 2 bytes, which is sufficient for an enum.
+This would help to save space in the database.
+
+To use this type, add `limit: 2` to the migration that creates the column.
+
+Example:
+
+```rb
+def change
+ add_column :ci_job_artifacts, :file_format, :integer, limit: 2
+end
+```
diff --git a/doc/development/database_debugging.md b/doc/development/database_debugging.md
index 9947f9c16c0..65a3e518585 100644
--- a/doc/development/database_debugging.md
+++ b/doc/development/database_debugging.md
@@ -19,7 +19,7 @@ If you just want to delete everything and start over with an empty DB (~1 minute
- `bundle exec rake db:reset RAILS_ENV=development`
-If you just want to delete everything and start over with dummy data (~40 minutes). This also does `db:reset` and runs DB-specific migrations:
+If you just want to delete everything and start over with dummy data (~4 minutes). This also does `db:reset` and runs DB-specific migrations:
- `bundle exec rake dev:setup RAILS_ENV=development`
diff --git a/doc/development/database_review.md b/doc/development/database_review.md
index 39236ab1910..f3c19002417 100644
--- a/doc/development/database_review.md
+++ b/doc/development/database_review.md
@@ -47,6 +47,13 @@ A database **reviewer**'s role is to:
reassign MR to the database **maintainer** suggested by Reviewer
Roulette.
+#### When there are no database maintainers available
+
+Currently we have a [critical shortage of database maintainers](https://gitlab.com/gitlab-org/gitlab/issues/29717). Until we are able to increase the number of database maintainers to support the volume of reviews, we have implemented this temporary solution. If the database **reviewer** cannot find an available database **maintainer** then:
+
+1. Assign the MR for a second review by a **database trainee maintainer** for further review.
+1. Once satisfied with the review process, and if the database **maintainer** is still not available, skip the database maintainer approval step and assign the merge request to a backend maintainer for final review and approval.
+
A database **maintainer**'s role is to:
- Perform the final database review on the MR.
diff --git a/doc/development/documentation/index.md b/doc/development/documentation/index.md
index fb0aa5130f8..7d575e9b0b1 100644
--- a/doc/development/documentation/index.md
+++ b/doc/development/documentation/index.md
@@ -16,7 +16,7 @@ In addition to this page, the following resources can help you craft and contrib
## Source files and rendered web locations
-Documentation for GitLab, GitLab Runner, Omnibus GitLab and Charts are published to <https://docs.gitlab.com>. Documentation for GitLab is also published within the application at `/help` on the domain of the GitLab instance.
+Documentation for GitLab, GitLab Runner, Omnibus GitLab and Charts is published to <https://docs.gitlab.com>. Documentation for GitLab is also published within the application at `/help` on the domain of the GitLab instance.
At `/help`, only help for your current edition and version is included. Help for other versions is available at <https://docs.gitlab.com/archives/>.
The source of the documentation exists within the codebase of each GitLab application in the following repository locations:
@@ -67,8 +67,6 @@ This document was moved to [another location](path/to/new_doc.md).
where `path/to/new_doc.md` is the relative path to the root directory `doc/`.
----
-
For example, if you move `doc/workflow/lfs/lfs_administration.md` to
`doc/administration/lfs.md`, then the steps would be:
diff --git a/doc/development/documentation/site_architecture/index.md b/doc/development/documentation/site_architecture/index.md
index f5a12e9c216..bf873995e54 100644
--- a/doc/development/documentation/site_architecture/index.md
+++ b/doc/development/documentation/site_architecture/index.md
@@ -4,14 +4,16 @@ description: "Learn how GitLab's documentation website is architectured."
# Documentation site architecture
-Learn how we build and architecture [`gitlab-docs`](https://gitlab.com/gitlab-org/gitlab-docs)
-and deploy it to <https://docs.gitlab.com>.
+The [`gitlab-docs`](https://gitlab.com/gitlab-org/gitlab-docs) project hosts
+the repository which is used to generate the GitLab documentation website and
+is deployed to <https://docs.gitlab.com>. It uses the [Nanoc](http://nanoc.ws)
+static site generator.
-## Repository
+## Architecture
While the source of the documentation content is stored in GitLab's respective product
-repositories, the source that is used to build the documentation site _from that content_
-is located at <https://gitlab.com/gitlab-org/gitlab-docs>.
+repositories, the source that is used to build the documentation
+site _from that content_ is located at <https://gitlab.com/gitlab-org/gitlab-docs>.
The following diagram illustrates the relationship between the repositories
from where content is sourced, the `gitlab-docs` project, and the published output.
@@ -43,8 +45,23 @@ from where content is sourced, the `gitlab-docs` project, and the published outp
G --> L
```
-See the [README there](https://gitlab.com/gitlab-org/gitlab-docs/blob/master/README.md)
-for detailed information.
+You will not find any GitLab docs content in the `gitlab-docs` repository.
+All documentation files are hosted in the respective repository of each
+product, and all together are pulled to generate the docs website:
+
+- [GitLab](https://gitlab.com/gitlab-org/gitlab/tree/master/doc)
+- [Omnibus GitLab](https://gitlab.com/gitlab-org/omnibus-gitlab/tree/master/doc)
+- [GitLab Runner](https://gitlab.com/gitlab-org/gitlab-runner/tree/master/docs)
+- [GitLab Chart](https://gitlab.com/charts/gitlab/tree/master/doc)
+
+NOTE: **Note:**
+In September 2019, we [moved towards a single codebase](https://gitlab.com/gitlab-org/gitlab-ee/issues/2952),
+as such the docs for CE and EE are now identical. For historical reasons and
+in order not to break any existing links throughout the internet, we still
+maintain the CE docs (`https://docs.gitlab.com/ce/`), although it is hidden
+from the website, and is now a symlink to the EE docs. When
+[Pages supports redirects](https://gitlab.com/gitlab-org/gitlab-pages/issues/24),
+we will be able to remove this completely.
## Assets
@@ -73,28 +90,112 @@ Read through [the global navigation documentation](global_nav.md) to understand:
- How the global navigation is built.
- How to add new navigation items.
-## Deployment
+<!--
+## Helpers
-The docs site is deployed to production with GitLab Pages, and previewed in
-merge requests with Review Apps.
+TBA
+-->
-The deployment aspects will be soon transferred from the [original document](https://gitlab.com/gitlab-org/gitlab-docs/blob/master/README.md)
-to this page.
+## Using YAML data files
-<!--
-## Repositories
+The easiest way to achieve something similar to
+[Jekyll's data files](https://jekyllrb.com/docs/datafiles/) in Nanoc is by
+using the [`@items`](https://nanoc.ws/doc/reference/variables/#items-and-layouts)
+variable.
-TBA
+The data file must be placed inside the `content/` directory and then it can
+be referenced in an ERB template.
-## Search engine
+Suppose we have the `content/_data/versions.yaml` file with the content:
-TBA
+```yaml
+versions:
+- 10.6
+- 10.5
+- 10.4
+```
-## Versions
+We can then loop over the `versions` array with something like:
-TBA
+```erb
+<% @items['/_data/versions.yaml'][:versions].each do | version | %>
-## Helpers
+<h3><%= version %></h3>
-TBA
--->
+<% end &>
+```
+
+Note that the data file must have the `yaml` extension (not `yml`) and that
+we reference the array with a symbol (`:versions`).
+
+## Bumping versions of CSS and Javascript
+
+Whenever the custom CSS and Javascript files under `content/assets/` change,
+make sure to bump their version in the frontmatter. This method guarantees that
+your changes will take effect by clearing the cache of previous files.
+
+Always use Nanoc's way of including those files, do not hardcode them in the
+layouts. For example use:
+
+```erb
+<script async type="application/javascript" src="<%= @items['/assets/javascripts/badges.*'].path %>"></script>
+
+<link rel="stylesheet" href="<%= @items['/assets/stylesheets/toc.*'].path %>">
+```
+
+The links pointing to the files should be similar to:
+
+```erb
+<%= @items['/path/to/assets/file.*'].path %>
+```
+
+Nanoc will then build and render those links correctly according with what's
+defined in [`Rules`](https://gitlab.com/gitlab-org/gitlab-docs/blob/master/Rules).
+
+## Linking to source files
+
+A helper called [`edit_on_gitlab`](https://gitlab.com/gitlab-org/gitlab-docs/blob/master/lib/helpers/edit_on_gitlab.rb) can be used
+to link to a page's source file. We can link to both the simple editor and the
+web IDE. Here's how you can use it in a Nanoc layout:
+
+- Default editor: `<a href="<%= edit_on_gitlab(@item, editor: :simple) %>">Simple editor</a>`
+- Web IDE: `<a href="<%= edit_on_gitlab(@item, editor: :webide) %>">Web IDE</a>`
+
+If you don't specify `editor:`, the simple one is used by default.
+
+## Algolia search engine
+
+The docs site uses [Algolia docsearch](https://community.algolia.com/docsearch/)
+for its search function. This is how it works:
+
+1. GitLab is a member of the [docsearch program](https://community.algolia.com/docsearch/#join-docsearch-program),
+ which is the free tier of [Algolia](https://www.algolia.com/).
+1. Algolia hosts a [doscsearch config](https://github.com/algolia/docsearch-configs/blob/master/configs/gitlab.json)
+ for the GitLab docs site, and we've worked together to refine it.
+1. That [config](https://community.algolia.com/docsearch/config-file.html) is
+ parsed by their [crawler](https://community.algolia.com/docsearch/crawler-overview.html)
+ every 24h and [stores](https://community.algolia.com/docsearch/inside-the-engine.html)
+ the [docsearch index](https://community.algolia.com/docsearch/how-do-we-build-an-index.html)
+ on [Algolia's servers](https://community.algolia.com/docsearch/faq.html#where-is-my-data-hosted%3F).
+1. On the docs side, we use a [docsearch layout](https://gitlab.com/gitlab-org/gitlab-docs/blob/master/layouts/docsearch.html) which
+ is present on pretty much every page except <https://docs.gitlab.com/search/>,
+ which uses its [own layout](https://gitlab.com/gitlab-org/gitlab-docs/blob/master/layouts/instantsearch.html). In those layouts,
+ there's a javascript snippet which initiates docsearch by using an API key
+ and an index name (`gitlab`) that are needed for Algolia to show the results.
+
+NOTE: **For GitLab employees:**
+The credentials to access the Algolia dashboard are stored in 1Password. If you
+want to receive weekly reports of the search usage, search the Google doc with
+title "Email, Slack, and GitLab Groups and Aliases", search for `docsearch`,
+and add a comment with your email to be added to the alias that gets the weekly
+reports.
+
+## Monthly release process (versions)
+
+The docs website supports versions and each month we add the latest one to the list.
+For more information, read about the [monthly release process](release_process.md).
+
+## Review Apps for documentation merge requests
+
+If you are contributing to GitLab docs read how to [create a Review App with each
+merge request](../index.md#previewing-the-changes-live).
diff --git a/doc/development/documentation/site_architecture/release_process.md b/doc/development/documentation/site_architecture/release_process.md
new file mode 100644
index 00000000000..6f723531f4c
--- /dev/null
+++ b/doc/development/documentation/site_architecture/release_process.md
@@ -0,0 +1,241 @@
+# GitLab Docs monthly release process
+
+The [`dockerfiles` directory](https://gitlab.com/gitlab-org/gitlab-docs/blob/master/dockerfiles/)
+contains all needed Dockerfiles to build and deploy the versioned website. It
+is heavily inspired by Docker's
+[Dockerfile](https://github.com/docker/docker.github.io/blob/06ed03db13895bfe867761b6fc2ad40acf6026dd/Dockerfile).
+
+The following Dockerfiles are used.
+
+| Dockerfile | Docker image | Description |
+| ---------- | ------------ | ----------- |
+| [`Dockerfile.bootstrap`](https://gitlab.com/gitlab-org/gitlab-docs/blob/master/dockerfiles/Dockerfile.bootstrap) | `gitlab-docs:bootstrap` | Contains all the dependencies that are needed to build the website. If the gems are updated and `Gemfile{,.lock}` changes, the image must be rebuilt. |
+| [`Dockerfile.builder.onbuild`](https://gitlab.com/gitlab-org/gitlab-docs/blob/master/dockerfiles/Dockerfile.builder.onbuild) | `gitlab-docs:builder-onbuild` | Base image to build the docs website. It uses `ONBUILD` to perform all steps and depends on `gitlab-docs:bootstrap`. |
+| [`Dockerfile.nginx.onbuild`](https://gitlab.com/gitlab-org/gitlab-docs/blob/master/dockerfiles/Dockerfile.nginx.onbuild) | `gitlab-docs:nginx-onbuild` | Base image to use for building documentation archives. It uses `ONBUILD` to perform all required steps to copy the archive, and relies upon its parent `Dockerfile.builder.onbuild` that is invoked when building single documentation achives (see the `Dockerfile` of each branch. |
+| [`Dockerfile.archives`](https://gitlab.com/gitlab-org/gitlab-docs/blob/master/dockerfiles/Dockerfile.archives) | `gitlab-docs:archives` | Contains all the versions of the website in one archive. It copies all generated HTML files from every version in one location. |
+
+## How to build the images
+
+Although build images are built automatically via GitLab CI/CD, you can build
+and tag all tooling images locally:
+
+1. Make sure you have [Docker installed](https://docs.docker.com/install/).
+1. Make sure you're on the `dockerfiles/` directory of the `gitlab-docs` repo.
+1. Build the images:
+
+ ```sh
+ docker build -t registry.gitlab.com/gitlab-org/gitlab-docs:bootstrap -f Dockerfile.bootstrap ../
+ docker build -t registry.gitlab.com/gitlab-org/gitlab-docs:builder-onbuild -f Dockerfile.builder.onbuild ../
+ docker build -t registry.gitlab.com/gitlab-org/gitlab-docs:nginx-onbuild -f Dockerfile.nginx.onbuild ../
+ ```
+
+For each image, there's a manual job under the `images` stage in
+[`.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab-docs/blob/master/.gitlab-ci.yml) which can be invoked at will.
+
+## Monthly release process
+
+When a new GitLab version is released on the 22nd, we need to create the respective
+single Docker image, and update some files so that the dropdown works correctly.
+
+### 1. Add the chart version
+
+Since the charts use a different version number than all the other GitLab
+products, we need to add a
+[version mapping](https://docs.gitlab.com/charts/installation/version_mappings.html):
+
+1. Check that there is a [stable branch created](https://gitlab.com/gitlab-org/charts/gitlab/-/branches)
+ for the new chart version. If you're unsure or can't find it, drop a line in
+ the `#g_delivery` channel.
+1. Make sure you're on the root path of the `gitlab-docs` repo.
+1. Open `content/_data/chart_versions.yaml` and add the new stable branch version using the
+ version mapping. Note that only the `major.minor` version is needed.
+1. Create a new merge request and merge it.
+
+TIP: **Tip:**
+It can be handy to create the future mappings since they are pretty much known.
+In that case, when a new GitLab version is released, you don't have to repeat
+this first step.
+
+### 2. Create an image for a single version
+
+The single docs version must be created before the release merge request, but
+this needs to happen when the stable branches for all products have been created.
+
+1. Make sure you're on the root path of the `gitlab-docs` repo.
+1. Run the raketask to create the single version:
+
+ ```sh
+ ./bin/rake "release:single[12.0]"
+ ```
+
+ A new `Dockerfile.12.0` should have been created and committed to a new branch.
+
+1. Push the newly created branch, but **don't create a merge request**.
+ Once you push, the `image:docker-singe` job will create a new Docker image
+ tagged with the branch name you created in the first step. In the end, the
+ image will be uploaded in the [Container Registry](https://gitlab.com/gitlab-org/gitlab-docs/container_registry)
+ and it will be listed under the
+ [`registry` environment folder](https://gitlab.com/gitlab-org/gitlab-docs/environments/folders/registry).
+
+Optionally, you can test locally by building the image and running it:
+
+```sh
+docker build -t docs:12.0 -f Dockerfile.12.0 .
+docker run -it --rm -p 4000:4000 docs:12.0
+```
+
+Visit `http://localhost:4000/12.0/` to see if everything works correctly.
+
+### 3. Create the release merge request
+
+Now it's time to create the monthly release merge request that adds the new
+version and rotates the old one:
+
+1. Make sure you're on the root path of the `gitlab-docs` repo.
+1. Create a branch `release-X-Y`:
+
+ ```sh
+ git checkout -b release-12-0
+ ```
+
+1. **Rotate the online and offline versions:**
+
+ At any given time, there are 4 browsable online versions: one pulled from
+ the upstream master branches (docs for GitLab.com) and the three latest
+ stable versions.
+
+ Edit `content/_data/versions.yaml` and rotate the versions to reflect the
+ new changes:
+
+ - `online`: The 3 latest stable versions.
+ - `offline`: All the previous versions offered as an offline archive.
+
+1. **Add the new offline version in the 404 page redirect script:**
+
+ Since we're deprecating the oldest version each month, we need to redirect
+ those URLs in order not to create [404 entries](https://gitlab.com/gitlab-org/gitlab-docs/issues/221).
+ There's a temporary hack for now:
+
+ 1. Edit `content/404.html`, making sure all offline versions under
+ `content/_data/versions.yaml` are in the Javascript snippet at the end of
+ the document.
+
+1. **Update the `:latest` and `:archives` Docker images:**
+
+ The following two Dockerfiles need to be updated:
+
+ 1. `dockerfiles/Dockerfile.archives` - Add the latest version at the top of
+ the list.
+ 1. `Dockerfile.master` - Rotate the versions (oldest gets removed and latest
+ is added at the top of the list).
+
+1. In the end, there should be four files in total that have changed.
+ Commit and push to create the merge request using the "Release" template:
+
+ ```sh
+ git add content/ Dockerfile.master dockerfiles/Dockerfile.archives
+ git commit -m "Release 12.0"
+ git push origin release-12-0
+ ```
+
+### 4. Update the dropdown for all online versions
+
+The versions dropdown is in a way "hardcoded". When the site is built, it looks
+at the contents of `content/_data/versions.yaml` and based on that, the dropdown
+is populated. So, older branches will have different content, which means the
+dropdown will be one or more releases behind. Remember that the new changes of
+the dropdown are included in the unmerged `release-X-Y` branch.
+
+The content of `content/_data/versions.yaml` needs to change for all online
+versions:
+
+1. Before creating the merge request, [disable the scheduled pipeline](https://gitlab.com/gitlab-org/gitlab-docs/pipeline_schedules/228/edit)
+ by unchecking the "Active" option. Since all steps must run in sequence, we need
+ to do this to avoid race conditions in the event some previous versions are
+ updated before the release merge request is merged.
+1. Run the raketask that will create all the respective merge requests needed to
+ update the dropdowns and will be set to automatically be merged when their
+ pipelines succeed. The `release-X-Y` branch needs to be present locally,
+ otherwise the raketask will fail:
+
+ ```sh
+ ./bin/rake release:dropdowns
+ ```
+
+Once all are merged, proceed to the following and final step.
+
+TIP: **Tip:**
+In case a pipeline fails, see [troubleshooting](#troubleshooting).
+
+### 5. Merge the release merge request
+
+The dropdown merge requests should have now been merged into their respective
+version (stable branch), which will trigger another pipeline. At this point,
+you need to only babysit the pipelines and make sure they don't fail:
+
+1. Check the [pipelines page](https://gitlab.com/gitlab-org/gitlab-docs/pipelines)
+ and make sure all stable branches have green pipelines.
+1. After all the pipelines of the online versions succeed, merge the release merge request.
+1. Finally, re-activate the [scheduled pipeline](https://gitlab.com/gitlab-org/gitlab-docs/pipeline_schedules/228/edit),
+ save it, and hit the play button to get it started.
+
+Once the scheduled pipeline succeeds, the docs site will be deployed with all
+new versions online.
+
+## Update an old Docker image with new upstream docs content
+
+If there are any changes to any of the stable branches of the products that are
+not included in the single Docker image, just
+[rerun the pipeline](https://gitlab.com/gitlab-org/gitlab-docs/pipelines/new)
+for the version in question.
+
+## Porting new website changes to old versions
+
+CAUTION: **Warning:**
+Porting changes to older branches can have unintended effects as we're constantly
+changing the backend of the website. Use only when you know what you're doing
+and make sure to test locally.
+
+The website will keep changing and being improved. In order to consolidate
+those changes to the stable branches, we'd need to pick certain changes
+from time to time.
+
+If this is not possible or there are many changes, merge master into them:
+
+```sh
+git branch 12.0
+git fetch origin master
+git merge origin/master
+```
+
+## Troubleshooting
+
+Releasing a new version is a long process that involves many moving parts.
+
+### `test_internal_links_and_anchors` failing on dropdown merge requests
+
+When [updating the dropdown for the stable versions](#4-update-the-dropdown-for-all-online-versions),
+there may be cases where some links might fail. The process of how the
+dropdown MRs are created have a caveat, and that is that the tests run by
+pulling the master branches of all products, instead of the respective stable
+ones.
+
+In a real world scenario, the [Update 12.2 dropdown to match that of 12.4](https://gitlab.com/gitlab-org/gitlab-docs/merge_requests/604)
+merge request failed because of the [`test_internal_links_and_anchors` test](https://gitlab.com/gitlab-org/gitlab-docs/-/jobs/328042431).
+
+This happened because there has been a rename of a product (`gitlab-monitor` to `gitlab-exporter`)
+and the old name was still referenced in the 12.2 docs. If the respective stable
+branches for 12.2 were used, this wouldn't have failed, but as we can see from
+the [`compile_dev` job](https://gitlab.com/gitlab-org/gitlab-docs/-/jobs/328042427),
+the `master` branches were pulled.
+
+To fix this, you need to [re-run the pipeline](https://gitlab.com/gitlab-org/gitlab-docs/pipelines/new)
+for the `update-12-2-for-release-12-4` branch, by including the following environment variables:
+
+- `BRANCH_CE` set to `12-2-stable`
+- `BRANCH_EE` set to `12-2-stable-ee`
+- `BRANCH_OMNIBUS` set to `12-2-stable`
+- `BRANCH_RUNNER` set to `12-2-stable`
+- `BRANCH_CHARTS` set to `2-2-stable`
+
+This should make the MR pass.
diff --git a/doc/development/documentation/styleguide.md b/doc/development/documentation/styleguide.md
index b6ec7a858fa..e6d666473c3 100644
--- a/doc/development/documentation/styleguide.md
+++ b/doc/development/documentation/styleguide.md
@@ -604,9 +604,6 @@ Inside the document:
- Always use a proper description for what the image is about. That way, when a
browser fails to show the image, this text will be used as an alternative
description.
-- If there are consecutive images with little text between them, always add
- three dashes (`---`) between the image and the text to create a horizontal
- line for better clarity.
- If a heading is placed right after an image, always add three dashes (`---`)
between the image and the heading.
@@ -1182,12 +1179,12 @@ Rendered example:
- Prefer to use examples using the personal access token and don't pass data of
username and password.
-| Methods | Description |
-|:-------------------------------------------|:------------------------------------------------------|
-| `-H "PRIVATE-TOKEN: <your_access_token>"` | Use this method as is, whenever authentication needed |
-| `-X POST` | Use this method when creating new objects |
-| `-X PUT` | Use this method when updating existing objects |
-| `-X DELETE` | Use this method when removing existing objects |
+| Methods | Description |
+|:------------------------------------------- |:------------------------------------------------------|
+| `--header "PRIVATE-TOKEN: <your_access_token>"` | Use this method as is, whenever authentication needed |
+| `--request POST` | Use this method when creating new objects |
+| `--request PUT` | Use this method when updating existing objects |
+| `--request DELETE` | Use this method when removing existing objects |
### cURL Examples
@@ -1209,9 +1206,9 @@ Create a new project under the authenticated user's namespace:
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects?name=foo"
```
-#### Post data using cURL's --data
+#### Post data using cURL's `--data`
-Instead of using `-X POST` and appending the parameters to the URI, you can use
+Instead of using `--request POST` and appending the parameters to the URI, you can use
cURL's `--data` option. The example below will create a new project `foo` under
the authenticated user's namespace.
diff --git a/doc/development/documentation/workflow.md b/doc/development/documentation/workflow.md
index 24399391b1a..c373b976453 100644
--- a/doc/development/documentation/workflow.md
+++ b/doc/development/documentation/workflow.md
@@ -208,7 +208,7 @@ code reviewer have ensured:
Documentation [is required](../contributing/merge_request_workflow.html#definition-of-done) for a
milestone when:
-- A new or enhanced feature is shipped that impacts the user of administrator experience.
+- A new or enhanced feature is shipped that impacts the user or administrator experience.
- There are changes to the UI or API.
- A process, workflow, or previously documented feature is changed.
- A feature is deprecated or removed.
diff --git a/doc/development/ee_features.md b/doc/development/ee_features.md
index cc9df479492..d716325f332 100644
--- a/doc/development/ee_features.md
+++ b/doc/development/ee_features.md
@@ -245,47 +245,29 @@ end
#### Use self-descriptive wrapper methods
-When it's not possible/logical to modify the implementation of a
-method. Wrap it in a self-descriptive method and use that method.
+When it's not possible/logical to modify the implementation of a method, then
+wrap it in a self-descriptive method and use that method.
-For example, in CE only an `admin` is allowed to access all private
-projects/groups, but in EE also an `auditor` has full private
-access. It would be incorrect to override the implementation of
-`User#admin?`, so instead add a method `full_private_access?` to
-`app/models/users.rb`. The implementation in CE will be:
+For example, in GitLab-FOSS, the only user created by the system is `User.ghost`
+but in EE there are several types of bot-users that aren't really users. It would
+be incorrect to override the implementation of `User#ghost?`, so instead we add
+a method `#internal?` to `app/models/user.rb`. The implementation will be:
```ruby
-def full_private_access?
- admin?
+def internal?
+ ghost?
end
```
In EE, the implementation `ee/app/models/ee/users.rb` would be:
```ruby
-override :full_private_access?
-def full_private_access?
- super || auditor?
+override :internal?
+def internal?
+ super || bot?
end
```
-In `lib/gitlab/visibility_level.rb` this method is used to return the
-allowed visibility levels:
-
-```ruby
-def levels_for_user(user = nil)
- if user.full_private_access?
- [PRIVATE, INTERNAL, PUBLIC]
- elsif # ...
-end
-```
-
-See [CE MR][ce-mr-full-private] and [EE MR][ee-mr-full-private] for
-full implementation details.
-
-[ce-mr-full-private]: https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/12373
-[ee-mr-full-private]: https://gitlab.com/gitlab-org/gitlab/merge_requests/2199
-
### Code in `config/routes`
When we add `draw :admin` in `config/routes.rb`, the application will try to
diff --git a/doc/development/event_tracking/index.md b/doc/development/event_tracking/index.md
index efc61d13cb0..ac19053320d 100644
--- a/doc/development/event_tracking/index.md
+++ b/doc/development/event_tracking/index.md
@@ -68,7 +68,3 @@ Once enabled, tracking events can be inspected locally by either:
- Looking at the network panel of the browser's development tools
- Using the [Snowplow Chrome Extension](https://chrome.google.com/webstore/detail/snowplow-inspector/maplkdomeamdlngconidoefjpogkmljm).
-
-## Additional libraries
-
-Session tracking is handled by [Pendo](https://www.pendo.io/), which is a purely client library and is a relatively minor development concern but is worth including in this documentation.
diff --git a/doc/development/fe_guide/development_process.md b/doc/development/fe_guide/development_process.md
index 3724bf60757..5b02098f020 100644
--- a/doc/development/fe_guide/development_process.md
+++ b/doc/development/fe_guide/development_process.md
@@ -73,7 +73,7 @@ With the purpose of being [respectful of others' time](https://about.gitlab.com/
- Before assigning to a maintainer, assign to a reviewer.
- If you assigned a merge request, or pinged someone directly, keep in mind that we work in different timezones and asynchronously, so be patient. Unless the merge request is urgent (like fixing a broken master), please don't DM or reassign the merge request before waiting for a 24-hour window.
- If you have a question regarding your merge request/issue, make it on the merge request/issue. When we DM each other, we no longer have a SSOT and [no one else is able to contribute](https://about.gitlab.com/handbook/values/#public-by-default).
-- When you have a big WIP merge request with many changes, you're adivsed to get the review started before adding/removing significant code. Make sure it is assigned well before the release cut-off, as the reviewer(s)/maintainer(s) would always prioritize reviewing finished MRs before WIP ones.
+- When you have a big WIP merge request with many changes, you're advised to get the review started before adding/removing significant code. Make sure it is assigned well before the release cut-off, as the reviewer(s)/maintainer(s) would always prioritize reviewing finished MRs before WIP ones.
- Make sure to remove the WIP title before the last round of review.
### Share your work early
diff --git a/doc/development/fe_guide/graphql.md b/doc/development/fe_guide/graphql.md
index fe4f6d7bec8..894a613ec2d 100644
--- a/doc/development/fe_guide/graphql.md
+++ b/doc/development/fe_guide/graphql.md
@@ -19,6 +19,14 @@ To save duplicated clients getting created in different apps, we have a
[default client][default-client] that should be used. This setups the
Apollo client with the correct URL and also sets the CSRF headers.
+Default client accepts two parameters: `resolvers` and `config`.
+
+- `resolvers` parameter is created to accept an object of resolvers for [local state management](#local-state-with-apollo) queries and mutations
+- `config` parameter takes an object of configuration settings:
+ - `cacheConfig` field accepts an optional object of settings to [customize Apollo cache](https://github.com/apollographql/apollo-client/tree/master/packages/apollo-cache-inmemory#configuration)
+ - `baseUrl` allows us to pass a URL for GraphQL endpoint different from our main endpoint (i.e.`${gon.relative_url_root}/api/graphql`)
+ - `assumeImmutableResults` (set to `false` by default) - this setting, when set to `true`, will assume that every single operation on updating Apollo Cache is immutable. It also sets `freezeResults` to `true`, so any attempt on mutating Apollo Cache will throw a console warning in development environment. Please ensure you're following the immutability pattern on cache update operations before setting this option to `true`.
+
## GraphQL Queries
To save query compilation at runtime, webpack can directly import `.graphql`
diff --git a/doc/development/fe_guide/style_guide_js.md b/doc/development/fe_guide/style_guide_js.md
index 306b19c6e5d..43cd8180b6e 100644
--- a/doc/development/fe_guide/style_guide_js.md
+++ b/doc/development/fe_guide/style_guide_js.md
@@ -581,6 +581,18 @@ Please check this [rules][eslint-plugin-vue-rules] for more documentation.
<component />
```
+#### Component usage within templates
+
+1. Prefer a component's kebab-cased name over other styles when using it in a template
+
+ ```javascript
+ // bad
+ <MyComponent />
+
+ // good
+ <my-component />
+ ```
+
#### Ordering
1. Tag order in `.vue` file
diff --git a/doc/development/fe_guide/style_guide_scss.md b/doc/development/fe_guide/style_guide_scss.md
index 07c87920dab..54d41b42c77 100644
--- a/doc/development/fe_guide/style_guide_scss.md
+++ b/doc/development/fe_guide/style_guide_scss.md
@@ -27,7 +27,7 @@ New utility classes should be added to [`utilities.scss`](https://gitlab.com/git
| Font size | `.text-{size}` | `.text-2` |
- `{variant}` is one of 'primary', 'secondary', 'success', 'warning', 'error'
-- `{shade}` is on of the shades listed on [colors](https://design.gitlab.com/product-foundations/colors/)
+- `{shade}` is one of the shades listed on [colors](https://design.gitlab.com/product-foundations/colors/)
- `{size}` is a number from 1-6 from our [Type scale](https://design.gitlab.com/product-foundations/typography)
#### When should I create component classes?
diff --git a/doc/development/feature_flags/controls.md b/doc/development/feature_flags/controls.md
index f22c3bb1e37..cbbbe1cd5ea 100644
--- a/doc/development/feature_flags/controls.md
+++ b/doc/development/feature_flags/controls.md
@@ -29,6 +29,14 @@ Monitor stage, Health group.
For all production environment Chatops commands, use the `#production` channel.
+Regardless of the channel in which the Chatops command is ran, any feature flag change that affects GitLab.com will automatically be logged in an issue.
+
+The issue is created in the [gl-infra/feature-flag-log](https://gitlab.com/gitlab-com/gl-infra/feature-flag-log/issues?scope=all&utf8=%E2%9C%93&state=closed) project, and it will at minimum log the Slack handle of person enabling a feature flag, the time, and the name of the flag being changed.
+
+The issue is then also posted to GitLab Inc. internal [Grafana dashboard](https://dashboards.gitlab.net/) as an annotation marker to make the change even more visible.
+
+Changes to the issue format can be submitted in the [Chatops project](https://gitlab.com/gitlab-com/chatops).
+
## Rolling out changes
When the changes are deployed to the environments it is time to start
diff --git a/doc/development/feature_flags/development.md b/doc/development/feature_flags/development.md
index 929c9b1c71c..c410c7eae41 100644
--- a/doc/development/feature_flags/development.md
+++ b/doc/development/feature_flags/development.md
@@ -25,7 +25,8 @@ end
Features that are developed and are intended to be merged behind a feature flag
should not include a changelog entry. The entry should be added in the merge
-request removing the feature flags.
+request removing the feature flag. If the feature contains any DB migration it
+should include a changelog entry for DB changes.
In the rare case that you need the feature flag to be on automatically, use
`default_enabled: true` when checking:
@@ -51,20 +52,16 @@ isn't gated by a License or Plan.
[namespace-fa]: https://gitlab.com/gitlab-org/gitlab/blob/4cc1c62918aa4c31750cb21dfb1a6c3492d71080/ee/app/models/ee/namespace.rb#L71-85
[license-fa]: https://gitlab.com/gitlab-org/gitlab/blob/4cc1c62918aa4c31750cb21dfb1a6c3492d71080/ee/app/models/license.rb#L293-300
-An important side-effect of the implicit feature flags mentioned above is that
+**An important side-effect of the implicit feature flags mentioned above is that
unless the feature is explicitly disabled or limited to a percentage of users,
-the feature flag check will default to `true`.
+the feature flag check will default to `true`.**
As an example, if you were to ship the backend half of a feature behind a flag,
you'd want to explicitly disable that flag until the frontend half is also ready
-to be shipped. [You can do this via Chatops](controls.md):
-
-```
-/chatops run feature set some_feature 0
-```
-
-Note that you can do this at any time, even before the merge request using the
-flag has been merged!
+to be shipped. To make sure this feature is disabled for both GitLab.com and
+self-managed instances you'd need to explicitly call `Feature.enabled?` method
+before the `feature_available` method. This ensures the feature_flag is defaulting
+to `false`.
## Feature groups
diff --git a/doc/development/geo.md b/doc/development/geo.md
index 446d85fceed..5010e44e826 100644
--- a/doc/development/geo.md
+++ b/doc/development/geo.md
@@ -101,15 +101,16 @@ it's successful, we replace the main repo with the newly cloned one.
### Uploads replication
File uploads are also being replicated to the **secondary** node. To
-track the state of syncing, the `Geo::FileRegistry` model is used.
+track the state of syncing, the `Geo::UploadRegistry` model is used.
-#### File Registry
+#### Upload Registry
Similar to the [Project Registry](#project-registry), there is a
-`Geo::FileRegistry` model that tracks the synced uploads.
+`Geo::UploadRegistry` model that tracks the synced uploads.
-CI Job Artifacts are synced in a similar way as uploads or LFS
-objects, but they are tracked by `Geo::JobArtifactRegistry` model.
+CI Job Artifacts and LFS objects are synced in a similar way as uploads,
+but they are tracked by `Geo::JobArtifactRegistry`, and `Geo::LfsObjectRegistry`
+models respectively.
#### File Download Dispatch worker
@@ -490,6 +491,24 @@ When some write actions are not allowed because the node is a
The database itself will already be read-only in a replicated setup,
so we don't need to take any extra step for that.
+## Steps needed to replicate a new data type
+
+As GitLab evolves, we constantly need to add new resources to the Geo replication system.
+The implementation depends on resource specifics, but there are several things
+that need to be taken care of:
+
+- Event generation on the primary site. Whenever a new resource is changed/updated, we need to
+ create a task for the Log Cursor.
+- Event handling. The Log Cursor needs to have a handler for every event type generated by the primary site.
+- Dispatch worker (cron job). Make sure the backfill condition works well.
+- Sync worker.
+- Registry with all possible states.
+- Verification.
+- Cleaner. When sync settings are changed for the secondary site, some resources need to be cleaned up.
+- Geo Node Status. We need to provide API endpoints as well as some presentation in the GitLab Admin Area.
+- Health Check. If we can perform some pre-cheсks and make node unhealthy if something is wrong, we should do that.
+ The `rake gitlab:geo:check` command has to be updated too.
+
## History of communication channel
The communication channel has changed since first iteration, you can
diff --git a/doc/development/git_object_deduplication.md b/doc/development/git_object_deduplication.md
index e8af6346524..6d9eb90d482 100644
--- a/doc/development/git_object_deduplication.md
+++ b/doc/development/git_object_deduplication.md
@@ -1,6 +1,6 @@
# How Git object deduplication works in GitLab
-When a GitLab user [forks a project](../workflow/forking_workflow.md),
+When a GitLab user [forks a project](../user/project/repository/forking_workflow.md),
GitLab creates a new Project with an associated Git repository that is a
copy of the original project at the time of the fork. If a large project
gets forked often, this can lead to a quick increase in Git repository
diff --git a/doc/development/gitaly.md b/doc/development/gitaly.md
index 64f283f69d9..7d3c2b8fdf8 100644
--- a/doc/development/gitaly.md
+++ b/doc/development/gitaly.md
@@ -166,12 +166,11 @@ end
Normally, GitLab CE/EE tests use a local clone of Gitaly in
`tmp/tests/gitaly` pinned at the version specified in
-`GITALY_SERVER_VERSION`. The `GITALY_SERVER_VERSION` file supports
-`=my-branch` syntax to use a custom branch in <https://gitlab.com/gitlab-org/gitaly>. If
+`GITALY_SERVER_VERSION`. The `GITALY_SERVER_VERSION` file supports also
+branches and SHA to use a custom commit in <https://gitlab.com/gitlab-org/gitaly>. If
you want to run tests locally against a modified version of Gitaly you
can replace `tmp/tests/gitaly` with a symlink. This is much faster
-because the `=my-branch` syntax forces a Gitaly re-install each time
-you run `rspec`.
+because if will avoid a Gitaly re-install each time you run `rspec`.
```shell
rm -rf tmp/tests/gitaly
diff --git a/doc/development/gotchas.md b/doc/development/gotchas.md
index c7eed880554..da27ae9110b 100644
--- a/doc/development/gotchas.md
+++ b/doc/development/gotchas.md
@@ -168,3 +168,73 @@ in an initializer._
### Further reading
- Stack Overflow: [Why you should not write inline JavaScript](https://softwareengineering.stackexchange.com/questions/86589/why-should-i-avoid-inline-scripting)
+
+## Auto loading
+
+Rails auto-loading on `development` differs from the load policy in the `production` environment.
+In development mode, `config.eager_load` is set to `false`, which means classes
+are loaded as needed. With the classic Rails autoloader, it is known that this can lead to
+[Rails resolving the wrong class](https://guides.rubyonrails.org/v5.2/autoloading_and_reloading_constants.html#when-constants-aren-t-missed-relative-references)
+if the class name is ambiguous. This can be fixed by specifying the complete namespace to the class.
+
+### Error prone example
+
+```ruby
+# app/controllers/application_controller.rb
+class ApplicationController < ActionController::Base
+ ...
+end
+
+# app/controllers/projects/application_controller.rb
+class Projects::ApplicationController < ApplicationController
+ ...
+ private
+
+ def project
+ ...
+ end
+end
+
+# app/controllers/projects/submodule/some_controller.rb
+module Projects
+ module Submodule
+ class SomeController < ApplicationController
+ def index
+ @some_id = project.id
+ end
+ end
+ end
+end
+```
+
+In this case, if for any reason the top level `ApplicationController`
+is loaded but `Projects::ApplicationController` is not, `ApplicationController`
+would be resolved to `::ApplicationController` and then the `project` method will
+be undefined and we will get an error.
+
+#### Solution
+
+```ruby
+# app/controllers/projects/submodule/some_controller.rb
+module Projects
+ module Submodule
+ class SomeController < Projects::ApplicationController
+ def index
+ @some_id = project.id
+ end
+ end
+ end
+end
+```
+
+By specifying `Projects::`, we tell Rails exactly what class we are referring
+to and we would avoid the issue.
+
+NOTE: **Note:**
+This problem will disappear as soon as we upgrade to Rails 6 and use the Zeitwerk autoloader.
+
+### Further reading
+
+- Rails Guides: [Autoloading and Reloading Constants (Classic Mode)](https://guides.rubyonrails.org/autoloading_and_reloading_constants_classic_mode.html)
+- Ruby Constant lookup: [Everything you ever wanted to know about constant lookup in Ruby](http://cirw.in/blog/constant-lookup)
+- Rails 6 and Zeitwerk autoloader: [Understanding Zeitwerk in Rails 6](https://medium.com/cedarcode/understanding-zeitwerk-in-rails-6-f168a9f09a1f)
diff --git a/doc/development/i18n/externalization.md b/doc/development/i18n/externalization.md
index 2f067ede70f..c8960ac0f61 100644
--- a/doc/development/i18n/externalization.md
+++ b/doc/development/i18n/externalization.md
@@ -326,9 +326,8 @@ file in. Once the changes are on master, they will be picked up by
[Crowdin](https://translate.gitlab.com) and be presented for
translation.
-We don't need to check in any changes to the
-`locale/[language]/gitlab.po` files. Those will be updated in a [when
-translations from Crowdin are merged](merging_translations.md).
+We don't need to check in any changes to the `locale/[language]/gitlab.po` files.
+They are updated automatically when [translations from Crowdin are merged](merging_translations.md).
If there are merge conflicts in the `gitlab.pot` file, you can delete the file
and regenerate it using the same command.
diff --git a/doc/development/i18n/merging_translations.md b/doc/development/i18n/merging_translations.md
index f5953cc5f6c..c773b187cc1 100644
--- a/doc/development/i18n/merging_translations.md
+++ b/doc/development/i18n/merging_translations.md
@@ -1,13 +1,12 @@
# Merging translations from Crowdin
-Crowdin automatically syncs the `gitlab.pot` file presenting newly
-added translations to the community of translators.
+Crowdin automatically syncs the `gitlab.pot` file with the Crowdin service, presenting
+newly added externalized strings to the community of translators.
-At the same time, it creates a merge request to merge all newly added
-& approved translations. Find the [merge request created by
-`gitlab-crowdin-bot`](https://gitlab.com/gitlab-org/gitlab/merge_requests?scope=all&utf8=%E2%9C%93&state=opened&author_username=gitlab-crowdin-bot)
-to see new and merged merge requests. They are created in EE and need
-to be ported to CE manually.
+[GitLab Crowdin Bot](https://gitlab.com/gitlab-crowdin-bot) also creates merge requests
+to take newly approved translation submissions and merge them into the `locale/<language>/gitlab.po`
+files. Check the [merge requests created by `gitlab-crowdin-bot`](https://gitlab.com/gitlab-org/gitlab/merge_requests?scope=all&utf8=%E2%9C%93&state=opened&author_username=gitlab-crowdin-bot)
+to see new and merged merge requests.
## Validation
@@ -21,7 +20,7 @@ doesn't do. Create a new pipeline at `https://gitlab.com/gitlab-org/gitlab/pipel
If there are validation errors, the easiest solution is to disapprove
the offending string in Crowdin, leaving a comment with what is
required to fix the offense. There is an
-[issue](https://gitlab.com/gitlab-org/gitlab-foss/issues/49208)
+[issue](https://gitlab.com/gitlab-org/gitlab/issues/23256)
suggesting to automate this process. Disapproving will exclude the
invalid translation, the merge request will be updated within a few
minutes.
@@ -32,19 +31,16 @@ clicking `Pause sync` on the [Crowdin integration settings
page](https://translate.gitlab.com/project/gitlab-ee/settings#integration).
When all failures are resolved, the translations need to be double
-checked once more as discussed in [confidential issue](../../user/project/issues/confidential_issues.md) `https://gitlab.com/gitlab-org/gitlab-foss/issues/37850`.
+checked once more as discussed in [confidential issue](../../user/project/issues/confidential_issues.md) `https://gitlab.com/gitlab-org/gitlab/issues/19485`.
## Merging translations
When all translations are found good and pipelines pass the
-translations can be merged into the master branch. After that is done,
-create a new merge request cherry-picking the translations from EE to
-CE. When merging the translations, make sure to check the `Remove
-source branch` checkbox, so Crowdin recreates the `master-i18n` from
-master after the new translation was merged.
-
-We are discussing automating this entire process
-[here](https://gitlab.com/gitlab-org/gitlab-foss/issues/39309).
+translations can be merged into the master branch. When merging the translations,
+make sure to check the **Remove source branch** checkbox, so Crowdin recreates the
+`master-i18n` from master after the new translation was merged.
+
+We are discussing [automating this entire process](https://gitlab.com/gitlab-org/gitlab/issues/19896).
## Recreate the merge request
diff --git a/doc/development/i18n/translation.md b/doc/development/i18n/translation.md
index c1a6fd8983c..50a417e9996 100644
--- a/doc/development/i18n/translation.md
+++ b/doc/development/i18n/translation.md
@@ -83,7 +83,7 @@ Therefore "create a new user" would translate into "Benutzer(in) anlegen".
### Updating the glossary
To propose additions to the glossary please
-[open an issue](https://gitlab.com/gitlab-org/gitlab-foss/issues).
+[open an issue](https://gitlab.com/gitlab-org/gitlab/issues?scope=all&utf8=✓&state=all&label_name[]=Category%3AInternationalization).
## French Translation Guidelines
diff --git a/doc/development/kubernetes.md b/doc/development/kubernetes.md
index 82aa02ac75d..a0dd97f2a1c 100644
--- a/doc/development/kubernetes.md
+++ b/doc/development/kubernetes.md
@@ -74,6 +74,50 @@ We have some Webmock stubs in
[`KubernetesHelpers`](https://gitlab.com/gitlab-org/gitlab/blob/master/spec/support/helpers/kubernetes_helpers.rb)
which can help with mocking out calls to Kubernetes API in your tests.
+### Amazon EKS integration
+
+This section outlines the process for allowing a GitLab instance to create EKS clusters.
+
+The following prerequisites are required:
+
+A `Customer` AWS account. This is the account in which the
+EKS cluster will be created. The following resources must be present:
+
+- A provisioning role that has permissions to create the cluster
+ and associated resources. It must list the `GitLab` AWS account
+ as a trusted entity.
+- A VPC, management role, security group, and subnets for use by the cluster.
+
+A `GitLab` AWS account. This is the account which performs
+the provisioning actions. The following resources must be present:
+
+- A service account with permissions to assume the provisioning
+ role in the `Customer` account above.
+- Credentials for this service account configured in GitLab via
+ the `kubernetes` section of `gitlab.yml`.
+
+The process for creating a cluster is as follows:
+
+1. Using the `:provision_role_external_id`, GitLab assumes the role provided
+ by `:provision_role_arn` and stores a set of temporary credentials on the
+ provider record. By default these credentials are valid for one hour.
+1. A CloudFormation stack is created, based on the
+ [`AWS CloudFormation EKS template`](https://gitlab.com/gitlab-org/gitlab/blob/master/vendor/aws/cloudformation/eks_cluster.yaml).
+ This triggers creation of all resources required for an EKS cluster.
+1. GitLab polls the status of the stack until all resources are ready,
+ which takes somewhere between 10 and 15 minutes in most cases.
+1. When the stack is ready, GitLab stores the cluster details and generates
+ another set of temporary credentials, this time to allow connecting to
+ the cluster via Kubeclient. These credentials are valid for one minute.
+1. GitLab configures the worker nodes so that they are able to authenticate
+ to the cluster, and creates a service account for itself for future operations.
+1. Credentials that are no longer required are removed. This deletes the following
+ attributes:
+
+ - `access_key_id`
+ - `secret_access_key`
+ - `session_token`
+
## Security
### SSRF
@@ -123,3 +167,10 @@ they are written:
```bash
kubectl logs <pod_name> --follow -n gitlab-managed-apps
```
+
+## GitLab Managed Apps
+
+GitLab provides [GitLab Managed Apps](../user/clusters/applications.html), a one-click install for various applications which can be added directly to your configured cluster.
+
+**<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
+For an overview of how to add a new GitLab-mananged app, see [How to add GitLab-managed-apps to Kubernetes integration](https://youtu.be/mKm-jkranEk).**
diff --git a/doc/development/lfs.md b/doc/development/lfs.md
index cb4c2d8967b..9139bbaca0e 100644
--- a/doc/development/lfs.md
+++ b/doc/development/lfs.md
@@ -5,7 +5,7 @@
In April 2019, Francisco Javier López hosted a [Deep Dive] on GitLab's [Git LFS] implementation to share his domain specific knowledge with anyone who may work in this part of the code base in the future. You can find the [recording on YouTube], and the slides on [Google Slides] and in [PDF]. Everything covered in this deep dive was accurate as of GitLab 11.10, and while specific details may have changed since then, it should still serve as a good introduction.
[Deep Dive]: https://gitlab.com/gitlab-org/create-stage/issues/1
-[Git LFS]: ../workflow/lfs/manage_large_binaries_with_git_lfs.html
+[Git LFS]: ../administration/lfs/manage_large_binaries_with_git_lfs.md
[recording on YouTube]: https://www.youtube.com/watch?v=Yyxwcksr0Qc
[Google Slides]: https://docs.google.com/presentation/d/1E-aw6-z0rYd0346YhIWE7E9A65zISL9iIMAOq2zaw9E/edit
[PDF]: https://gitlab.com/gitlab-org/create-stage/uploads/07a89257a140db067bdfb484aecd35e1/Git_LFS_Deep_Dive__Create_.pdf
diff --git a/doc/development/merge_request_performance_guidelines.md b/doc/development/merge_request_performance_guidelines.md
index 4456e5e6d18..2e80e813a4b 100644
--- a/doc/development/merge_request_performance_guidelines.md
+++ b/doc/development/merge_request_performance_guidelines.md
@@ -1,7 +1,9 @@
# Merge Request Performance Guidelines
+Each new introduced merge request **should be performant by default**.
+
To ensure a merge request does not negatively impact performance of GitLab
-_every_ merge request **must** adhere to the guidelines outlined in this
+_every_ merge request **should** adhere to the guidelines outlined in this
document. There are no exceptions to this rule unless specifically discussed
with and agreed upon by backend maintainers and performance specialists.
@@ -12,6 +14,19 @@ the following guides:
- [Performance Guidelines](performance.md)
- [What requires downtime?](what_requires_downtime.md)
+## Definition
+
+The term `SHOULD` per the [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt) means:
+
+> This word, or the adjective "RECOMMENDED", mean that there
+> may exist valid reasons in particular circumstances to ignore a
+> particular item, but the full implications must be understood and
+> carefully weighed before choosing a different course.
+
+Ideally, each of these tradeoffs should be documented
+in the separate issues, labelled accordingly and linked
+to original issue and epic.
+
## Impact Analysis
**Summary:** think about the impact your merge request may have on performance
@@ -44,6 +59,64 @@ should ask one of the merge request reviewers to review your changes. You can
find a list of these reviewers at <https://about.gitlab.com/company/team/>. A reviewer
in turn can request a performance specialist to review the changes.
+## Think outside of the box
+
+Everyone has their own perception how the new feature is going to be used.
+Always consider how users might be using the feature instead. Usually,
+users test our features in a very unconventional way,
+like by brute forcing or abusing edge conditions that we have.
+
+## Data set
+
+The data set that will be processed by the merge request should be known
+and documented. The feature should clearly document what the expected
+data set is for this feature to process, and what problems it might cause.
+
+If you would think about the following example that puts
+a strong emphasis of data set being processed.
+The problem is simple: you want to filter a list of files from
+some git repository. Your feature requests a list of all files
+from the repository and perform search for the set of files.
+As an author you should in context of that problem consider
+the following:
+
+1. What repositories are going to be supported?
+1. How long it will take for big repositories like Linux kernel?
+1. Is there something that we can do differently to not process such a
+ big data set?
+1. Should we build some fail-safe mechanism to contain
+ computational complexity? Usually it is better to degrade
+ the service for a single user instead of all users.
+
+## Query plans and database structure
+
+The query plan can answer the questions whether we need additional
+indexes, or whether we perform expensive filtering (i.e. using sequential scans).
+
+Each query plan should be run against substantional size of data set.
+For example if you look for issues with specific conditions,
+you should consider validating the query against
+a small number (a few hundred) and a big number (100_000) of issues.
+See how the query will behave if the result will be a few
+and a few thousand.
+
+This is needed as we have users using GitLab for very big projects and
+in a very unconventional way. Even, if it seems that it is unlikely
+that such big data set will be used, it is still plausible that one
+of our customers will have the problem with the feature.
+
+Understanding ahead of time how it is going to behave at scale even if we accept it,
+is the desired outcome. We should always have a plan or understanding what it takes
+to optimise feature to the magnitude of higher usage patterns.
+
+Every database structure should be optimised and sometimes even over-described
+to be prepared to be easily extended. The hardest part after some point is
+data migration. Migrating millions of rows will always be troublesome and
+can have negative impact on application.
+
+To better understand how to get help with the query plan reviews
+read this section on [how to prepare the merge request for a database review](https://docs.gitlab.com/ee/development/database_review.html#how-to-prepare-the-merge-request-for-a-database-review).
+
## Query Counts
**Summary:** a merge request **should not** increase the number of executed SQL
@@ -172,3 +245,107 @@ Caching data per transaction can be done using
`Gitlab::SafeRequestStore` to avoid having to remember to check
`RequestStore.active?`). Caching data in Redis can be done using [Rails' caching
system](https://guides.rubyonrails.org/caching_with_rails.html).
+
+## Pagination
+
+Each feature that renders a list of items as a table needs to include pagination.
+
+The main styles of pagination are:
+
+1. Offset-based pagination: user goes to a specific page, like 1. User sees the next page number,
+ and the total number of pages. This style is well supported by all components of GitLab.
+1. Offset-based pagination, but without the count: user goes to a specific page, like 1.
+ User sees only the next page number, but does not see the total amount of pages.
+1. Next page using keyset-based pagination: user can only go to next page, as we do not know how many pages
+ are available.
+1. Infinite scrolling pagination: user scrolls the page and next items are loaded asynchronously. This is ideal,
+ as it has exact same benefits as the previous one.
+
+The ultimately scalable solution for pagination is to use Keyset-based pagination.
+However, we don't have support for that at GitLab at that moment. You
+can follow the progress looking at [API: Keyset Pagination
+](https://gitlab.com/groups/gitlab-org/-/epics/2039).
+
+Take into consideration the following when choosing a pagination strategy:
+
+1. It is very inefficient to calculate amount of objects that pass the filtering,
+ this operation usually can take seconds, and can time out,
+1. It is very inefficent to get entries for page at higher ordinals, like 1000.
+ The database has to sort and iterate all previous items, and this operation usually
+ can result in substantial load put on database.
+
+## Badge counters
+
+Counters should always be truncated. It means that we do not want to present
+the exact number over some threshold. The reason for that is for the cases where we want
+to calculate exact number of items, we effectively need to filter each of them for
+the purpose of knowing the exact number of items matching.
+
+From ~UX perspective it is often acceptable to see that you have over 1000+ pipelines,
+instead of that you have 40000+ pipelines, but at a tradeoff of loading page for 2s longer.
+
+An example of this pattern is the list of pipelines and jobs. We truncate numbers to `1000+`,
+but we show an accurate number of running pipelines, which is the most interesting information.
+
+There's a helper method that can be used for that purpose - `NumbersHelper.limited_counter_with_delimiter` -
+that accepts an upper limit of counting rows.
+
+In some cases it is desired that badge counters are loaded asynchronously.
+This can speed up the initial page load and give a better user experience overall.
+
+## Application/misuse limits
+
+Every new feature should have safe usage quotas introduced.
+The quota should be optimised to a level that we consider the feature to
+be performant and usable for the user, but **not limiting**.
+
+**We want the features to be fully usable for the users.**
+**However, we want to ensure that the feature will continue to perform well if used at its limit**
+**and it will not cause availability issues.**
+
+Consider that it is always better to start with some kind of limitation,
+instead of later introducing a breaking change that would result in some
+workflows breaking.
+
+The intent is to provide a safe usage pattern for the feature,
+as our implementation decisions are optimised for the given data set.
+Our feature limits should reflect the optimisations that we introduced.
+
+The intent of quotas could be different:
+
+1. We want to provide higher quotas for higher tiers of features:
+ we want to provide on GitLab.com more capabilities for different tiers,
+1. We want to prevent misuse of the feature: someone accidentially creates
+ 10000 deploy tokens, because of a broken API script,
+1. We want to prevent abuse of the feature: someone purposely creates
+ a 10000 pipelines to take advantage of the system.
+
+Examples:
+
+1. Pipeline Schedules: It is very unlikely that user will want to create
+ more than 50 schedules.
+ In such cases it is rather expected that this is either misuse
+ or abuse of the feature. Lack of the upper limit can result
+ in service degredation as the system will try to process all schedules
+ assigned the the project.
+
+1. GitLab CI includes: We started with the limit of maximum of 50 nested includes.
+ We understood that performance of the feature was acceptable at that level.
+ We received a request from the community that the limit is too small.
+ We had a time to understand the customer requirement, and implement an additional
+ fail-safe mechanism (time-based one) to increase the limit 100, and if needed increase it
+ further without negative impact on availability of the feature and GitLab.
+
+## Usage of feature flags
+
+Each feature that has performance critical elements or has a known performance deficiency
+needs to come with feature flag to disable it.
+
+The feature flag makes our team more happy, because they can monitor the system and
+quickly react without our users noticing the problem.
+
+Performance deficiencies should be addressed right away after we merge initial
+changes.
+
+Read more about when and how feature flags should be used in
+[Feature flags in GitLab development](https://docs.gitlab.com/ee/development/feature_flags/process.html#feature-flags-in-gitlab-development).
diff --git a/doc/development/migration_style_guide.md b/doc/development/migration_style_guide.md
index 20d705136b2..32c4313a1ed 100644
--- a/doc/development/migration_style_guide.md
+++ b/doc/development/migration_style_guide.md
@@ -211,7 +211,7 @@ class MyMigration < ActiveRecord::Migration[4.2]
end
def down
- remove_index :table, :column if index_exists?(:table, :column)
+ remove_concurrent_index :table, :column
end
end
```
diff --git a/doc/development/packages.md b/doc/development/packages.md
index 2474392db62..6d4a9ea9f41 100644
--- a/doc/development/packages.md
+++ b/doc/development/packages.md
@@ -4,12 +4,13 @@ This document will guide you through adding another [package management system](
See already supported package types in [Packages documentation](../administration/packages/index.md)
-Since GitLab packages' UI is pretty generic, it is possible to add new
+Since GitLab packages' UI is pretty generic, it is possible to add basic new
package system support by solely backend changes. This guide is superficial and does
not cover the way the code should be written. However, you can find a good example
by looking at existing merge requests with Maven and NPM support:
- [NPM registry support](https://gitlab.com/gitlab-org/gitlab/merge_requests/8673).
+- [Conan repository](https://gitlab.com/gitlab-org/gitlab/issues/8248).
- [Maven repository](https://gitlab.com/gitlab-org/gitlab/merge_requests/6607).
- [Instance level endpoint for Maven repository](https://gitlab.com/gitlab-org/gitlab/merge_requests/8757)
@@ -34,7 +35,7 @@ endpoints like:
- GET package file content.
- PUT upload package.
-Since the packages belong to a project, it's expected to have project-level endpoint
+Since the packages belong to a project, it's expected to have project-level endpoint (remote)
for uploading and downloading them. For example:
```
@@ -44,9 +45,48 @@ PUT https://gitlab.com/api/v4/projects/<your_project_id>/packages/npm/
Group-level and instance-level endpoints are good to have but are optional.
-NOTE: **Note:**
-To avoid name conflict for instance-level endpoints we use
-[the package naming convention](../user/packages/npm_registry/index.md#package-naming-convention)
+## Naming conventions
+
+To avoid name conflict for instance-level endpoints you will need to define a package naming convention
+that gives a way to identify the project that the package belongs to. This generally involves using the project
+id or full project path in the package name. See
+[Conan's naming convention](../user/packages/conan_repository/index.md#package-recipe-naming-convention) as an example.
+
+For group and project-level endpoints, naming can be less constrained, and it will be up to the group and project
+members to be certain that there is no conflict between two package names, however the system should prevent
+a user from reusing an existing name within a given scope.
+
+Otherwise, naming should follow the package manager's naming conventions and include a validation in the `package.md`
+model for that package type.
+
+## File uploads
+
+File uploads should be handled by GitLab workhorse using object accelerated uploads. What this means is that
+the workhorse proxy that checks all incoming requests to GitLab will intercept the upload request,
+upload the file, and forward a request to the main GitLab codebase only containing the metadata
+and file location rather than the file itself. An overview of this process can be found in the
+[development documentation](uploads.md#workhorse-object-storage-acceleration).
+
+In terms of code, this means a route will need to be added to the
+[gitlab-workhorse project](https://gitlab.com/gitlab-org/gitlab-workhorse) for each level of remote being added
+(instance, group, project). [This merge request](https://gitlab.com/gitlab-org/gitlab-workhorse/merge_requests/412/diffs)
+demonstrates adding an instance-level endpoint for Conan to workhorse. You can also see the Maven project level endpoint
+implemented in the same file.
+
+Once the route has been added, you will need to add an additional `/authorize` version of the upload endpoint to your API file.
+[Here is an example](https://gitlab.com/gitlab-org/gitlab/blob/398fef1ca26ae2b2c3dc89750f6b20455a1e5507/ee/lib/api/maven_packages.rb#L164)
+of the additional endpoint added for Maven. The `/authorize` endpoint verifies and authorizes the request from workhorse,
+then the normal upload endpoint is implemented below, consuming the metadata that workhorse provides in order to
+create the package record. Workhorse provides a variety of file metadata such as type, size, and different checksum formats.
+
+For testing purposes, you may want to [enable object storage](https://gitlab.com/gitlab-org/gitlab-development-kit/blob/master/doc/howto/object_storage.md)
+in your local development environment.
+
+## Services and finders
+
+Logic for performing tasks such as creating package or package file records or finding packages should not live
+within the API file, but should live in services and finders. Existing services and finders should be used or
+extended when possible to keep the common package logic grouped as much as possible.
## Configuration
@@ -56,7 +96,7 @@ to add anything there.
Packages can be configured to use object storage, therefore your code must support it.
-## Database
+## Database and handling metadata
The current database model allows you to store a name and a version for each package.
Every time you upload a new package, you can either create a new record of `Package`
@@ -65,4 +105,58 @@ information like the file `name`, `side`, `sha1`, etc.
If there is specific data necessary to be stored for only one package system support,
consider creating a separate metadata model. See `packages_maven_metadata` table
-and `Packages::MavenMetadatum` model as example for package specific data.
+and `Packages::MavenMetadatum` model as an example for package specific data, and `packages_conan_file_metadata` table
+and `Packages::ConanFileMetadatum` model as an example for package file specific data.
+
+If there is package specific behavior for a given package manager, add those methods to the metadata models and
+delegate from the package model.
+
+Note that the existing package UI only displays information within the `packages_packages` and `packages_package_files`
+tables. If the data stored in the metadata tables need to be displayed, a ~frontend change will be required.
+
+## Authorization
+
+There are project and group level permissions for `read_package`, `create_package`, and `destroy_package`. Each
+endpoint should
+[authorize the requesting user](https://gitlab.com/gitlab-org/gitlab/blob/398fef1ca26ae2b2c3dc89750f6b20455a1e5507/ee/lib/api/conan_packages.rb#L84)
+against the project or group before continuing.
+
+## Keep iterations small
+
+When implementing a new package manager, it is easy to end up creating one large merge request containing all of the
+necessary endpoints and services necessary to support basic usage. If this is the case, consider putting the
+API endpoints behind a [feature flag](feature_flags/development.md) and
+submitting each endpoint or behavior (download, upload, etc) in different merge requests to shorten the review
+process.
+
+### Potential MRs for any given package system
+
+#### MVC MRs
+
+These changes represent all that is needed to deliver a minimally usable package management system.
+
+1. Empty file structure (api file, base service for this package)
+1. Authentication system for 'logging in' to the package manager
+1. Identify metadata and create applicable tables
+1. Workhorse route for [object storage accelerated uploads](uploads.md#workhorse-object-storage-acceleration)
+1. Endpoints required for upload/publish
+1. Endpoints required for install/download
+1. Endpoints required for remove/delete
+
+#### Possible post-MVC MRs
+
+These updates are not essential to be able to publish and consume packages, but may be desired as the system is
+released for general use.
+
+1. Endpoints required for search
+1. Front end updates to display additional package information and metadata
+1. Limits on file sizes
+1. Tracking for metrics
+
+## Exceptions
+
+This documentation is just guidelines on how to implement a package manager to match the existing structure and logic
+already present within GitLab. While the structure is intended to be extendable and flexible enough to allow for
+any given package manager, if there is good reason to stray due to the constraints or needs of a given package
+manager, then it should be raised and discussed within the implementation issue or merge request to work towards
+the most efficient outcome.
diff --git a/doc/development/pipelines.md b/doc/development/pipelines.md
index 5954de03db4..764bd68000d 100644
--- a/doc/development/pipelines.md
+++ b/doc/development/pipelines.md
@@ -15,6 +15,8 @@ as much as possible.
The current stages are:
+- `sync`: This stage is used to synchronize changes from gitlab-org/gitlab to
+ gitlab-org/gitlab-foss.
- `prepare`: This stage includes jobs that prepare artifacts that are needed by
jobs in subsequent stages.
- `quick-test`: This stage includes test jobs that should run first and fail the
@@ -27,7 +29,6 @@ The current stages are:
- `review`: This stage includes jobs that deploy the GitLab and Docs Review Apps.
- `qa`: This stage includes jobs that perform QA tasks against the Review App
that is deployed in the previous stage.
-- `notification`: This stage includes jobs that sends notifications about pipeline status.
- `post-test`: This stage includes jobs that build reports or gather data from
the previous stages' jobs (e.g. coverage, Knapsack metadata etc.).
- `pages`: This stage includes a job that deploys the various reports as
@@ -38,7 +39,8 @@ The current stages are:
## Default image
The default image is currently
-`gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.3-golang-1.11-git-2.22-chrome-73.0-node-12.x-yarn-1.16-postgresql-9.6-graphicsmagick-1.3.33`.
+`registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.3-golang-1.11-git-2.22-chrome-73.0-node-12.x-yarn-1.16-postgresql-9.6-graphicsmagick-1.3.33`.
+
It includes Ruby 2.6.3, Go 1.11, Git 2.22, Chrome 73, Node 12, Yarn 1.16,
PostgreSQL 9.6, and Graphics Magick 1.3.33.
@@ -48,24 +50,13 @@ project, which is push-mirrored to <https://dev.gitlab.org/gitlab/gitlab-build-i
for redundancy.
The current version of the build images can be found in the
-["Used by GitLab CE/EE section"](https://gitlab.com/gitlab-org/gitlab-build-images/blob/master/.gitlab-ci.yml).
+["Used by GitLab section"](https://gitlab.com/gitlab-org/gitlab-build-images/blob/master/.gitlab-ci.yml).
## Default variables
In addition to the [predefined variables](../ci/variables/predefined_variables.md),
-each pipeline includes the following [variables](../ci/variables/README.md):
-
-- `RAILS_ENV: "test"`
-- `NODE_ENV: "test"`
-- `SIMPLECOV: "true"`
-- `GIT_DEPTH: "50"`
-- `GIT_SUBMODULE_STRATEGY: "none"`
-- `GET_SOURCES_ATTEMPTS: "3"`
-- `KNAPSACK_RSPEC_SUITE_REPORT_PATH: knapsack/${CI_PROJECT_NAME}/rspec_report-master.json`
-- `FLAKY_RSPEC_SUITE_REPORT_PATH: rspec_flaky/report-suite.json`
-- `BUILD_ASSETS_IMAGE: "false"`
-- `ES_JAVA_OPTS: "-Xms256m -Xmx256m"`
-- `ELASTIC_URL: "http://elastic:changeme@docker.elastic.co-elasticsearch-elasticsearch:9200"`
+each pipeline includes default variables defined in
+<https://gitlab.com/gitlab-org/gitlab/blob/master/.gitlab-ci.yml>.
## Common job definitions
@@ -85,22 +76,35 @@ These common definitions are:
Ruby/Rails and frontend tasks.
- `.default-only`: Restricts the cases where a job is created. This currently
includes `master`, `/^[\d-]+-stable(-ee)?$/` (stable branches),
- `/^\d+-\d+-auto-deploy-\d+$/` (security branches), `merge_requests`, `tags`.
+ `/^\d+-\d+-auto-deploy-\d+$/` (auto-deploy branches), `/^security\//` (security branches), `merge_requests`, `tags`.
Note that jobs won't be created for branches with this default configuration.
-- `.only-review`: Only creates a job for the `gitlab-org` namespace and if
- Kubernetes integration is available. Also, prevents a job from being created
- for `master` and auto-deploy branches.
-- `.only-review-schedules`: Same as `.only-review` but also restrict a job to
- only run for [schedules](../user/project/pipelines/schedules.md).
-- `.only-canonical-schedules`: Only creates a job for scheduled pipelines in
- the `gitlab-org/gitlab` and `gitlab-org/gitlab-foss` projects
+- `.only:variables-canonical-dot-com`: Only creates a job if the project is
+ located under <https://gitlab.com/gitlab-org>.
+- `.only:variables_refs-canonical-dot-com-schedules`: Same as
+ `.only:variables-canonical-dot-com` but add the condition that pipeline is scheduled.
+- `.except:refs-deploy`: Don't create a job if the `ref` is an auto-deploy branch.
+- `.except:refs-master-tags-stable-deploy`: Don't create a job if the `ref` is one of:
+ - `master`
+ - a tag
+ - a stable branch
+ - an auto-deploy branch
+- `.only:kubernetes`: Only creates a job if a Kubernetes integration is enabled
+ on the project.
+- `.only-review`: This extends from:
+ - `.only:variables-canonical-dot-com`
+ - `.only:kubernetes`
+ - `.except:refs-master-tags-stable-deploy`
+- `.only-review-schedules`: This extends from:
+ - `.only:variables_refs-canonical-dot-com-schedules`
+ - `.only:kubernetes`
+ - `.except:refs-deploy`
- `.use-pg9`: Allows a job to use the `postgres:9.6` and `redis:alpine` services.
- `.use-pg10`: Allows a job to use the `postgres:10.9` and `redis:alpine` services.
- `.use-pg9-ee`: Same as `.use-pg9` but also use the
`docker.elastic.co/elasticsearch/elasticsearch:5.6.12` services.
- `.use-pg10-ee`: Same as `.use-pg10` but also use the
`docker.elastic.co/elasticsearch/elasticsearch:5.6.12` services.
-- `.only-ee`: Only creates a job for the `gitlab` project.
+- `.only-ee`: Only creates a job for the `gitlab` or `gitlab-ee` project.
- `.only-ee-as-if-foss`: Same as `.only-ee` but simulate the FOSS project by
setting the `FOSS_ONLY='1'` environment variable.
@@ -111,11 +115,13 @@ the cases where it should be created
[based on the changes](../ci/yaml/README.md#onlychangesexceptchanges)
from a commit or MR by extending from the following CI definitions:
-- `.only-code-changes`: Allows a job to only be created upon code-related changes.
-- `.only-qa-changes`: Allows a job to only be created upon QA-related changes.
-- `.only-docs-changes`: Allows a job to only be created upon docs-related changes.
-- `.only-code-qa-changes`: Allows a job to only be created upon code-related or QA-related changes.
-- `.only-graphql-changes`: Allows a job to only be created upon graphql-related changes.
+- `.only:changes-code`: Allows a job to only be created upon code-related changes.
+- `.only:changes-qa`: Allows a job to only be created upon QA-related changes.
+- `.only:changes-docs`: Allows a job to only be created upon docs-related changes.
+- `.only:changes-graphql`: Allows a job to only be created upon GraphQL-related changes.
+- `.only:changes-code-backstage`: Allows a job to only be created upon code-related or backstage-related (e.g. Danger, RuboCop, specs) changes.
+- `.only:changes-code-qa`: Allows a job to only be created upon code-related or QA-related changes.
+- `.only:changes-code-backstage-qa`: Allows a job to only be created upon code-related, backstage-related (e.g. Danger, RuboCop, specs) or QA-related changes.
**See <https://gitlab.com/gitlab-org/gitlab/blob/master/.gitlab/ci/global.gitlab-ci.yml>
for the list of exact patterns.**
@@ -203,11 +209,6 @@ subgraph "`qa` stage"
dast -.-> |needs and depends on| G;
end
-subgraph "`notification` stage"
- NOTIFICATION1["schedule:package-and-qa:notify-success<br>(on_success)"] -.-> |needs| P;
- NOTIFICATION2["schedule:package-and-qa:notify-failure<br>(on_failure)"] -.-> |needs| P;
- end
-
subgraph "`post-test` stage"
M
end
diff --git a/doc/development/policies.md b/doc/development/policies.md
index 833b0acb13e..8e5ef6e57c0 100644
--- a/doc/development/policies.md
+++ b/doc/development/policies.md
@@ -157,3 +157,18 @@ end
```
will include all rules from `ProjectPolicy`. The delegated conditions will be evaluated with the correct delegated subject, and will be sorted along with the regular rules in the policy. Note that only the relevant rules for a particular ability will actually be considered.
+
+## Specifying Policy Class
+
+You can also override the Policy used for a given subject:
+
+```ruby
+class Foo
+
+ def self.declarative_policy_class
+ 'SomeOtherPolicy'
+ end
+end
+```
+
+This will use & check permissions on the `SomeOtherPolicy` class rather than the usual calculated `FooPolicy` class.
diff --git a/doc/development/profiling.md b/doc/development/profiling.md
index 04897e770f8..18683fa10f8 100644
--- a/doc/development/profiling.md
+++ b/doc/development/profiling.md
@@ -42,6 +42,10 @@ Passing a `logger:` keyword argument to `Gitlab::Profiler.profile` will send
ActiveRecord and ActionController log output to that logger. Further options are
documented with the method source.
+```ruby
+Gitlab::Profiler.profile('/gitlab-org/gitlab-test', user: User.first, logger: Logger.new(STDOUT))
+```
+
There is also a RubyProf printer available:
`Gitlab::Profiler::TotalTimeFlatPrinter`. This acts like
`RubyProf::FlatPrinter`, but its `min_percent` option works on the method's
diff --git a/doc/development/rake_tasks.md b/doc/development/rake_tasks.md
index a6d3c008686..369806d462b 100644
--- a/doc/development/rake_tasks.md
+++ b/doc/development/rake_tasks.md
@@ -12,6 +12,14 @@ The `setup` task is an alias for `gitlab:setup`.
This tasks calls `db:reset` to create the database, and calls `db:seed_fu` to seed the database.
Note: `db:setup` calls `db:seed` but this does nothing.
+### Env variables
+
+**MASS_INSERT**: Create millions of users (2m), projects (5m) and its
+relations. It's highly recommended to run the seed with it to catch slow queries
+while developing. Expect the process to take up to 20 extra minutes.
+
+**LARGE_PROJECTS**: Create large projects (through import) from a predefined set of urls.
+
### Seeding issues for all or a given project
You can seed issues for all or a given project with the `gitlab:seed:issues`
@@ -221,7 +229,7 @@ bundle exec rake db:obsolete_ignored_columns
Feel free to remove their definitions from their `ignored_columns` definitions.
-## Update GraphQL Documentation
+## Update GraphQL Documentation and Schema definitions
To generate GraphQL documentation based on the GitLab schema, run:
@@ -243,3 +251,13 @@ The actual renderer is at `Gitlab::Graphql::Docs::Renderer`.
`@parsed_schema` is an instance variable that the `graphql-docs` gem expects to have available.
`Gitlab::Graphql::Docs::Helper` defines the `object` method we currently use. This is also where you
should implement any new methods for new types you'd like to display.
+
+### Update machine-readable schema files
+
+To generate GraphQL schema files based on the GitLab schema, run:
+
+```shell
+bundle exec rake gitlab:graphql:schema:dump
+```
+
+This uses graphql-ruby's built-in rake tasks to generate files in both [IDL](https://www.prisma.io/blog/graphql-sdl-schema-definition-language-6755bcb9ce51) and JSON formats.
diff --git a/doc/development/repository_mirroring.md b/doc/development/repository_mirroring.md
index 8521d6fcd30..0a0c91821cf 100644
--- a/doc/development/repository_mirroring.md
+++ b/doc/development/repository_mirroring.md
@@ -5,6 +5,6 @@
In December 2018, Tiago Botelho hosted a [Deep Dive] on GitLab's [Pull Repository Mirroring functionality] to share his domain specific knowledge with anyone who may work in this part of the code base in the future. You can find the [recording on YouTube], and the slides in [PDF]. Everything covered in this deep dive was accurate as of GitLab 11.6, and while specific details may have changed since then, it should still serve as a good introduction.
[Deep Dive]: https://gitlab.com/gitlab-org/create-stage/issues/1
-[Pull Repository Mirroring functionality]: ../workflow/repository_mirroring.md#pulling-from-a-remote-repository-starter
+[Pull Repository Mirroring functionality]: ../user/project/repository/repository_mirroring.md#pulling-from-a-remote-repository-starter
[recording on YouTube]: https://www.youtube.com/watch?v=sSZq0fpdY-Y
[PDF]: https://gitlab.com/gitlab-org/create-stage/uploads/8693404888a941fd851f8a8ecdec9675/Gitlab_Create_-_Pull_Mirroring_Deep_Dive.pdf
diff --git a/doc/development/sidekiq_style_guide.md b/doc/development/sidekiq_style_guide.md
index d52a3e652e3..e433691c1ed 100644
--- a/doc/development/sidekiq_style_guide.md
+++ b/doc/development/sidekiq_style_guide.md
@@ -61,6 +61,168 @@ the extra jobs will take resources away from jobs from workers that were already
there, if the resources available to the Sidekiq process handling the namespace
are not adjusted appropriately.
+## Latency Sensitive Jobs
+
+If a large number of background jobs get scheduled at once, queueing of jobs may
+occur while jobs wait for a worker node to be become available. This is normal
+and gives the system resilience by allowing it to gracefully handle spikes in
+traffic. Some jobs, however, are more sensitive to latency than others. Examples
+of these jobs include:
+
+1. A job which updates a merge request following a push to a branch.
+1. A job which invalidates a cache of known branches for a project after a push
+ to the branch.
+1. A job which recalculates the groups and projects a user can see after a
+ change in permissions.
+1. A job which updates the status of a CI pipeline after a state change to a job
+ in the pipeline.
+
+When these jobs are delayed, the user may perceive the delay as a bug: for
+example, they may push a branch and then attempt to create a merge request for
+that branch, but be told in the UI that the branch does not exist. We deem these
+jobs to be `latency_sensitive`.
+
+Extra effort is made to ensure that these jobs are started within a very short
+period of time after being scheduled. However, in order to ensure throughput,
+these jobs also have very strict execution duration requirements:
+
+1. The median job execution time should be less than 1 second.
+1. 99% of jobs should complete within 10 seconds.
+
+If a worker cannot meet these expectations, then it cannot be treated as a
+`latency_sensitive` worker: consider redesigning the worker, or splitting the
+work between two different workers, one with `latency_sensitive` code that
+executes quickly, and the other with non-`latency_sensitive`, which has no
+execution latency requirements (but also has lower scheduling targets).
+
+This can be summed up in the following table:
+
+| **Latency Sensitivity** | **Queue Scheduling Target** | **Execution Latency Requirement** |
+|-------------------------|-----------------------------|-------------------------------------|
+| Not `latency_sensitive` | 1 minute | Maximum run time of 1 hour |
+| `latency_sensitive` | 100 milliseconds | p50 of 1 second, p99 of 10 seconds |
+
+To mark a worker as being `latency_sensitive`, use the
+`latency_sensitive_worker!` attribute, as shown in this example:
+
+```ruby
+class LatencySensitiveWorker
+ include ApplicationWorker
+
+ latency_sensitive_worker!
+
+ # ...
+end
+```
+
+## Jobs with External Dependencies
+
+Most background jobs in the GitLab application communicate with other GitLab
+services, eg Postgres, Redis, Gitaly and Object Storage. These are considered
+to be "internal" dependencies for a job.
+
+However, some jobs will be dependent on external services in order to complete
+successfully. Some examples include:
+
+1. Jobs which call web-hooks configured by a user.
+1. Jobs which deploy an application to a k8s cluster configured by a user.
+
+These jobs have "external dependencies". This is important for the operation of
+the background processing cluster in several ways:
+
+1. Most external dependencies (such as web-hooks) do not provide SLOs, and
+ therefore we cannot guarantee the execution latencies on these jobs. Since we
+ cannot guarantee execution latency, we cannot ensure throughput and
+ therefore, in high-traffic environments, we need to ensure that jobs with
+ external dependencies are separated from `latency_sensitive` jobs, to ensure
+ throughput on those queues.
+1. Errors in jobs with external dependencies have higher alerting thresholds as
+ there is a likelihood that the cause of the error is external.
+
+```ruby
+class ExternalDependencyWorker
+ include ApplicationWorker
+
+ # Declares that this worker depends on
+ # third-party, external services in order
+ # to complete successfully
+ worker_has_external_dependencies!
+
+ # ...
+end
+```
+
+NOTE: **Note:** Note that a job cannot be both latency sensitive and have
+external dependencies.
+
+## CPU-bound and Memory-bound Workers
+
+Workers that are constrained by CPU or memory resource limitations should be
+annotated with the `worker_resource_boundary` method.
+
+Most workers tend to spend most of their time blocked, wait on network responses
+from other services such as Redis, Postgres and Gitaly. Since Sidekiq is a
+multithreaded environment, these jobs can be scheduled with high concurrency.
+
+Some workers, however, spend large amounts of time _on-cpu_ running logic in
+Ruby. Ruby MRI does not support true multithreading - it relies on the
+[GIL](https://thoughtbot.com/blog/untangling-ruby-threads#the-global-interpreter-lock)
+to greatly simplify application development by only allowing one section of Ruby
+code in a process to run at a time, no matter how many cores the machine
+hosting the process has. For IO bound workers, this is not a problem, since most
+of the threads are blocked in underlying libraries (which are outside of the
+GIL).
+
+If many threads are attempting to run Ruby code simultaneously, this will lead
+to contention on the GIL which will have the affect of slowing down all
+processes.
+
+In high-traffic environments, knowing that a worker is CPU-bound allows us to
+run it on a different fleet with lower concurrency. This ensures optimal
+performance.
+
+Likewise, if a worker uses large amounts of memory, we can run these on a
+bespoke low concurrency, high memory fleet.
+
+Note that Memory-bound workers create heavy GC workloads, with pauses of
+10-50ms. This will have an impact on the latency requirements for the
+worker. For this reason, `memory` bound, `latency_sensitive` jobs are not
+permitted and will fail CI. In general, `memory` bound workers are
+discouraged, and alternative approaches to processing the work should be
+considered.
+
+## Declaring a Job as CPU-bound
+
+This example shows how to declare a job as being CPU-bound.
+
+```ruby
+class CPUIntensiveWorker
+ include ApplicationWorker
+
+ # Declares that this worker will perform a lot of
+ # calculations on-CPU.
+ worker_resource_boundary :cpu
+
+ # ...
+end
+```
+
+## Determining whether a worker is CPU-bound
+
+We use the following approach to determine whether a worker is CPU-bound:
+
+- In the sidekiq structured JSON logs, aggregate the worker `duration` and
+ `cpu_s` fields.
+- `duration` refers to the total job execution duration, in seconds
+- `cpu_s` is derived from the
+ [`Process::CLOCK_THREAD_CPUTIME_ID`](https://www.rubydoc.info/stdlib/core/Process:clock_gettime)
+ counter, and is a measure of time spent by the job on-CPU.
+- Divide `cpu_s` by `duration` to get the percentage time spend on-CPU.
+- If this ratio exceeds 33%, the worker is considered CPU-bound and should be
+ annotated as such.
+- Note that these values should not be used over small sample sizes, but
+ rather over fairly large aggregates.
+
## Feature Categorization
Each Sidekiq worker, or one of its ancestor classes, must declare a
@@ -74,7 +236,7 @@ The declaration uses the `feature_category` class method, as shown below.
class SomeScheduledTaskWorker
include ApplicationWorker
- # Declares that this feature is part of the
+ # Declares that this worker is part of the
# `continuous_integration` feature category
feature_category :continuous_integration
@@ -88,11 +250,11 @@ source](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/stages.yml
### Updating `config/feature_categories.yml`
-Occassionally new features will be added to GitLab stages. When this occurs, you
+Occasionally new features will be added to GitLab stages. When this occurs, you
can automatically update `config/feature_categories.yml` by running
`scripts/update-feature-categories`. This script will fetch and parse
[`stages.yml`](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/stages.yml)
-and generare a new version of the file, which needs to be checked into source control.
+and generate a new version of the file, which needs to be checked into source control.
### Excluding Sidekiq workers from feature categorization
@@ -116,9 +278,63 @@ end
Each Sidekiq worker must be tested using RSpec, just like any other class. These
tests should be placed in `spec/workers`.
-## Removing or renaming queues
+## Sidekiq Compatibility across Updates
+
+Keep in mind that the arguments for a Sidekiq job are stored in a queue while it
+is scheduled for execution. During a online update, this could lead to several
+possible situations:
+
+1. An older version of the application publishes a job, which is executed by an
+ upgraded Sidekiq node.
+1. A job is queued before an upgrade, but executed after an upgrade.
+1. A job is queued by a node running the newer version of the application, but
+ executed on a node running an older version of the application.
+
+### Changing the arguments for a worker
+
+Jobs need to be backwards- and forwards-compatible between consecutive versions
+of the application.
+
+This can be done by following this process:
+
+1. **Do not remove arguments from the `perform` function.**. Instead, use the
+ following approach
+ 1. Provide a default value (usually `nil`) and use a comment to mark the
+ argument as deprecated
+ 1. Stop using the argument in `perform_async`.
+ 1. Ignore the value in the worker class, but do not remove it until the next
+ major release.
+
+### Removing workers
+
+Try to avoid removing workers and their queues in minor and patch
+releases.
-Try to avoid renaming or removing workers and their queues in minor and patch releases.
During online update instance can have pending jobs and removing the queue can
lead to those jobs being stuck forever. If you can't write migration for those
-Sidekiq jobs, please consider doing rename or remove queue in major release only.
+Sidekiq jobs, please consider removing the worker in a major release only.
+
+### Renaming queues
+
+For the same reasons that removing workers is dangerous, care should be taken
+when renaming queues.
+
+When renaming queues, use the `sidekiq_queue_migrate` helper migration method,
+as show in this example:
+
+```ruby
+class MigrateTheRenamedSidekiqQueue < ActiveRecord::Migration[5.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def up
+ sidekiq_queue_migrate 'old_queue_name', to: 'new_queue_name'
+ end
+
+ def down
+ sidekiq_queue_migrate 'new_queue_name', to: 'old_queue_name'
+ end
+end
+
+```
diff --git a/doc/development/testing_guide/best_practices.md b/doc/development/testing_guide/best_practices.md
index 32e079f915c..fe3989474e6 100644
--- a/doc/development/testing_guide/best_practices.md
+++ b/doc/development/testing_guide/best_practices.md
@@ -44,6 +44,14 @@ bundle exec rspec
bundle exec rspec spec/[path]/[to]/[spec].rb
```
+Use [guard](https://github.com/guard/guard) to continuously monitor for changes and only run matching tests:
+
+```sh
+bundle exec guard
+```
+
+When using spring and guard together, use `SPRING=1 bundle exec guard` instead to make use of spring.
+
### General guidelines
- Use a single, top-level `describe ClassName` block.
@@ -61,6 +69,7 @@ bundle exec rspec spec/[path]/[to]/[spec].rb
- When using `evaluate_script("$('.js-foo').testSomething()")` (or `execute_script`) which acts on a given element,
use a Capyabara matcher beforehand (e.g. `find('.js-foo')`) to ensure the element actually exists.
- Use `focus: true` to isolate parts of the specs you want to run.
+- Use [`:aggregate_failures`](https://relishapp.com/rspec/rspec-core/docs/expectation-framework-integration/aggregating-failures) when there is more than one expectation in a test.
### System / Feature tests
@@ -356,10 +365,22 @@ However, if a spec makes direct Redis calls, it should mark itself with the
`:clean_gitlab_redis_cache`, `:clean_gitlab_redis_shared_state` or
`:clean_gitlab_redis_queues` traits as appropriate.
-Sidekiq jobs are typically not run in specs, but this behaviour can be altered
-in each spec through the use of `perform_enqueued_jobs` blocks. Any spec that
-causes Sidekiq jobs to be pushed to Redis should use the `:sidekiq` trait, to
-ensure that they are removed once the spec completes.
+#### Background jobs / Sidekiq
+
+By default, Sidekiq jobs are enqueued into a jobs array and aren't processed.
+If a test enqueues Sidekiq jobs and need them to be processed, the
+`:sidekiq_inline` trait can be used.
+
+The `:sidekiq_might_not_need_inline` trait was added when [Sidekiq inline mode was
+changed to fake mode](https://gitlab.com/gitlab-org/gitlab/merge_requests/15479)
+to all the tests that needed Sidekiq to actually process jobs. Tests with
+this trait should be either fixed to not rely on Sidekiq processing jobs, or their
+`:sidekiq_might_not_need_inline` trait should be updated to `:sidekiq_inline` if
+the processing of background jobs is needed/expected.
+
+NOTE: **Note:**
+The usage of `perform_enqueued_jobs` is currently useless since our
+workers aren't inheriting from `ApplicationJob` / `ActiveJob::Base`.
#### Filesystem
diff --git a/doc/development/testing_guide/end_to_end/best_practices.md b/doc/development/testing_guide/end_to_end/best_practices.md
index 042879b47aa..e2a0d267ba1 100644
--- a/doc/development/testing_guide/end_to_end/best_practices.md
+++ b/doc/development/testing_guide/end_to_end/best_practices.md
@@ -65,3 +65,31 @@ This library [saves the screenshots in the RSpec's `after` hook](https://github.
Given this fact, we should limit the use of `before(:all)` to only those operations where a screenshot is not
necessary in case of failure and QA logs would be enough for debugging.
+
+## Ensure tests do not leave the browser logged in
+
+All QA tests expect to be able to log in at the start of the test.
+
+That's not possible if a test leaves the browser logged in when it finishes. Normally this isn't a problem because [Capybara resets the session after each test](https://github.com/teamcapybara/capybara/blob/9ebc5033282d40c73b0286e60217515fd1bb0b5d/lib/capybara/rspec.rb#L18). But Capybara does that in an `after` block, so when a test logs in in an `after(:context)` block, the browser returns to a logged in state *after* Capybara had logged it out. And so the next test will fail.
+
+For an example see: <https://gitlab.com/gitlab-org/gitlab/issues/34736>
+
+Ideally, any actions peformed in an `after(:context)` (or [`before(:context)`](#limit-the-use-of-beforeall-hook)) block would be performed via the API. But if it's necessary to do so via the UI (e.g., if API functionality doesn't exist), make sure to log out at the end of the block.
+
+```ruby
+after(:all) do
+ login unless Page::Main::Menu.perform(&:signed_in?)
+
+ # Do something while logged in
+
+ Page::Main::Menu.perform(&:sign_out)
+end
+```
+
+## Tag tests that require Administrator access
+
+We don't run tests that require Administrator access against our Production environments.
+
+When you add a new test that requires Administrator access, apply the RSpec metadata `:requires_admin` so that the test will not be included in the test suites executed against Production and other environments on which we don't want to run those tests.
+
+Note: When running tests locally or configuring a pipeline, the environment variable `QA_CAN_TEST_ADMIN_FEATURES` can be set to `false` to skip tests that have the `:requires_admin` tag.
diff --git a/doc/development/testing_guide/end_to_end/feature_flags.md b/doc/development/testing_guide/end_to_end/feature_flags.md
new file mode 100644
index 00000000000..bf1e70be9cb
--- /dev/null
+++ b/doc/development/testing_guide/end_to_end/feature_flags.md
@@ -0,0 +1,27 @@
+# Testing with feature flags
+
+To run a specific test with a feature flag enabled you can use the `QA::Runtime::Feature` class to enabled and disable feature flags ([via the API](../../../api/features.md)).
+
+Note that administrator authorization is required to change feature flags. `QA::Runtime::Feature` will automatically authenticate as an administrator as long as you provide an appropriate access token via `GITLAB_QA_ADMIN_ACCESS_TOKEN` (recommended), or provide `GITLAB_ADMIN_USERNAME` and `GITLAB_ADMIN_PASSWORD`.
+
+```ruby
+context "with feature flag enabled" do
+ before do
+ Runtime::Feature.enable('feature_flag_name')
+ end
+
+ it "feature flag test" do
+ # Execute a test with a feature flag enabled
+ end
+
+ after do
+ Runtime::Feature.disable('feature_flag_name')
+ end
+end
+```
+
+## Running a scenario with a feature flag enabled
+
+It's also possible to run an entire scenario with a feature flag enabled, without having to edit existing tests or write new ones.
+
+Please see the [QA readme](https://gitlab.com/gitlab-org/gitlab/tree/master/qa#running-tests-with-a-feature-flag-enabled) for details.
diff --git a/doc/development/testing_guide/end_to_end/flows.md b/doc/development/testing_guide/end_to_end/flows.md
new file mode 100644
index 00000000000..fb1d82914aa
--- /dev/null
+++ b/doc/development/testing_guide/end_to_end/flows.md
@@ -0,0 +1,56 @@
+# Flows in GitLab QA
+
+Flows are frequently used sequences of actions. They are a higher level
+of abstraction than page objects. Flows can include multiple page objects,
+or any other relevant code.
+
+For example, the sign in flow encapsulates two steps that are included
+in every browser UI test.
+
+```ruby
+# QA::Flow::Login
+
+def sign_in(as: nil)
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.perform { |login| login.sign_in_using_credentials(user: as) }
+end
+
+# When used in a test
+
+it 'performs a test after signing in as the default user' do
+ Flow::Login.sign_in
+
+ # Perform the test
+end
+```
+
+`QA::Flow::Login` provides an even more useful flow, allowing a test to easily switch users.
+
+```ruby
+# QA::Flow::Login
+
+def while_signed_in(as: nil)
+ Page::Main::Menu.perform(&:sign_out_if_signed_in)
+
+ sign_in(as: as)
+
+ yield
+
+ Page::Main::Menu.perform(&:sign_out)
+end
+
+# When used in a test
+
+it 'performs a test as one user and verifies as another' do
+ user1 = Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1)
+ user2 = Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_2, Runtime::Env.gitlab_qa_password_2)
+
+ Flow::Login.while_signed_in(as: user1) do
+ # Perform some setup as user1
+ end
+
+ Flow::Login.sign_in(as: user2)
+
+ # Perform the rest of the test as user2
+end
+```
diff --git a/doc/development/testing_guide/end_to_end/index.md b/doc/development/testing_guide/end_to_end/index.md
index a9fb4be284e..19885f5756f 100644
--- a/doc/development/testing_guide/end_to_end/index.md
+++ b/doc/development/testing_guide/end_to_end/index.md
@@ -130,6 +130,8 @@ Continued reading:
- [Quick Start Guide](quick_start_guide.md)
- [Style Guide](style_guide.md)
- [Best Practices](best_practices.md)
+- [Testing with feature flags](feature_flags.md)
+- [Flows](flows.md)
## Where can I ask for help?
diff --git a/doc/development/testing_guide/end_to_end/page_objects.md b/doc/development/testing_guide/end_to_end/page_objects.md
index 28111c18378..554995fa2e2 100644
--- a/doc/development/testing_guide/end_to_end/page_objects.md
+++ b/doc/development/testing_guide/end_to_end/page_objects.md
@@ -167,6 +167,65 @@ There are two supported methods of defining elements within a view.
Any existing `.qa-selector` class should be considered deprecated
and we should prefer the `data-qa-selector` method of definition.
+### Dynamic element selection
+
+> Introduced in GitLab 12.5
+
+A common occurrence in automated testing is selecting a single "one-of-many" element.
+In a list of several items, how do you differentiate what you are selecting on?
+The most common workaround for this is via text matching. Instead, a better practice is
+by matching on that specific element by a unique identifier, rather than by text.
+
+We got around this by adding the `data-qa-*` extensible selection mechanism.
+
+#### Examples
+
+**Example 1**
+
+Given the following Rails view (using GitLab Issues as an example):
+
+```haml
+%ul.issues-list
+ - @issues.each do |issue|
+ %li.issue{data: { qa_selector: 'issue', qa_issue_title: issue.title } }= link_to issue
+```
+
+We can select on that specific issue by matching on the Rails model.
+
+```ruby
+class Page::Project::Issues::Index < Page::Base
+ def has_issue?(issue)
+ has_element? :issue, issue_title: issue
+ end
+end
+```
+
+In our test, we can validate that this particular issue exists.
+
+```ruby
+describe 'Issue' do
+ it 'has an issue titled "hello"' do
+ Page::Project::Issues::Index.perform do |index|
+ expect(index).to have_issue('hello')
+ end
+ end
+end
+```
+
+**Example 2**
+
+*By an index...*
+
+```haml
+%ol
+ - @some_model.each_with_index do |model, idx|
+ %li.model{ data: { qa_selector: 'model', qa_index: idx } }
+```
+
+```ruby
+expect(the_page).to have_element(:model, index: 1) #=> select on the first model that appears in the list
+```
+
### Exceptions
In some cases it might not be possible or worthwhile to add a selector.
diff --git a/doc/development/testing_guide/flaky_tests.md b/doc/development/testing_guide/flaky_tests.md
index 0823c2e02b8..3a96f8204fc 100644
--- a/doc/development/testing_guide/flaky_tests.md
+++ b/doc/development/testing_guide/flaky_tests.md
@@ -83,6 +83,7 @@ This was originally implemented in: <https://gitlab.com/gitlab-org/gitlab-foss/m
- In JS tests, shifting elements can cause Capybara to misclick when the element moves at the exact time Capybara sends the click
- [Dropdowns rendering upward or downward due to window size and scroll position](https://gitlab.com/gitlab-org/gitlab/merge_requests/17660)
- [Lazy loaded images can cause Capybara to misclick](https://gitlab.com/gitlab-org/gitlab/merge_requests/18713)
+- [Triggering JS events before the event handlers are set up](https://gitlab.com/gitlab-org/gitlab/merge_requests/18742)
#### Capybara viewport size related issues
diff --git a/doc/development/testing_guide/frontend_testing.md b/doc/development/testing_guide/frontend_testing.md
index 314995ca9b3..236f175cee5 100644
--- a/doc/development/testing_guide/frontend_testing.md
+++ b/doc/development/testing_guide/frontend_testing.md
@@ -119,6 +119,50 @@ Global mocks introduce magic and can affect how modules are imported in your tes
When in doubt, construct mocks in your test file using [`jest.mock()`](https://jestjs.io/docs/en/jest-object#jestmockmodulename-factory-options), [`jest.spyOn()`](https://jestjs.io/docs/en/jest-object#jestspyonobject-methodname), etc.
+### Data-driven tests
+
+Similar to [RSpec's parameterized tests](best_practices.md#table-based--parameterized-tests),
+Jest supports data-driven tests for:
+
+- Individual tests using [`test.each`](https://jestjs.io/docs/en/api#testeachtable-name-fn-timeout) (aliased to `it.each`).
+- Groups of tests using [`describe.each`](https://jestjs.io/docs/en/api#describeeachtable-name-fn-timeout).
+
+These can be useful for reducing repetition within tests. Each option can take an array of
+data values or a tagged template literal.
+
+For example:
+
+```javascript
+// function to test
+const icon = status => status ? 'pipeline-passed' : 'pipeline-failed'
+const message = status => status ? 'pipeline-passed' : 'pipeline-failed'
+
+// test with array block
+it.each([
+ [false, 'pipeline-failed'],
+ [true, 'pipeline-passed']
+])('icon with %s will return %s',
+ (status, icon) => {
+ expect(renderPipeline(status)).toEqual(icon)
+ }
+);
+
+// test suite with tagged template literal block
+describe.each`
+ status | icon | message
+ ${false} | ${'pipeline-failed'} | ${'Pipeline failed - boo-urns'}
+ ${true} | ${'pipeline-passed'} | ${'Pipeline succeeded - win!'}
+`('pipeline component', ({ status, icon, message }) => {
+ it(`returns icon ${icon} with status ${status}`, () => {
+ expect(icon(status)).toEqual(message)
+ })
+
+ it(`returns message ${message} with status ${status}`, () => {
+ expect(message(status)).toEqual(message)
+ })
+});
+```
+
## Karma test suite
GitLab uses the [Karma][karma] test runner with [Jasmine] as its test
@@ -457,6 +501,39 @@ it('waits for an event', () => {
});
```
+#### Ensuring that tests are isolated
+
+Tests are normally architected in a pattern which requires a recurring setup and breakdown of the component under test. This is done by making use of the `beforeEach` and `afterEach` hooks.
+
+Example
+
+```javascript
+ let wrapper;
+
+ beforeEach(() => {
+ wrapper = mount(Component);
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+```
+
+When looking at this initially you'd suspect that the component is setup before each test and then broken down afterwards, providing isolation between tests.
+
+This is however not entirely true as the `destroy` method does not remove everything which has been mutated on the `wrapper` object. For functional components, destroy only removes the rendered DOM elements from the document.
+
+In order to ensure that a clean wrapper object and DOM are being used in each test, the breakdown of the component should rather be performed as follows:
+
+```javascript
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+```
+
+See also the [Vue Test Utils documention on `destroy`](https://vue-test-utils.vuejs.org/api/wrapper/#destroy).
+
#### Migrating flaky Karma tests to Jest
Some of our Karma tests are flaky because they access the properties of a shared scope.
diff --git a/doc/development/testing_guide/review_apps.md b/doc/development/testing_guide/review_apps.md
index 3dd403f148e..ecfcbc731e1 100644
--- a/doc/development/testing_guide/review_apps.md
+++ b/doc/development/testing_guide/review_apps.md
@@ -189,10 +189,10 @@ that the `review-apps-ce/ee` cluster is unhealthy. Leading indicators may be hea
The following items may help diagnose this:
-- [Instance group CPU Utilization in GCP](https://console.cloud.google.com/compute/instanceGroups/details/us-central1-b/gke-review-apps-ee-preemp-n1-standard-8affc0f5-grp?project=gitlab-review-apps&tab=monitoring&graph=GCE_CPU&duration=P30D) - helpful to identify if nodes are problematic or the entire cluster is trending towards unhealthy
-- [Instance Group size in GCP](https://console.cloud.google.com/compute/instanceGroups/details/us-central1-b/gke-review-apps-ee-preemp-n1-standard-8affc0f5-grp?project=gitlab-review-apps&tab=monitoring&graph=GCE_SIZE&duration=P30D) - aids in identifying load spikes on the cluster. Kubernetes will add nodes up to 220 based on total resource requests.
-- `kubectl top nodes --sort-by=cpu` - can identify if node spikes are common or load on specific nodes which may get rebalanced by the Kubernetes scheduler.
-- `kubectl top pods --sort-by=cpu` -
+- [Review Apps Health dashboard](https://app.google.stackdriver.com/dashboards/6798952013815386466?project=gitlab-review-apps&timeDomain=1d)
+ - Aids in identifying load spikes on the cluster, and if nodes are problematic or the entire cluster is trending towards unhealthy.
+- `kubectl top nodes | sort --key 3 --numeric` - can identify if node spikes are common or load on specific nodes which may get rebalanced by the Kubernetes scheduler.
+- `kubectl top pods | sort --key 2 --numeric` -
- [K9s] - K9s is a powerful command line dashboard which allows you to filter by labels. This can help identify trends with apps exceeding the [review-app resource requests](https://gitlab.com/gitlab-org/gitlab/blob/master/scripts/review_apps/base-config.yaml). Kubernetes will schedule pods to nodes based on resource requests and allow for CPU usage up to the limits.
- In K9s you can sort or add filters by typing the `/` character
- `-lrelease=<review-app-slug>` - filters down to all pods for a release. This aids in determining what is having issues in a single deployment
diff --git a/doc/development/understanding_explain_plans.md b/doc/development/understanding_explain_plans.md
index 7c926c83a36..53b50b6332c 100644
--- a/doc/development/understanding_explain_plans.md
+++ b/doc/development/understanding_explain_plans.md
@@ -705,6 +705,43 @@ For more information about the available options, run:
/chatops run explain --help
```
+### `#database-lab`
+
+Another tool GitLab employees can use is a chatbot powered by [Joe](https://gitlab.com/postgres-ai/joe), available in the [`#database-lab`](https://gitlab.slack.com/archives/CLJMDRD8C) channel on Slack.
+Unlike chatops, it gives you a way to execute DDL statements (like creating indexes and tables) and get query plan not only for `SELECT` but also `UPDATE` and `DELETE`.
+
+For example, in order to test new index you can do the following:
+
+Create the index:
+
+```
+exec CREATE INDEX index_projects_marked_for_deletion ON projects (marked_for_deletion_at) WHERE marked_for_deletion_at IS NOT NULL
+```
+
+Analyze the table to update its statistics:
+
+```
+exec ANALYZE projects
+```
+
+Get the query plan:
+
+```
+explain SELECT * FROM projects WHERE marked_for_deletion_at < CURRENT_DATE
+```
+
+Once done you can rollback your changes:
+
+```
+reset
+```
+
+For more information about the available options, run:
+
+```
+help
+```
+
## Further reading
A more extensive guide on understanding query plans can be found in
diff --git a/doc/development/utilities.md b/doc/development/utilities.md
index 38e416d68e4..25869a0d2b5 100644
--- a/doc/development/utilities.md
+++ b/doc/development/utilities.md
@@ -1,6 +1,6 @@
# GitLab utilities
-We developed a number of utilities to ease development.
+We have developed a number of utilities to help ease development:
## `MergeHash`
@@ -51,15 +51,15 @@ Refer to: <https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/utils/mer
Refer to <https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/utils/override.rb>:
-- This utility could help us check if a particular method would override
- another method or not. It has the same idea of Java's `@Override` annotation
- or Scala's `override` keyword. However we only do this check when
+- This utility can help you check if one method would override
+ another or not. It is the same concept as Java's `@Override` annotation
+ or Scala's `override` keyword. However, you should only do this check when
`ENV['STATIC_VERIFICATION']` is set to avoid production runtime overhead.
- This is useful to check:
+ This is useful for checking:
- - If we have typos in overriding methods.
- - If we renamed the overridden methods, making original overriding methods
- overrides nothing.
+ - If you have typos in overriding methods.
+ - If you renamed the overridden methods, which make the original override methods
+ irrelevant.
Here's a simple example:
@@ -100,11 +100,11 @@ Refer to <https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/utils/stro
- Memoize the value even if it is `nil` or `false`.
- We often do `@value ||= compute`, however this doesn't work well if
- `compute` might eventually give `nil` and we don't want to compute again.
- Instead we could use `defined?` to check if the value is set or not.
- However it's tedious to write such pattern, and `StrongMemoize` would
- help us use such pattern.
+ We often do `@value ||= compute`. However, this doesn't work well if
+ `compute` might eventually give `nil` and you don't want to compute again.
+ Instead you could use `defined?` to check if the value is set or not.
+ It's tedious to write such pattern, and `StrongMemoize` would
+ help you use such pattern.
Instead of writing patterns like this:
@@ -118,7 +118,7 @@ Refer to <https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/utils/stro
end
```
- We could write it like:
+ You could write it like:
``` ruby
class Find
@@ -151,7 +151,7 @@ and the cache key would be based on the class name, method name,
optionally customized instance level values, optionally customized
method level values, and optional method arguments.
-A simple example that only uses the instance level customised values:
+A simple example that only uses the instance level customised values is:
``` ruby
class UserAccess
@@ -169,8 +169,8 @@ end
This way, the result of `can_push_to_branch?` would be cached in
`RequestStore.store` based on the cache key. If `RequestStore` is not
-currently active, then it would be stored in a hash saved in an
-instance variable, so the cache logic would be the same.
+currently active, then it would be stored in a hash, and saved in an
+instance variable so the cache logic would be the same.
We can also set different strategies for different methods:
@@ -184,3 +184,83 @@ class Commit
request_cache(:author) { author_email }
end
```
+
+## `ReactiveCaching`
+
+The `ReactiveCaching` concern is used to fetch some data in the background and
+store it in the Rails cache, keeping it up-to-date for as long as it is being
+requested. If the data hasn't been requested for `reactive_cache_lifetime`,
+it will stop being refreshed, and then be removed.
+
+Example of use:
+
+```ruby
+class Foo < ApplicationRecord
+ include ReactiveCaching
+
+ after_save :clear_reactive_cache!
+
+ def calculate_reactive_cache
+ # Expensive operation here. The return value of this method is cached
+ end
+
+ def result
+ with_reactive_cache do |data|
+ # ...
+ end
+ end
+end
+```
+
+In this example, the first time `#result` is called, it will return `nil`.
+However, it will enqueue a background worker to call `#calculate_reactive_cache`
+and set an initial cache lifetime of ten minutes.
+
+The background worker needs to find or generate the object on which
+`with_reactive_cache` was called.
+The default behaviour can be overridden by defining a custom
+`reactive_cache_worker_finder`.
+Otherwise, the background worker will use the class name and primary key to get
+the object using the ActiveRecord `find_by` method.
+
+```ruby
+class Bar
+ include ReactiveCaching
+
+ self.reactive_cache_key = ->() { ["bar", "thing"] }
+ self.reactive_cache_worker_finder = ->(_id, *args) { from_cache(*args) }
+
+ def self.from_cache(var1, var2)
+ # This method will be called by the background worker with "bar1" and
+ # "bar2" as arguments.
+ new(var1, var2)
+ end
+
+ def initialize(var1, var2)
+ # ...
+ end
+
+ def calculate_reactive_cache
+ # Expensive operation here. The return value of this method is cached
+ end
+
+ def result
+ with_reactive_cache("bar1", "bar2") do |data|
+ # ...
+ end
+ end
+end
+```
+
+Each time the background job completes, it stores the return value of
+`#calculate_reactive_cache`. It is also re-enqueued to run again after
+`reactive_cache_refresh_interval`, therefore, it will keep the stored value up to date.
+Calculations are never run concurrently.
+
+Calling `#result` while a value is cached will call the block given to
+`#with_reactive_cache`, yielding the cached value. It will also extend the
+lifetime by the `reactive_cache_lifetime` value.
+
+Once the lifetime has expired, no more background jobs will be enqueued and
+calling `#result` will again return `nil` - starting the process all over
+again.
diff --git a/doc/gitlab-basics/README.md b/doc/gitlab-basics/README.md
index fc3d36910f2..258a85d0474 100644
--- a/doc/gitlab-basics/README.md
+++ b/doc/gitlab-basics/README.md
@@ -23,6 +23,7 @@ The following are guides to basic GitLab functionality:
- [Create a group](../user/group/index.md#create-a-new-group), to combine and administer
projects together.
- [Create a branch](create-branch.md), to make changes to files stored in a project's repository.
+- [Feature branch workflow](feature_branch_workflow.md).
- [Fork a project](fork-project.md), to duplicate projects so they can be worked on in parallel.
- [Add a file](add-file.md), to add new files to a project's repository.
- [Create an issue](../user/project/issues/managing_issues.md#create-a-new-issue),
@@ -30,7 +31,7 @@ The following are guides to basic GitLab functionality:
- [Create a merge request](add-merge-request.md), to request changes made in a branch
be merged into a project's repository.
- See how these features come together in the [GitLab Flow introduction video](https://youtu.be/InKNIvky2KE)
- and [GitLab Flow page](../workflow/gitlab_flow.md).
+ and [GitLab Flow page](../topics/gitlab_flow.md).
## Working with Git from the command line
diff --git a/doc/gitlab-basics/feature_branch_workflow.md b/doc/gitlab-basics/feature_branch_workflow.md
new file mode 100644
index 00000000000..2b641126d0d
--- /dev/null
+++ b/doc/gitlab-basics/feature_branch_workflow.md
@@ -0,0 +1,35 @@
+---
+disqus_identifier: 'https://docs.gitlab.com/ee/workflow/workflow.html'
+---
+
+# Feature branch workflow
+
+1. Clone project:
+
+ ```bash
+ git clone git@example.com:project-name.git
+ ```
+
+1. Create branch with your feature:
+
+ ```bash
+ git checkout -b $feature_name
+ ```
+
+1. Write code. Commit changes:
+
+ ```bash
+ git commit -am "My feature is ready"
+ ```
+
+1. Push your branch to GitLab:
+
+ ```bash
+ git push origin $feature_name
+ ```
+
+1. Review your code on commits page.
+
+1. Create a merge request.
+
+1. Your team lead will review the code &amp; merge it to the main branch.
diff --git a/doc/gitlab-basics/fork-project.md b/doc/gitlab-basics/fork-project.md
index 5c19985121d..e92491a0821 100644
--- a/doc/gitlab-basics/fork-project.md
+++ b/doc/gitlab-basics/fork-project.md
@@ -8,4 +8,4 @@ A fork is a copy of an original repository that you put in another namespace
where you can experiment and apply changes that you can later decide whether or
not to share, without affecting the original project.
-It takes just a few steps to [fork a project in GitLab](../workflow/forking_workflow.md#creating-a-fork).
+It takes just a few steps to [fork a project in GitLab](../user/project/repository/forking_workflow.md#creating-a-fork).
diff --git a/doc/gitlab-basics/start-using-git.md b/doc/gitlab-basics/start-using-git.md
index 05329993c64..1f43b151d5d 100644
--- a/doc/gitlab-basics/start-using-git.md
+++ b/doc/gitlab-basics/start-using-git.md
@@ -287,7 +287,7 @@ git reset HEAD~1
This leaves the changed files and folders unstaged in your local repository.
CAUTION: **Warning:**
-A Git commit should not usually be reverse, particularly if you already pushed it
+A Git commit should not usually be reversed, particularly if you already pushed it
to the remote repository. Although you can undo a commit, the best option is to avoid
the situation altogether by working carefully.
diff --git a/doc/install/README.md b/doc/install/README.md
index b906deadca9..441826687aa 100644
--- a/doc/install/README.md
+++ b/doc/install/README.md
@@ -7,7 +7,7 @@ type: index
# Installation **(CORE ONLY)**
GitLab can be installed in most GNU/Linux distributions and in a number
-of cloud providers. To get the best experience from GitLab you need to balance
+of cloud providers. To get the best experience from GitLab, you need to balance
performance, reliability, ease of administration (backups, upgrades and troubleshooting),
and cost of hosting.
diff --git a/doc/install/aws/index.md b/doc/install/aws/index.md
index 2dea763688e..c1dde05196c 100644
--- a/doc/install/aws/index.md
+++ b/doc/install/aws/index.md
@@ -539,7 +539,7 @@ which would otherwise take much space.
In particular, you can store in S3:
-- [The Git LFS objects](../../workflow/lfs/lfs_administration.md#s3-for-omnibus-installations) ((Omnibus GitLab installations))
+- [The Git LFS objects](../../administration/lfs/lfs_administration.md#s3-for-omnibus-installations) ((Omnibus GitLab installations))
- [The Container Registry images](../../administration/packages/container_registry.md#container-registry-storage-driver) (Omnibus GitLab installations)
- [The GitLab CI/CD job artifacts](../../administration/job_artifacts.md#using-object-storage) (Omnibus GitLab installations)
diff --git a/doc/install/installation.md b/doc/install/installation.md
index dd4b5544659..98094ca1185 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -13,7 +13,7 @@ If you want to install on RHEL/CentOS, we recommend using the
[Omnibus packages](https://about.gitlab.com/install/).
This guide is long because it covers many cases and includes all commands you
-need, this is [one of the few installation scripts that actually works out of the box](https://twitter.com/robinvdvleuten/status/424163226532986880).
+need, this is [one of the few installation scripts that actually work out of the box](https://twitter.com/robinvdvleuten/status/424163226532986880).
The following steps have been known to work. **Use caution when you deviate**
from this guide. Make sure you don't violate any assumptions GitLab makes about
its environment. For example, many people run into permission problems because
@@ -35,7 +35,7 @@ After this termination runit will detect Sidekiq is not running and will start i
Since installations from source don't use runit for process supervision, Sidekiq
can't be terminated and its memory usage will grow over time.
-## Select version to install
+## Select a version to install
Make sure you view [this installation guide](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/install/installation.md) from the branch (version) of GitLab you would like to install (e.g., `11-7-stable`).
You can select the branch in the version dropdown in the top left corner of GitLab (below the menu bar).
@@ -56,7 +56,7 @@ of this page:
| |-- repositories
```
-- `/home/git/.ssh` - Contains OpenSSH settings. Specifically the `authorized_keys`
+- `/home/git/.ssh` - Contains OpenSSH settings. Specifically, the `authorized_keys`
file managed by GitLab Shell.
- `/home/git/gitlab` - GitLab core software.
- `/home/git/gitlab-shell` - Core add-on component of GitLab. Maintains SSH
@@ -183,7 +183,7 @@ sudo make prefix=/usr/local install
# When editing config/gitlab.yml (Step 5), change the git -> bin_path to /usr/local/bin/git
```
-For the [Custom Favicon](../customization/favicon.md) to work, GraphicsMagick
+For the [Custom Favicon](../user/admin_area/appearance.md#favicon) to work, GraphicsMagick
needs to be installed.
```sh
@@ -315,7 +315,7 @@ use of extensions and concurrent index removal, you need at least PostgreSQL 9.2
sudo -u postgres psql -d template1 -c "CREATE EXTENSION IF NOT EXISTS pg_trgm;"
```
-1. Create the GitLab production database and grant all privileges on database:
+1. Create the GitLab production database and grant all privileges on the database:
```sh
sudo -u postgres psql -d template1 -c "CREATE DATABASE gitlabhq_production OWNER git;"
@@ -397,7 +397,7 @@ sudo usermod -aG redis git
## 8. GitLab
```sh
-# We'll install GitLab into home directory of the user "git"
+# We'll install GitLab into the home directory of the user "git"
cd /home/git
```
@@ -424,7 +424,7 @@ cd /home/git/gitlab
# Copy the example GitLab config
sudo -u git -H cp config/gitlab.yml.example config/gitlab.yml
-# Update GitLab config file, follow the directions at top of file
+# Update GitLab config file, follow the directions at top of the file
sudo -u git -H editor config/gitlab.yml
# Copy the example secrets file
@@ -465,7 +465,7 @@ nproc
# Enable cluster mode if you expect to have a high load instance
# Set the number of workers to at least the number of cores
-# Ex. change amount of workers to 3 for 2GB RAM server
+# Ex. change the amount of workers to 3 for 2GB RAM server
sudo -u git -H editor config/unicorn.rb
# Copy the example Rack attack config
@@ -588,7 +588,7 @@ You can specify a different Git repository by providing it as an extra parameter
sudo -u git -H bundle exec rake "gitlab:workhorse:install[/home/git/gitlab-workhorse,https://example.com/gitlab-workhorse.git]" RAILS_ENV=production
```
-### Install GitLab-Elasticsearch-indexer`
+### Install GitLab-Elasticsearch-indexer
GitLab-Elasticsearch-Indexer uses [GNU Make](https://www.gnu.org/software/make/). The
following command-line will install GitLab-Elasticsearch-Indexer in `/home/git/gitlab-elasticsearch-indexer`
@@ -670,7 +670,7 @@ sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production
# or you can skip the question by adding force=yes
sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production force=yes
-# When done you see 'Administrator account created:'
+# When done, you see 'Administrator account created:'
```
NOTE: **Note:**
@@ -684,7 +684,7 @@ sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production GITLAB_ROOT_PA
The `secrets.yml` file stores encryption keys for sessions and secure variables.
Backup `secrets.yml` someplace safe, but don't store it in the same place as your database backups.
-Otherwise your secrets are exposed if one of your backups is compromised.
+Otherwise, your secrets are exposed if one of your backups is compromised.
### Install Init Script
@@ -835,7 +835,7 @@ initial administrator account. Enter your desired password and you'll be
redirected back to the login screen.
The default account's username is **root**. Provide the password you created
-earlier and login. After login you can change the username if you wish.
+earlier and login. After login, you can change the username if you wish.
**Enjoy!**
@@ -905,7 +905,7 @@ for the changes to take effect.
### Custom Redis Connection
-If you'd like to connect to a Redis server on a non-standard port or on a different host, you can configure its connection string via the `config/resque.yml` file.
+If you'd like to connect to a Redis server on a non-standard port or a different host, you can configure its connection string via the `config/resque.yml` file.
```
# example
@@ -921,7 +921,7 @@ production:
url: unix:/path/to/redis/socket
```
-Also you can use environment variables in the `config/resque.yml` file:
+Also, you can use environment variables in the `config/resque.yml` file:
```
# example
diff --git a/doc/install/openshift_and_gitlab/index.md b/doc/install/openshift_and_gitlab/index.md
index 010e56fb097..181d4414a9b 100644
--- a/doc/install/openshift_and_gitlab/index.md
+++ b/doc/install/openshift_and_gitlab/index.md
@@ -23,8 +23,6 @@ tools that will help us achieve our goal.
For a video demonstration on installing GitLab on OpenShift, check the article [In 13 minutes from Kubernetes to a complete application development tool](https://about.gitlab.com/blog/2016/11/14/idea-to-production/).
----
-
## Prerequisites
CAUTION: **Caution:** This information is no longer up to date, as the current versions
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index 8b53ee7c3e1..ecd6516bd2e 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -35,7 +35,7 @@ Please see the [installation from source guide](installation.md) and the [instal
### Microsoft Windows
GitLab is developed for Linux-based operating systems.
-It does **not** run on Microsoft Windows, and we have no plans to support it in the near future. For the latest development status view this [issue](https://gitlab.com/gitlab-org/gitlab-foss/issues/46567).
+It does **not** run on Microsoft Windows, and we have no plans to support it in the near future. For the latest development status view this [issue](https://gitlab.com/gitlab-org/gitlab/issues/22337).
Please consider using a virtual machine to run GitLab.
## Ruby versions
diff --git a/doc/integration/README.md b/doc/integration/README.md
index 3a08303bf20..3f33aa94cb9 100644
--- a/doc/integration/README.md
+++ b/doc/integration/README.md
@@ -2,45 +2,71 @@
comments: false
---
-# GitLab Integration
-
-GitLab integrates with multiple third-party services to allow external issue
-trackers and external authentication.
-
-See the documentation below for details on how to configure these services.
-
-- [Akismet](akismet.md) Configure Akismet to stop spam
-- [Auth0 OmniAuth](auth0.md) Enable the Auth0 OmniAuth provider
-- [Bitbucket](bitbucket.md) Import projects from Bitbucket.org and login to your GitLab instance with your Bitbucket.org account
-- [CAS](cas.md) Configure GitLab to sign in using CAS
-- [External issue tracker](external-issue-tracker.md) Redmine, Jira, etc.
-- [Gmail actions buttons](gmail_action_buttons_for_gitlab.md) Adds GitLab actions to messages
-- [Jenkins](jenkins.md) Integrate with the Jenkins CI
-- [Jira](../user/project/integrations/jira.md) Integrate with the Jira issue tracker
-- [Kerberos](kerberos.md) Integrate with Kerberos
-- [LDAP](ldap.md) Set up sign in via LDAP
-- [OAuth2 provider](oauth_provider.md) OAuth2 application creation
-- [OmniAuth](omniauth.md) Sign in via Twitter, GitHub, GitLab.com, Google, Bitbucket, Facebook, Shibboleth, SAML, Crowd, Azure and Authentiq ID
-- [OpenID Connect](openid_connect_provider.md) Use GitLab as an identity provider
-- [PlantUML](../administration/integration/plantuml.md) Configure PlantUML to use diagrams in AsciiDoc documents.
-- [reCAPTCHA](recaptcha.md) Configure GitLab to use Google reCAPTCHA for new users
-- [SAML](saml.md) Configure GitLab as a SAML 2.0 Service Provider
-- [Trello](trello_power_up.md) Integrate Trello with GitLab
-
-> GitLab Enterprise Edition contains [advanced Jenkins support](jenkins.md).
+# GitLab integrations
+
+GitLab can be integrated with external services for enhanced functionality.
+
+## Issue trackers
+
+You can use an [external issue tracker](external-issue-tracker.md) at the same time as the GitLab issue tracker, or use only the external issue tracker.
+
+GitLab can be integrated with the following external issue trackers:
+
+- Jira
+- Redmine
+- Bugzilla
+- YouTrack
+
+## Authentication sources
+
+GitLab can be configured to authenticate access requests with the following authentication sources:
+
+- Enable the [Auth0 OmniAuth](auth0.md) provider.
+- Enable sign in with [Bitbucket](bitbucket.md) accounts.
+- Configure GitLab to sign in using [CAS](cas.md).
+- Integrate with [Kerberos](kerberos.md).
+- Enable sign in via [LDAP](ldap.md).
+- Enable [OAuth2 provider](oauth_provider.md) application creation.
+- Use [OmniAuth](omniauth.md) to enable sign in via Twitter, GitHub, GitLab.com, Google,
+Bitbucket, Facebook, Shibboleth, SAML, Crowd, Azure or Authentiq ID.
+- Use GitLab as an [OpenID Connect](openid_connect_provider.md) identity provider.
+- Configure GitLab as a [SAML](saml.md) 2.0 Service Provider.
+
+## Security enhancements
+
+GitLab can be integrated with the following external services to enhance security:
+
+- [Akismet](akismet.md) helps reduce spam.
+- Google [reCAPTCHA](recaptcha.md) helps verify new users.
+
+GitLab also provides features to improve the security of your own application. For more details see [GitLab Secure](../user/application_security/index.md).
+
+## Continuous integration
+
+GitLab can be integrated with the following external service for continuous integration:
+
+- [Jenkins](jenkins.md) CI. **(STARTER)**
+
+## Feature enhancements
+
+GitLab can be integrated with the following enhancements:
+
+- Add GitLab actions to [Gmail actions buttons](gmail_action_buttons_for_gitlab.md).
+- Configure [PlantUML](../administration/integration/plantuml.md) to use diagrams in AsciiDoc documents.
+- Attach merge requests to [Trello](trello_power_up.md) cards.
+- Enable integrated code intelligence powered by [Sourcegraph](sourcegraph.md).
## Project services
-Integration with services such as Campfire, Flowdock, HipChat,
-Pivotal Tracker, and Slack are available in the form of a [Project Service][].
+Integration with services such as Campfire, Flowdock, HipChat, Pivotal Tracker, and Slack are available as [Project Services](../user/project/integrations/project_services.md).
+
+## Troubleshooting
-[Project Service]: ../user/project/integrations/project_services.md
+### SSL certificate errors
-## SSL certificate errors
+When trying to integrate GitLab with services that are using self-signed certificates, it is very likely that SSL certificate errors will occur in different parts of the application, most likely Sidekiq.
-When trying to integrate GitLab with services that are using self-signed certificates,
-it is very likely that SSL certificate errors will occur on different parts of the
-application, most likely Sidekiq. There are 2 approaches you can take to solve this:
+There are two approaches you can take to solve this:
1. Add the root certificate to the trusted chain of the OS.
1. If using Omnibus, you can add the certificate to GitLab's trusted certificates.
@@ -61,12 +87,12 @@ in to GitLab Omnibus.
It is enough to concatenate the certificate to the main trusted certificate
however it may be overwritten during upgrades:
-```bash
+```shell
cat jira.pem >> /opt/gitlab/embedded/ssl/certs/cacert.pem
```
After that restart GitLab with:
-```bash
+```shell
sudo gitlab-ctl restart
```
diff --git a/doc/integration/bitbucket.md b/doc/integration/bitbucket.md
index 63ffa69e606..7cead234709 100644
--- a/doc/integration/bitbucket.md
+++ b/doc/integration/bitbucket.md
@@ -24,7 +24,7 @@ Bitbucket.org.
GitLab 8.15 significantly simplified the way to integrate Bitbucket.org with
GitLab. You are encouraged to upgrade your GitLab instance if you haven't done so
already. If you're using GitLab 8.14 or below, [use the previous integration
-docs][bb-old].
+docs](https://gitlab.com/gitlab-org/gitlab/blob/8-14-stable-ee/doc/integration/bitbucket.md).
To enable the Bitbucket OmniAuth provider you must register your application
with Bitbucket.org. Bitbucket will generate an application ID and secret key for
@@ -135,9 +135,6 @@ GitLab and [start importing your projects][bb-import].
If you want to import projects from Bitbucket, but don't want to enable signing in,
you can [disable Sign-Ins in the admin panel](omniauth.md#enable-or-disable-sign-in-with-an-omniauth-provider-without-disabling-import-sources).
-[init-oauth]: omniauth.md#initial-omniauth-configuration
-[bb-import]: ../workflow/importing/import_projects_from_bitbucket.md
-[bb-old]: https://gitlab.com/gitlab-org/gitlab/blob/8-14-stable/doc/integration/bitbucket.md
-[bitbucket-docs]: https://confluence.atlassian.com/bitbucket/use-the-ssh-protocol-with-bitbucket-cloud-221449711.html#UsetheSSHprotocolwithBitbucketCloud-KnownhostorBitbucket%27spublickeyfingerprints
+[bb-import]: ../user/project/import/bitbucket.md
[reconfigure GitLab]: ../administration/restart_gitlab.md#omnibus-gitlab-reconfigure
[restart]: ../administration/restart_gitlab.md#installations-from-source
diff --git a/doc/integration/elasticsearch.md b/doc/integration/elasticsearch.md
index da53987ce1b..5c77bd5bcd9 100644
--- a/doc/integration/elasticsearch.md
+++ b/doc/integration/elasticsearch.md
@@ -583,3 +583,12 @@ Here are some common pitfalls and how to overcome them:
AWS has [fixed limits](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/aes-limits.html)
for this setting ("Maximum Size of HTTP Request Payloads"), based on the size of
the underlying instance.
+
+### Reverting to basic search
+
+Sometimes there may be issues with your Elasticsearch index data and as such
+GitLab will allow you to revert to "basic search" when there are no search
+results and assuming that basic search is supported in that scope. This "basic
+search" will behave as though you don't have Elasticsearch enabled at all for
+your instance and search using other data sources (ie. Postgres data and Git
+data).
diff --git a/doc/integration/img/sourcegraph_admin_v12_5.png b/doc/integration/img/sourcegraph_admin_v12_5.png
new file mode 100644
index 00000000000..23e38f56619
--- /dev/null
+++ b/doc/integration/img/sourcegraph_admin_v12_5.png
Binary files differ
diff --git a/doc/integration/img/sourcegraph_demo_v12_5.png b/doc/integration/img/sourcegraph_demo_v12_5.png
new file mode 100644
index 00000000000..c70448c0a8a
--- /dev/null
+++ b/doc/integration/img/sourcegraph_demo_v12_5.png
Binary files differ
diff --git a/doc/integration/img/sourcegraph_popover_v12_5.png b/doc/integration/img/sourcegraph_popover_v12_5.png
new file mode 100644
index 00000000000..878d6143646
--- /dev/null
+++ b/doc/integration/img/sourcegraph_popover_v12_5.png
Binary files differ
diff --git a/doc/integration/img/sourcegraph_user_preferences_v12_5.png b/doc/integration/img/sourcegraph_user_preferences_v12_5.png
new file mode 100644
index 00000000000..2c0e138e296
--- /dev/null
+++ b/doc/integration/img/sourcegraph_user_preferences_v12_5.png
Binary files differ
diff --git a/doc/integration/saml.md b/doc/integration/saml.md
index b72be55aca3..099cab0f5b8 100644
--- a/doc/integration/saml.md
+++ b/doc/integration/saml.md
@@ -572,7 +572,7 @@ installations from source. Restart Unicorn using the `sudo gitlab-ctl restart un
command on Omnibus installations and `sudo service gitlab restart` on installations
from source.
-You may also find the [SSO Tracer](https://addons.mozilla.org/en-US/firefox/addon/sso-tracer/)
+You may also find the [SAML Tracer](https://addons.mozilla.org/en-US/firefox/addon/saml-tracer/)
(Firefox) and [SAML Chrome Panel](https://chrome.google.com/webstore/detail/saml-chrome-panel/paijfdbeoenhembfhkhllainmocckace)
(Chrome) browser extensions useful in your debugging.
diff --git a/doc/integration/slash_commands.md b/doc/integration/slash_commands.md
index b8842ef3a43..bc2f190920c 100644
--- a/doc/integration/slash_commands.md
+++ b/doc/integration/slash_commands.md
@@ -18,6 +18,7 @@ Taking the trigger term as `project-name`, the commands are:
| `/project-name issue close <id>` | Closes the issue with id `<id>` |
| `/project-name issue search <query>` | Shows up to 5 issues matching `<query>` |
| `/project-name issue move <id> to <project>` | Moves issue ID `<id>` to `<project>` |
+| `/project-name issue comment <id> <shift+return> <comment>` | Adds a new comment to an issue with id `<id>` and comment body `<comment>` |
| `/project-name deploy <from> to <to>` | Deploy from the `<from>` environment to the `<to>` environment |
| `/project-name run <job name> <arguments>` | Execute [ChatOps](../ci/chatops/README.md) job `<job name>` on `master` |
diff --git a/doc/integration/sourcegraph.md b/doc/integration/sourcegraph.md
new file mode 100644
index 00000000000..5e7cbdfbac3
--- /dev/null
+++ b/doc/integration/sourcegraph.md
@@ -0,0 +1,128 @@
+---
+type: reference, how-to
+---
+
+# Sourcegraph integration
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/16556) in GitLab 12.5. Please note that this integration is in BETA and [behind a feature flag](#enable-the-sourcegraph-feature-flag).
+
+[Sourcegraph](https://sourcegraph.com) provides code intelligence features, natively integrated into the GitLab UI.
+
+For GitLab.com users, see [Sourcegraph for GitLab.com](#sourcegraph-for-gitlabcom).
+
+![Sourcegraph demo](img/sourcegraph_demo_v12_5.png)
+
+<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
+For an overview, watch the video [Sourcegraph's new GitLab native integration](https://www.youtube.com/watch?v=LjVxkt4_sEA).
+
+NOTE: **Note:**
+This feature requires user opt-in. After Sourcegraph has been enabled for your GitLab instance,
+you can choose to enable Sourcegraph [through your user preferences](#enable-sourcegraph-in-user-preferences).
+
+## Set up for self-managed GitLab instances **(CORE ONLY)**
+
+Before you can enable Sourcegraph code intelligence in GitLab you will need to:
+
+- Enable the `sourcegraph` feature flag for your GitLab instance.
+- Configure a Sourcegraph instance with your GitLab instance as an external service.
+
+### Enable the Sourcegraph feature flag
+
+NOTE: **Note:**
+If you are running a self-managed instance, the Sourcegraph integration will not be available
+unless the feature flag `sourcegraph` is enabled. This can be done from the Rails console
+by instance administrators.
+
+Use these commands to start the Rails console:
+
+```sh
+# Omnibus GitLab
+gitlab-rails console
+
+# Installation from source
+cd /home/git/gitlab
+sudo -u git -H bin/rails console RAILS_ENV=production
+```
+
+Then run the following command to enable the feature flag:
+
+```
+Feature.enable(:sourcegraph)
+```
+
+You can also enable the feature flag only for specific projects with:
+
+```
+Feature.enable(:sourcegraph, Project.find_by_full_path('my_group/my_project'))
+```
+
+### Set up a self-managed Sourcegraph instance
+
+If you are new to Sourcegraph, head over to the [Sourcegraph installation documentation](https://docs.sourcegraph.com/admin) and get your instance up and running.
+
+### Connect your Sourcegraph instance to your GitLab instance
+
+1. Navigate to the site admin area in Sourcegraph.
+1. [Configure your GitLab external service](https://docs.sourcegraph.com/admin/external_service/gitlab).
+You can skip this step if you already have your GitLab repositories searchable in Sourcegraph.
+1. Validate that you can search your repositories from GitLab in your Sourcegraph instance by running a test query.
+1. Add your GitLab instance URL to the [`corsOrigin` setting](https://docs.sourcegraph.com/admin/config/site_config#corsOrigin) in your site configuration.
+
+### Configure your GitLab instance with Sourcegraph
+
+1. In GitLab, go to **Admin Area > Settings > Integrations**.
+1. Expand the **Sourcegraph** configuration section.
+1. Check **Enable Sourcegraph**.
+1. Set the Sourcegraph URL to your Sourcegraph instance, e.g., `https://sourcegraph.example.com`.
+
+![Sourcegraph admin settings](img/sourcegraph_admin_v12_5.png)
+
+## Enable Sourcegraph in user preferences
+
+If a GitLab administrator has enabled Sourcegraph, you can enable this feature in your user preferences.
+
+1. In GitLab, click your avatar in the top-right corner, then click **Settings**. On the left-hand nav, click **Preferences**.
+1. Under **Integrations**, find the **Sourcegraph** section.
+1. Check **Enable Sourcegraph**.
+
+![Sourcegraph user preferences](img/sourcegraph_user_preferences_v12_5.png)
+
+## Using Sourcegraph code intelligence
+
+Once enabled, participating projects will have a code intelligence popover available in
+the following code views:
+
+- Merge request diffs
+- Commit view
+- File view
+
+When visiting one of these views, you can now hover over a code reference to see a popover with:
+
+- Details on how this reference was defined.
+- **Go to definition**, which navigates to the line of code where this reference was defined.
+- **Find references**, which navigates to the configured Sourcegraph instance, showing a list of references to the hilighted code.
+
+![Sourcegraph demo](img/sourcegraph_popover_v12_5.png)
+
+## Sourcegraph for GitLab.com
+
+Sourcegraph powered code intelligence will be incrementally rolled out on GitLab.com.
+It will eventually become available for all public projects, but for now, it is only
+available for some specific [`gitlab-org` projects](https://gitlab.com/gitlab-org/).
+This means that you can see it working and use it to dig into the code of these projects,
+but you cannot use it on your own project on GitLab.com yet.
+
+If you would like to use it in your own projects as of GitLab 12.5, you can do so by
+setting up a self-managed GitLab instance.
+
+Follow the epic [&2201](https://gitlab.com/groups/gitlab-org/-/epics/2201) for
+updates.
+
+## Sourcegraph and Privacy
+
+From Sourcegraph's [extension documentation](https://docs.sourcegraph.com/integration/browser_extension#privacy) which is the
+engine behind the native GitLab integration:
+
+> Sourcegraph integrations never send any logs, pings, usage statistics, or telemetry to Sourcegraph.com.
+> They will only connect to Sourcegraph.com as required to provide code intelligence or other functionality on public code.
+> As a result, no private code, private repository names, usernames, or any other specific data is sent to Sourcegraph.com.
diff --git a/doc/integration/ultra_auth.md b/doc/integration/ultra_auth.md
index fb950ba989a..83b2d7fe096 100644
--- a/doc/integration/ultra_auth.md
+++ b/doc/integration/ultra_auth.md
@@ -8,7 +8,7 @@ To enable UltraAuth OmniAuth provider, you must use UltraAuth's credentials for
To get the credentials (a pair of Client ID and Client Secret), you must register an application on UltraAuth.
1. Sign in to [UltraAuth](https://ultraauth.com).
-1. Navigate to [Create an App](https://ultraauth.com/select-strategy) and click on "Ruby on Rails".
+1. Navigate to **Create an App** and click on **Ruby on Rails**.
1. Scroll down the page that is displayed to locate the **Client ID** and **Client Secret**.
Keep this page open as you continue configuration.
diff --git a/doc/intro/README.md b/doc/intro/README.md
index 33b23372280..58cb11423d5 100644
--- a/doc/intro/README.md
+++ b/doc/intro/README.md
@@ -18,13 +18,13 @@ Create issues, labels, milestones, cast your vote, and review issues.
- [Create an issue](../user/project/issues/managing_issues.md#create-a-new-issue)
- [Assign labels to issues](../user/project/labels.md)
- [Use milestones as an overview of your project's tracker](../user/project/milestones/index.md)
-- [Use voting to express your like/dislike to issues and merge requests](../workflow/award_emoji.md)
+- [Use voting to express your like/dislike to issues and merge requests](../user/award_emojis.md)
## Collaborate
Create merge requests and review code.
-- [Fork a project and contribute to it](../workflow/forking_workflow.md)
+- [Fork a project and contribute to it](../user/project/repository/forking_workflow.md)
- [Create a new merge request](../gitlab-basics/add-merge-request.md)
- [Automatically close issues from merge requests](../user/project/issues/managing_issues.md#closing-issues-automatically)
- [Automatically merge when pipeline succeeds](../user/project/merge_requests/merge_when_pipeline_succeeds.md)
diff --git a/doc/policy/maintenance.md b/doc/policy/maintenance.md
index d118c2f40cb..ef94236d711 100644
--- a/doc/policy/maintenance.md
+++ b/doc/policy/maintenance.md
@@ -30,21 +30,68 @@ The following table describes the version types and their release cadence:
## Patch releases
-Patch releases usually only include bug fixes and are only done for the current
-stable release. That said, in some cases, we may backport it to previous stable
+Our current policy is to support **only the current stable release** at any given time.
+
+Patch releases **only include bug fixes** for the current stable released version of
+GitLab.
+
+These two policies are in place because:
+
+1. GitLab has Community and Enterprise distributions, doubling the amount of work
+necessary to test/release the software.
+1. Backporting to more than one release creates a high development, quality assurance,
+and support cost.
+1. Supporting parallel version discourages incremental upgrades which over time accumulate in
+complexity and create upgrade challenges for all users. GitLab has a dedicated team ensuring that
+incremental upgrades (and installations) are as simple as possible.
+1. The number of changes created in the GitLab application is high, which contributes to backporting complexity to older releases. In number of cases, backporting has to go through the same
+review process a new change goes through.
+1. Ensuring that tests pass on older release is a considerable challenge in some cases, and as such is very time consuming.
+
+Including new features in patch releases is not possible as that would break [Semantic Versioning].
+Breaking [Semantic Versioning] has the following consequences for users that
+have to adhere to various internal requirements (e.g. org. compliance, verifying new features and similar):
+
+1. Inability to quickly upgrade to leverage bug fixes included in patch versions.
+1. Inability to quickly upgrade to leverage security fixes included in patch versions.
+1. Requirements consisting of extensive testing for not only stable GitLab release, but every patch version.
+
+In cases where a strategic user has a requirement to test a feature before it is
+officially released, we can offer to create a Release Candidate (RC) version that will
+include the specific feature. This should be needed only in extreme cases, and can be requested for consideration by raising an issue in [release/tasks] issue tracker.
+It is important to note that the Release Candidate will also contain other
+features and changes as it is not possible to easily isolate a specific feature (similar reasons as noted above). The Release Candidate will be no different than any code that is deployed to GitLab.com or is publicly accessible.
+
+### Backporting to older releases
+
+Backporting to more than one stable release is reserved for [security releases](#security-releases).
+In some cases however, we may need to backport *a bug fix* to more than one stable
release, depending on the severity of the bug.
-For instance, if we release `10.1.1` with a fix for a severe bug introduced in
-`10.0.0`, we could backport the fix to a new `10.0.x` patch release.
+Decision on whether backporting a change will be performed is done at the discretion of the [current release managers][release-managers], similar to what is described in the [managing bugs] process, based on *all* of the following:
+
+1. Estimated [severity][severity-labels] of the bug: Highest possible impact to users based on the current definition of severity.
+
+1. Estimated [priority][priority-labels] of the bug: Immediate impact on all impacted users based on the above estimated severity.
+
+1. Potentially incurring data loss and/or security breach.
+
+1. Potentially affecting one or more strategic accounts due to a proven inability by the user to upgrade to the current stable version.
+
+If *all* of the above are satisfied, the backport releases can be created for
+the current stable stable release, and two previous monthly releases.
+For instance, if we release `11.2.1` with a fix for a severe bug introduced in
+`11.0.0`, we could backport the fix to a new `11.0.x`, and `11.1.x` patch release.
+
+To request backporting to more than one stable release for consideration, raise an issue in [release/tasks] issue tracker.
### Security releases
Security releases are a special kind of patch release that only include security
fixes and patches (see below).
-Our current policy is to support one stable release at any given time, but for
-medium-level security issues, we may backport security fixes to the previous two
-monthly releases.
+Our current policy is to backport security fixes to the previous two
+monthly releases in addition to the current stable release.
For very serious security issues, there is
[precedent](https://about.gitlab.com/blog/2016/05/02/cve-2016-4340-patches/)
@@ -91,3 +138,9 @@ Please see the table below for some examples:
More information about the release procedures can be found in our
[release documentation](https://gitlab.com/gitlab-org/release/docs). You may also want to read our
[Responsible Disclosure Policy](https://about.gitlab.com/security/disclosure/).
+
+[release-managers]: https://about.gitlab.com/community/release-managers/
+[priority-definition]: ../development/contributing/issue_workflow.md#priority-labels
+[severity-labels]: ../development/contributing/issue_workflow.html#severity-labels
+[managing bugs]: https://gitlab.com/gitlab-org/gitlab/blob/master/PROCESS.md#managing-bugs
+[release/tasks]: https://gitlab.com/gitlab-org/release/tasks/issues
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index fe9617c75ad..006e998b1ab 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -877,7 +877,7 @@ including (but not restricted to):
- [Custom Pages domains](../user/project/pages/custom_domains_ssl_tls_certification/index.md)
- [Project error tracking](../user/project/operations/error_tracking.md)
- [Runner authentication](../ci/runners/README.md)
-- [Project mirroring](../workflow/repository_mirroring.md)
+- [Project mirroring](../user/project/repository/repository_mirroring.md)
- [Web hooks](../user/project/integrations/webhooks.md)
In cases like CI/CD variables and Runner authentication, you might
diff --git a/doc/raketasks/cleanup.md b/doc/raketasks/cleanup.md
index 67bf7cbd828..937f15554b4 100644
--- a/doc/raketasks/cleanup.md
+++ b/doc/raketasks/cleanup.md
@@ -88,7 +88,7 @@ gitlab-rake gitlab:cleanup:orphan_job_artifact_files DRY_RUN=false
You can also limit the number of files to delete with `LIMIT`:
```shell
-gitlab-rake gitlab:cleanup:orphan_job_artifact_files LIMIT=100`
+gitlab-rake gitlab:cleanup:orphan_job_artifact_files LIMIT=100
```
This will only delete up to 100 files from disk. You can use this to
diff --git a/doc/security/webhooks.md b/doc/security/webhooks.md
index b9af1ac108f..cb9ad2b694c 100644
--- a/doc/security/webhooks.md
+++ b/doc/security/webhooks.md
@@ -9,19 +9,24 @@ local network, these may be vulnerable to exploitation via Webhooks.
With [Webhooks](../user/project/integrations/webhooks.md), you and your project
maintainers and owners can set up URLs to be triggered when specific changes
-occur in your projects. Normally, these requests are sent to external web services
-specifically set up for this purpose, that process the request and its attached
-data in some appropriate way.
+occur in your projects. Normally, these requests are sent to external web
+services specifically set up for this purpose, that process the request and its
+attached data in some appropriate way.
Things get hairy, however, when a Webhook is set up with a URL that doesn't
point to an external, but to an internal service, that may do something
completely unintended when the webhook is triggered and the POST request is
sent.
-Because Webhook requests are made by the GitLab server itself, these have
-complete access to everything running on the server (`http://localhost:123`) or
-within the server's local network (`http://192.168.1.12:345`), even if these
-services are otherwise protected and inaccessible from the outside world.
+Webhook requests are made by the GitLab server itself and use a single
+(optional) secret token per hook for authorization (instead of a user or
+repo-specific token). As a result, these may have broader access than
+intended to everything running on the server hosting the webhook (which
+may include the GitLab server or API itself, e.g., `http://localhost:123`).
+Depending on the called webhook, this may also result in network access
+to other servers within that webhook server's local network (e.g.,
+`http://192.168.1.12:345`), even if these services are otherwise protected
+and inaccessible from the outside world.
If a web service does not require authentication, Webhooks can be used to
trigger destructive commands by getting the GitLab server to make POST requests
diff --git a/doc/ssh/README.md b/doc/ssh/README.md
index 07b426b7f28..01d86331a0a 100644
--- a/doc/ssh/README.md
+++ b/doc/ssh/README.md
@@ -51,7 +51,7 @@ GitLab supports RSA, DSA, ECDSA, and ED25519 keys. Their difference lies on
the signing algorithm, and some of them have advantages over the others. For
more information, you can read this
[nice article on ArchWiki](https://wiki.archlinux.org/index.php/SSH_keys#Choosing_the_authentication_key_type).
-We'll focus on ED25519 and RSA and here.
+We'll focus on ED25519 and RSA here.
NOTE: **Note:**
As an admin, you can [restrict which keys should be permitted and their minimum length](../security/ssh_keys_restrictions.md).
diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md
index a1373639a87..93549ac4de5 100644
--- a/doc/topics/autodevops/index.md
+++ b/doc/topics/autodevops/index.md
@@ -95,58 +95,85 @@ Auto DevOps.
To make full use of Auto DevOps, you will need:
+- **Kubernetes** (for Auto Review Apps, Auto Deploy, and Auto Monitoring)
+
+ To enable deployments, you will need:
+
+ 1. A [Kubernetes 1.12+ cluster](../../user/project/clusters/index.md) for the project. The easiest
+ way is to add a [new cluster using the GitLab UI](../../user/project/clusters/add_remove_clusters.md#add-new-cluster).
+ 1. NGINX Ingress. You can deploy it to your Kubernetes cluster by installing
+ the [GitLab-managed app for Ingress](../../user/clusters/applications.md#ingress),
+ once you have configured GitLab's Kubernetes integration in the previous step.
+
+ Alternatively, you can use the
+ [`nginx-ingress`](https://github.com/helm/charts/tree/master/stable/nginx-ingress)
+ Helm chart to install Ingress manually.
+
+ NOTE: **Note:**
+ If you are using your own Ingress instead of the one provided by GitLab's managed
+ apps, ensure you are running at least version 0.9.0 of NGINX Ingress and
+ [enable Prometheus metrics](https://github.com/helm/charts/tree/master/stable/nginx-ingress#prometheus-metrics)
+ in order for the response metrics to appear. You will also have to
+ [annotate](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/)
+ the NGINX Ingress deployment to be scraped by Prometheus using
+ `prometheus.io/scrape: "true"` and `prometheus.io/port: "10254"`.
+
+- **Base domain** (for Auto Review Apps, Auto Deploy, and Auto Monitoring)
+
+ You will need a domain configured with wildcard DNS which is going to be used
+ by all of your Auto DevOps applications. If you're using the
+ [GitLab-managed app for Ingress](../../user/clusters/applications.md#ingress),
+ the URL endpoint will be automatically configured for you.
+
+ You will then need to [specify the Auto DevOps base domain](#auto-devops-base-domain).
+
- **GitLab Runner** (for all stages)
Your Runner needs to be configured to be able to run Docker. Generally this
means using either the [Docker](https://docs.gitlab.com/runner/executors/docker.html)
or [Kubernetes](https://docs.gitlab.com/runner/executors/kubernetes.html) executors, with
[privileged mode enabled](https://docs.gitlab.com/runner/executors/docker.html#use-docker-in-docker-with-privileged-mode).
-
The Runners do not need to be installed in the Kubernetes cluster, but the
Kubernetes executor is easy to use and is automatically autoscaling.
Docker-based Runners can be configured to autoscale as well, using [Docker
Machine](https://docs.gitlab.com/runner/install/autoscaling.html).
+ If you have configured GitLab's Kubernetes integration in the first step, you
+ can deploy it to your cluster by installing the
+ [GitLab-managed app for GitLab Runner](../../user/clusters/applications.md#gitlab-runner).
+
Runners should be registered as [shared Runners](../../ci/runners/README.md#registering-a-shared-runner)
for the entire GitLab instance, or [specific Runners](../../ci/runners/README.md#registering-a-specific-runner)
- that are assigned to specific projects.
-- **Base domain** (for Auto Review Apps and Auto Deploy)
-
- You will need a domain configured with wildcard DNS which is going to be used
- by all of your Auto DevOps applications.
-
- Read the [specifics](#auto-devops-base-domain).
-- **Kubernetes** (for Auto Review Apps, Auto Deploy, and Auto Monitoring)
-
- To enable deployments, you will need:
+ that are assigned to specific projects (the default if you have installed the
+ GitLab Runner managed application).
- - Kubernetes 1.5+.
- - A [Kubernetes cluster][kubernetes-clusters] for the project.
- - A load balancer. You can use NGINX Ingress by deploying it to your
- Kubernetes cluster by either:
- - Using the [`nginx-ingress`](https://github.com/helm/charts/tree/master/stable/nginx-ingress) Helm chart.
- - Installing the Ingress [GitLab Managed App](../../user/clusters/applications.md#ingress).
- **Prometheus** (for Auto Monitoring)
- To enable Auto Monitoring, you
- will need Prometheus installed somewhere (inside or outside your cluster) and
- configured to scrape your Kubernetes cluster. To get response metrics
- (in addition to system metrics), you need to
- [configure Prometheus to monitor NGINX](../../user/project/integrations/prometheus_library/nginx_ingress.md#configuring-nginx-ingress-monitoring).
+ To enable Auto Monitoring, you will need Prometheus installed somewhere
+ (inside or outside your cluster) and configured to scrape your Kubernetes cluster.
+ If you have configured GitLab's Kubernetes integration, you can deploy it to
+ your cluster by installing the
+ [GitLab-managed app for Prometheus](../../user/clusters/applications.md#prometheus).
The [Prometheus service](../../user/project/integrations/prometheus.md)
- integration needs to be enabled for the project, or enabled as a
+ integration needs to be enabled for the project (or enabled as a
[default service template](../../user/project/integrations/services_templates.md)
- for the entire GitLab installation.
+ for the entire GitLab installation).
+
+ To get response metrics (in addition to system metrics), you need to
+ [configure Prometheus to monitor NGINX](../../user/project/integrations/prometheus_library/nginx_ingress.md#configuring-nginx-ingress-monitoring).
If you do not have Kubernetes or Prometheus installed, then Auto Review Apps,
Auto Deploy, and Auto Monitoring will be silently skipped.
+One all requirements are met, you can go ahead and [enable Auto DevOps](#enablingdisabling-auto-devops).
+
## Auto DevOps base domain
-The Auto DevOps base domain is required if you want to make use of [Auto
-Review Apps](#auto-review-apps) and [Auto Deploy](#auto-deploy). It can be defined
-in any of the following places:
+The Auto DevOps base domain is required if you want to make use of
+[Auto Review Apps](#auto-review-apps), [Auto Deploy](#auto-deploy), and
+[Auto Monitoring](#auto-monitoring). It can be defined in any of the following
+places:
- either under the cluster's settings, whether for [projects](../../user/project/clusters/index.md#base-domain) or [groups](../../user/group/clusters/index.md#base-domain)
- or in instance-wide settings in the **admin area > Settings** under the "Continuous Integration and Delivery" section
@@ -156,9 +183,15 @@ in any of the following places:
The base domain variable `KUBE_INGRESS_BASE_DOMAIN` follows the same order of precedence
as other environment [variables](../../ci/variables/README.md#priority-of-environment-variables).
-NOTE: **Note**
-`AUTO_DEVOPS_DOMAIN` environment variable is deprecated and
-[is scheduled to be removed](https://gitlab.com/gitlab-org/gitlab-foss/issues/56959).
+TIP: **Tip:**
+If you're using the [GitLab managed app for Ingress](../../user/clusters/applications.md#ingress),
+the URL endpoint should be automatically configured for you. All you have to do
+is use its value for the `KUBE_INGRESS_BASE_DOMAIN` variable.
+
+NOTE: **Note:**
+`AUTO_DEVOPS_DOMAIN` was [deprecated in GitLab 11.8](https://gitlab.com/gitlab-org/gitlab-foss/issues/52363)
+and replaced with `KUBE_INGRESS_BASE_DOMAIN`. It was removed in
+[GitLab 12.0](https://gitlab.com/gitlab-org/gitlab-foss/issues/56959).
A wildcard DNS A record matching the base domain(s) is required, for example,
given a base domain of `example.com`, you'd need a DNS entry like:
@@ -179,77 +212,28 @@ Auto DevOps base domain to `1.2.3.4.nip.io`.
Once set up, all requests will hit the load balancer, which in turn will route
them to the Kubernetes pods that run your application(s).
-NOTE: **Note:**
-From GitLab 11.8, `KUBE_INGRESS_BASE_DOMAIN` replaces `AUTO_DEVOPS_DOMAIN`.
-Support for `AUTO_DEVOPS_DOMAIN` was [removed in GitLab
-12.0](https://gitlab.com/gitlab-org/gitlab-foss/issues/56959).
-
-## Using multiple Kubernetes clusters **(PREMIUM)**
-
-When using Auto DevOps, you may want to deploy different environments to
-different Kubernetes clusters. This is possible due to the 1:1 connection that
-[exists between them](../../user/project/clusters/index.md#multiple-kubernetes-clusters-premium).
-
-In the [Auto DevOps template] (used behind the scenes by Auto DevOps), there
-are currently 3 defined environment names that you need to know:
-
-- `review/` (every environment starting with `review/`)
-- `staging`
-- `production`
-
-Those environments are tied to jobs that use [Auto Deploy](#auto-deploy), so
-except for the environment scope, they would also need to have a different
-domain they would be deployed to. This is why you need to define a separate
-`KUBE_INGRESS_BASE_DOMAIN` variable for all the above
-[based on the environment](../../ci/variables/README.md#limiting-environment-scopes-of-environment-variables).
-
-The following table is an example of how the three different clusters would
-be configured.
-
-| Cluster name | Cluster environment scope | `KUBE_INGRESS_BASE_DOMAIN` variable value | Variable environment scope | Notes |
-|--------------|---------------------------|-------------------------------------------|----------------------------|---|
-| review | `review/*` | `review.example.com` | `review/*` | The review cluster which will run all [Review Apps](../../ci/review_apps/index.md). `*` is a wildcard, which means it will be used by every environment name starting with `review/`. |
-| staging | `staging` | `staging.example.com` | `staging` | (Optional) The staging cluster which will run the deployments of the staging environments. You need to [enable it first](#deploy-policy-for-staging-and-production-environments). |
-| production | `production` | `example.com` | `production` | The production cluster which will run the deployments of the production environment. You can use [incremental rollouts](#incremental-rollout-to-production-premium). |
-
-To add a different cluster for each environment:
-
-1. Navigate to your project's **Operations > Kubernetes** and create the Kubernetes clusters
- with their respective environment scope as described from the table above.
-
- ![Auto DevOps multiple clusters](img/autodevops_multiple_clusters.png)
-
-1. After the clusters are created, navigate to each one and install Helm Tiller
- and Ingress. Wait for the Ingress IP address to be assigned.
-1. Make sure you have [configured your DNS](#auto-devops-base-domain) with the
- specified Auto DevOps domains.
-1. Navigate to each cluster's page, through **Operations > Kubernetes**,
- and add the domain based on its Ingress IP address.
-
-Now that all is configured, you can test your setup by creating a merge request
-and verifying that your app is deployed as a review app in the Kubernetes
-cluster with the `review/*` environment scope. Similarly, you can check the
-other environments.
-
## Enabling/Disabling Auto DevOps
-When first using Auto Devops, review the [requirements](#requirements) to ensure all necessary components to make
+When first using Auto DevOps, review the [requirements](#requirements) to ensure all necessary components to make
full use of Auto DevOps are available. If this is your fist time, we recommend you follow the
[quick start guide](quick_start_guide.md).
GitLab.com users can enable/disable Auto DevOps at the project-level only. Self-managed users
can enable/disable Auto DevOps at the project-level, group-level or instance-level.
-### At the instance level (Administrators only)
+### At the project level
-Even when disabled at the instance level, group owners and project maintainers can still enable
-Auto DevOps at the group and project level, respectively.
+If enabling, check that your project doesn't have a `.gitlab-ci.yml`, or if one exists, remove it.
-1. Go to **Admin area > Settings > Continuous Integration and Deployment**.
-1. Toggle the checkbox labeled **Default to Auto DevOps pipeline for all projects**.
-1. If enabling, optionally set up the Auto DevOps [base domain](#auto-devops-base-domain) which will be used for Auto Deploy and Auto Review Apps.
+1. Go to your project's **Settings > CI/CD > Auto DevOps**.
+1. Toggle the **Default to Auto DevOps pipeline** checkbox (checked to enable, unchecked to disable)
+1. When enabling, it's optional but recommended to add in the [base domain](#auto-devops-base-domain)
+ that will be used by Auto DevOps to [deploy your application](#auto-deploy)
+ and choose the [deployment strategy](#deployment-strategy).
1. Click **Save changes** for the changes to take effect.
+When the feature has been enabled, an Auto DevOps pipeline is triggered on the default branch.
+
### At the group level
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/52447) in GitLab 11.10.
@@ -266,19 +250,16 @@ When enabling or disabling Auto DevOps at group-level, group configuration will
the subgroups and projects inside that group, unless Auto DevOps is specifically enabled or disabled on
the subgroup or project.
-### At the project level
+### At the instance level (Administrators only)
-If enabling, check that your project doesn't have a `.gitlab-ci.yml`, or if one exists, remove it.
+Even when disabled at the instance level, group owners and project maintainers can still enable
+Auto DevOps at the group and project level, respectively.
-1. Go to your project's **Settings > CI/CD > Auto DevOps**.
-1. Toggle the **Default to Auto DevOps pipeline** checkbox (checked to enable, unchecked to disable)
-1. When enabling, it's optional but recommended to add in the [base domain](#auto-devops-base-domain)
- that will be used by Auto DevOps to [deploy your application](#auto-deploy)
- and choose the [deployment strategy](#deployment-strategy).
+1. Go to **Admin area > Settings > Continuous Integration and Deployment**.
+1. Toggle the checkbox labeled **Default to Auto DevOps pipeline for all projects**.
+1. If enabling, optionally set up the Auto DevOps [base domain](#auto-devops-base-domain) which will be used for Auto Deploy and Auto Review Apps.
1. Click **Save changes** for the changes to take effect.
-When the feature has been enabled, an Auto DevOps pipeline is triggered on the default branch.
-
### Enable for a percentage of projects
There is also a feature flag to enable Auto DevOps by default to your chosen percentage of projects.
@@ -310,6 +291,53 @@ The available options are:
- `master` branch is directly deployed to staging.
- Manual actions are provided for incremental rollout to production.
+## Using multiple Kubernetes clusters **(PREMIUM)**
+
+When using Auto DevOps, you may want to deploy different environments to
+different Kubernetes clusters. This is possible due to the 1:1 connection that
+[exists between them](../../user/project/clusters/index.md#multiple-kubernetes-clusters-premium).
+
+In the [Auto DevOps template] (used behind the scenes by Auto DevOps), there
+are currently 3 defined environment names that you need to know:
+
+- `review/` (every environment starting with `review/`)
+- `staging`
+- `production`
+
+Those environments are tied to jobs that use [Auto Deploy](#auto-deploy), so
+except for the environment scope, they would also need to have a different
+domain they would be deployed to. This is why you need to define a separate
+`KUBE_INGRESS_BASE_DOMAIN` variable for all the above
+[based on the environment](../../ci/variables/README.md#limiting-environment-scopes-of-environment-variables).
+
+The following table is an example of how the three different clusters would
+be configured.
+
+| Cluster name | Cluster environment scope | `KUBE_INGRESS_BASE_DOMAIN` variable value | Variable environment scope | Notes |
+|--------------|---------------------------|-------------------------------------------|----------------------------|---|
+| review | `review/*` | `review.example.com` | `review/*` | The review cluster which will run all [Review Apps](../../ci/review_apps/index.md). `*` is a wildcard, which means it will be used by every environment name starting with `review/`. |
+| staging | `staging` | `staging.example.com` | `staging` | (Optional) The staging cluster which will run the deployments of the staging environments. You need to [enable it first](#deploy-policy-for-staging-and-production-environments). |
+| production | `production` | `example.com` | `production` | The production cluster which will run the deployments of the production environment. You can use [incremental rollouts](#incremental-rollout-to-production-premium). |
+
+To add a different cluster for each environment:
+
+1. Navigate to your project's **Operations > Kubernetes** and create the Kubernetes clusters
+ with their respective environment scope as described from the table above.
+
+ ![Auto DevOps multiple clusters](img/autodevops_multiple_clusters.png)
+
+1. After the clusters are created, navigate to each one and install Helm Tiller
+ and Ingress. Wait for the Ingress IP address to be assigned.
+1. Make sure you have [configured your DNS](#auto-devops-base-domain) with the
+ specified Auto DevOps domains.
+1. Navigate to each cluster's page, through **Operations > Kubernetes**,
+ and add the domain based on its Ingress IP address.
+
+Now that all is configured, you can test your setup by creating a merge request
+and verifying that your app is deployed as a review app in the Kubernetes
+cluster with the `review/*` environment scope. Similarly, you can check the
+other environments.
+
## Stages of Auto DevOps
The following sections describe the stages of Auto DevOps. Read them carefully
@@ -670,9 +698,28 @@ workers:
terminationGracePeriodSeconds: 60
```
-### Auto Monitoring
+#### Running commands in the container
+
+Applications built with [Auto Build](#auto-build) using Herokuish, the default
+unless you have [a custom Dockerfile](#auto-build-using-a-dockerfile), may require
+commands to be wrapped as follows:
+
+```shell
+/bin/herokuish procfile exec $COMMAND
+```
+
+This might be neccessary, for example, when:
+
+- Attaching using `kubectl exec`.
+- Using GitLab's [Web Terminal](../../ci/environments.md#web-terminals).
+
+For example, to start a Rails console from the application root directory, run:
+
+```sh
+/bin/herokuish procfile exec bin/rails c
+```
-See the [requirements](#requirements) for Auto Monitoring to enable this stage.
+### Auto Monitoring
Once your application is deployed, Auto Monitoring makes it possible to monitor
your application's server and response metrics right out of the box. Auto
@@ -687,18 +734,15 @@ The metrics include:
- **Response Metrics:** latency, throughput, error rate
- **System Metrics:** CPU utilization, memory utilization
-In order to make use of monitoring you need to:
+To make use of Auto Monitoring:
-1. [Deploy Prometheus](../../user/project/integrations/prometheus.md) into your Kubernetes cluster
-1. If you would like response metrics, ensure you are running at least version
- 0.9.0 of NGINX Ingress and
- [enable Prometheus metrics](https://github.com/kubernetes/ingress-nginx/blob/master/docs/examples/customization/custom-vts-metrics-prometheus/nginx-vts-metrics-conf.yaml).
-1. Finally, [annotate](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/)
- the NGINX Ingress deployment to be scraped by Prometheus using
- `prometheus.io/scrape: "true"` and `prometheus.io/port: "10254"`.
-
-To view the metrics, open the
-[Monitoring dashboard for a deployed environment](../../ci/environments.md#monitoring-environments).
+1. [Install and configure the requirements](#requirements).
+1. [Enable Auto DevOps](#enablingdisabling-auto-devops) if you haven't done already.
+1. Finally, go to your project's **CI/CD > Pipelines** and run a pipeline.
+1. Once the pipeline finishes successfully, open the
+ [monitoring dashboard for a deployed environment](../../ci/environments.md#monitoring-environments)
+ to view the metrics of your deployed application. To view the metrics of the
+ whole Kubernetes cluster, navigate to **Operations > Metrics**.
![Auto Metrics](img/auto_monitoring.png)
@@ -725,6 +769,8 @@ or a `.buildpacks` file in your project:
CAUTION: **Caution:**
Using multiple buildpacks isn't yet supported by Auto DevOps.
+CAUTION: **Caution:** When using the `.buildpacks` file, Auto Test will not work. The buildpack [heroku-buildpack-multi](https://github.com/heroku/heroku-buildpack-multi/) (which is used under the hood to parse the `.buildpacks` file) doesn't provide the necessary commands `bin/test-compile` and `bin/test`. Make sure to provide the project variable `BUILDPACK_URL` instead.
+
### Custom `Dockerfile`
If your project has a `Dockerfile` in the root of the project repo, Auto DevOps
@@ -924,6 +970,7 @@ applications.
| `AUTO_DEVOPS_CHART_REPOSITORY_NAME` | From GitLab 11.11, used to set the name of the Helm repository. Defaults to `gitlab`. |
| `AUTO_DEVOPS_CHART_REPOSITORY_USERNAME` | From GitLab 11.11, used to set a username to connect to the Helm repository. Defaults to no credentials. Also set `AUTO_DEVOPS_CHART_REPOSITORY_PASSWORD`. |
| `AUTO_DEVOPS_CHART_REPOSITORY_PASSWORD` | From GitLab 11.11, used to set a password to connect to the Helm repository. Defaults to no credentials. Also set `AUTO_DEVOPS_CHART_REPOSITORY_USERNAME`. |
+| `AUTO_DEVOPS_MODSECURITY_SEC_RULE_ENGINE` | From GitLab 12.5, used in combination with [Modsecurity feature flag](../../user/clusters/applications.md#web-application-firewall-modsecurity) to toggle [Modsecurity's `SecRuleEngine`](https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual-(v2.x)#SecRuleEngine) behavior. Defaults to `DetectionOnly`. |
| `BUILDPACK_URL` | Buildpack's full URL. Can point to either Git repositories or a tarball URL. For Git repositories, it is possible to point to a specific `ref`. For example `https://github.com/heroku/heroku-buildpack-ruby.git#v142`. |
| `CANARY_ENABLED` | From GitLab 11.0, used to define a [deploy policy for canary environments](#deploy-policy-for-canary-environments-premium). |
| `CANARY_PRODUCTION_REPLICAS` | Number of canary replicas to deploy for [Canary Deployments](../../user/project/canary_deployments.md) in the production environment. Takes precedence over `CANARY_REPLICAS`. Defaults to 1. |
@@ -968,7 +1015,6 @@ The following table lists variables related to security tools.
| **Variable** | **Description** |
| `SAST_CONFIDENCE_LEVEL` | Minimum confidence level of security issues you want to be reported; `1` for Low, `2` for Medium, `3` for High. Defaults to `3`. |
-| `DS_DISABLE_REMOTE_CHECKS` | Whether remote Dependency Scanning checks are disabled. Defaults to `"false"`. Set to `"true"` to disable checks that send data to GitLab central servers. [Read more about remote checks](../../user/application_security/dependency_scanning/index.md#remote-checks). |
#### Disable jobs
@@ -1301,7 +1347,6 @@ curl --data "value=true" --header "PRIVATE-TOKEN: personal_access_token" https:/
```
[ce-37115]: https://gitlab.com/gitlab-org/gitlab-foss/issues/37115
-[kubernetes-clusters]: ../../user/project/clusters/index.md
[docker-in-docker]: ../../docker/using_docker_build.md#use-docker-in-docker-executor
[review-app]: ../../ci/review_apps/index.md
[container-registry]: ../../user/packages/container_registry/index.md
diff --git a/doc/topics/autodevops/quick_start_guide.md b/doc/topics/autodevops/quick_start_guide.md
index d9bdd73221f..ce3a3dd5ca6 100644
--- a/doc/topics/autodevops/quick_start_guide.md
+++ b/doc/topics/autodevops/quick_start_guide.md
@@ -25,7 +25,7 @@ Google account (for example, one that you use to access Gmail, Drive, etc.) or c
TIP: **Tip:**
Every new Google Cloud Platform (GCP) account receives [$300 in credit](https://console.cloud.google.com/freetrial),
and in partnership with Google, GitLab is able to offer an additional $200 for new GCP accounts to get started with GitLab's
-Google Kubernetes Engine Integration. All you have to do is [follow this link](https://cloud.google.com/partners/partnercredit/?PCN=a0n60000006Vpz4AAC) and apply for credit.
+Google Kubernetes Engine Integration. All you have to do is [follow this link](https://cloud.google.com/partners/partnercredit/?pcn_code=0014M00001h35gDQAQ#contact-form) and apply for credit.
## Creating a new project from a template
@@ -212,7 +212,7 @@ under **Settings > CI/CD > Environment variables**.
### Working with branches
-Following the [GitLab flow](../../workflow/gitlab_flow.md#working-with-feature-branches),
+Following the [GitLab flow](../gitlab_flow.md#working-with-feature-branches),
let's create a feature branch that will add some content to the application.
Under your repository, navigate to the following file: `app/views/welcome/index.html.erb`.
@@ -280,6 +280,6 @@ and customized to fit your workflow. Here are some helpful resources for further
1. [Multiple Kubernetes clusters](index.md#using-multiple-kubernetes-clusters-premium) **(PREMIUM)**
1. [Incremental rollout to production](index.md#incremental-rollout-to-production-premium) **(PREMIUM)**
1. [Disable jobs you don't need with environment variables](index.md#environment-variables)
-1. [Use a static IP for your cluster](../../user/project/clusters/index.md#using-a-static-ip)
+1. [Use a static IP for your cluster](../../user/clusters/applications.md#using-a-static-ip)
1. [Use your own buildpacks to build your application](index.md#custom-buildpacks)
1. [Prometheus monitoring](../../user/project/integrations/prometheus.md)
diff --git a/doc/topics/git/index.md b/doc/topics/git/index.md
index d6e1f83b876..4325980a60c 100644
--- a/doc/topics/git/index.md
+++ b/doc/topics/git/index.md
@@ -32,7 +32,7 @@ The following resources will help you get started with Git:
- Commits:
- [Revert a commit](../../user/project/merge_requests/revert_changes.md#reverting-a-commit)
- [Cherry-picking a commit](../../user/project/merge_requests/cherry_pick_changes.md#cherry-picking-a-commit)
- - [Squashing commits](../../workflow/gitlab_flow.md#squashing-commits-with-rebase)
+ - [Squashing commits](../gitlab_flow.md#squashing-commits-with-rebase)
### Concepts
@@ -85,7 +85,7 @@ The following relate to Git Large File Storage:
- [Getting Started with Git LFS](https://about.gitlab.com/blog/2017/01/30/getting-started-with-git-lfs-tutorial/)
- [Migrate an existing Git repo with Git LFS](migrate_to_git_lfs/index.md)
-- [GitLab Git LFS user documentation](../../workflow/lfs/manage_large_binaries_with_git_lfs.md)
-- [GitLab Git LFS admin documentation](../../workflow/lfs/lfs_administration.md)
-- [git-annex to Git-LFS migration guide](../../workflow/lfs/migrate_from_git_annex_to_git_lfs.md)
+- [GitLab Git LFS user documentation](../../administration/lfs/manage_large_binaries_with_git_lfs.md)
+- [GitLab Git LFS admin documentation](../../administration/lfs/lfs_administration.md)
+- [git-annex to Git-LFS migration guide](../../administration/lfs/migrate_from_git_annex_to_git_lfs.md)
- [Towards a production quality open source Git LFS server](https://about.gitlab.com/blog/2015/08/13/towards-a-production-quality-open-source-git-lfs-server/)
diff --git a/doc/topics/git/migrate_to_git_lfs/index.md b/doc/topics/git/migrate_to_git_lfs/index.md
index 0c30b45c552..eec1c3c10c1 100644
--- a/doc/topics/git/migrate_to_git_lfs/index.md
+++ b/doc/topics/git/migrate_to_git_lfs/index.md
@@ -163,9 +163,9 @@ but commented out to help encourage others to add to it in the future. -->
## References
- [Getting Started with Git LFS](https://about.gitlab.com/blog/2017/01/30/getting-started-with-git-lfs-tutorial/)
-- [Migrate from Git Annex to Git LFS](../../../workflow/lfs/migrate_from_git_annex_to_git_lfs.md)
-- [GitLab's Git LFS user documentation](../../../workflow/lfs/manage_large_binaries_with_git_lfs.md)
-- [GitLab's Git LFS administrator documentation](../../../workflow/lfs/lfs_administration.md)
+- [Migrate from Git Annex to Git LFS](../../../administration/lfs/migrate_from_git_annex_to_git_lfs.md)
+- [GitLab's Git LFS user documentation](../../../administration/lfs/manage_large_binaries_with_git_lfs.md)
+- [GitLab's Git LFS administrator documentation](../../../administration/lfs/lfs_administration.md)
- Alternative method to [migrate an existing repo to Git LFS](https://github.com/git-lfs/git-lfs/wiki/Tutorial#migrating-existing-repository-data-to-lfs)
<!--
diff --git a/doc/topics/git/partial_clone.md b/doc/topics/git/partial_clone.md
index ce1b551ddb6..e6f84ee8251 100644
--- a/doc/topics/git/partial_clone.md
+++ b/doc/topics/git/partial_clone.md
@@ -39,16 +39,20 @@ Follow [Git for enormous repositories](https://gitlab.com/groups/gitlab-org/-/ep
## Enabling partial clone
-GitLab 12.1 uses Git 2.21.0 which has an arbitrary file access security
-vulnerability when `uploadpack.allowFilter` is enabled, and should not be
-enabled in production environments.
+> [Introduced](https://gitlab.com/gitlab-org/gitaly/issues/1553) in GitLab 12.4.
-A feature flag is planned to enable `uploadpack.allowFilter` and
-`uploadpack.allowAnySHA1InWant` once the version of Git used by GitLab has been
-updated to Git 2.22.0.
+To enable partial clone, use the [feature flags API](../../api/features.md).
+For example:
-Follow [this issue](https://gitlab.com/gitlab-org/gitaly/issues/1553) for
-updated.
+```sh
+curl --data "value=true" --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/features/gitaly_upload_pack_filter
+```
+
+Alternatively, flip the switch and enable the feature flag:
+
+```ruby
+Feature.enable(:gitaly_upload_pack_filter)
+```
## Excluding objects by size
diff --git a/doc/topics/gitlab_flow.md b/doc/topics/gitlab_flow.md
new file mode 100644
index 00000000000..0fab4de8454
--- /dev/null
+++ b/doc/topics/gitlab_flow.md
@@ -0,0 +1,330 @@
+---
+disqus_identifier: 'https://docs.gitlab.com/ee/workflow/gitlab_flow.html'
+---
+
+# Introduction to GitLab Flow
+
+![GitLab Flow](img/gitlab_flow.png)
+
+Git allows a wide variety of branching strategies and workflows.
+Because of this, many organizations end up with workflows that are too complicated, not clearly defined, or not integrated with issue tracking systems.
+Therefore, we propose GitLab flow as a clearly defined set of best practices.
+It combines [feature-driven development](https://en.wikipedia.org/wiki/Feature-driven_development) and [feature branches](https://martinfowler.com/bliki/FeatureBranch.html) with issue tracking.
+
+Organizations coming to Git from other version control systems frequently find it hard to develop a productive workflow.
+This article describes GitLab flow, which integrates the Git workflow with an issue tracking system.
+It offers a simple, transparent, and effective way to work with Git.
+
+![Four stages (working copy, index, local repo, remote repo) and three steps between them](img/gitlab_flow_four_stages.png)
+
+When converting to Git, you have to get used to the fact that it takes three steps to share a commit with colleagues.
+Most version control systems have only one step: committing from the working copy to a shared server.
+In Git, you add files from the working copy to the staging area. After that, you commit them to your local repo.
+The third step is pushing to a shared remote repository.
+After getting used to these three steps, the next challenge is the branching model.
+
+![Multiple long-running branches and merging in all directions](img/gitlab_flow_messy_flow.png)
+
+Since many organizations new to Git have no conventions for how to work with it, their repositories can quickly become messy.
+The biggest problem is that many long-running branches emerge that all contain part of the changes.
+People have a hard time figuring out which branch has the latest code, or which branch to deploy to production.
+Frequently, the reaction to this problem is to adopt a standardized pattern such as [Git flow](https://nvie.com/posts/a-successful-git-branching-model/) and [GitHub flow](http://scottchacon.com/2011/08/31/github-flow.html).
+We think there is still room for improvement. In this document, we describe a set of practices we call GitLab flow.
+
+For a video introduction of how this works in GitLab, see [GitLab Flow](https://youtu.be/InKNIvky2KE).
+
+## Git flow and its problems
+
+![Git Flow timeline by Vincent Driessen, used with permission](img/gitlab_flow_gitdashflow.png)
+
+Git flow was one of the first proposals to use Git branches, and it has received a lot of attention.
+It suggests a `master` branch and a separate `develop` branch, as well as supporting branches for features, releases, and hotfixes.
+The development happens on the `develop` branch, moves to a release branch, and is finally merged into the `master` branch.
+
+Git flow is a well-defined standard, but its complexity introduces two problems.
+The first problem is that developers must use the `develop` branch and not `master`. `master` is reserved for code that is released to production.
+It is a convention to call your default branch `master` and to mostly branch from and merge to this.
+Since most tools automatically use the `master` branch as the default, it is annoying to have to switch to another branch.
+
+The second problem of Git flow is the complexity introduced by the hotfix and release branches.
+These branches can be a good idea for some organizations but are overkill for the vast majority of them.
+Nowadays, most organizations practice continuous delivery, which means that your default branch can be deployed.
+Continuous delivery removes the need for hotfix and release branches, including all the ceremony they introduce.
+An example of this ceremony is the merging back of release branches.
+Though specialized tools do exist to solve this, they require documentation and add complexity.
+Frequently, developers make mistakes such as merging changes only into `master` and not into the `develop` branch.
+The reason for these errors is that Git flow is too complicated for most use cases.
+For example, many projects do releases but don't need to do hotfixes.
+
+## GitHub flow as a simpler alternative
+
+![Master branch with feature branches merged in](img/gitlab_flow_github_flow.png)
+
+In reaction to Git flow, GitHub created a simpler alternative.
+[GitHub flow](https://guides.github.com/introduction/flow/index.html) has only feature branches and a `master` branch.
+This flow is clean and straightforward, and many organizations have adopted it with great success.
+Atlassian recommends [a similar strategy](https://www.atlassian.com/blog/git/simple-git-workflow-is-simple), although they rebase feature branches.
+Merging everything into the `master` branch and frequently deploying means you minimize the amount of unreleased code, which is in line with lean and continuous delivery best practices.
+However, this flow still leaves a lot of questions unanswered regarding deployments, environments, releases, and integrations with issues.
+With GitLab flow, we offer additional guidance for these questions.
+
+## Production branch with GitLab flow
+
+![Master branch and production branch with an arrow that indicates a deployment](img/gitlab_flow_production_branch.png)
+
+GitHub flow assumes you can deploy to production every time you merge a feature branch.
+While this is possible in some cases, such as SaaS applications, there are many cases where this is not possible.
+One case is where you don't control the timing of a release, for example, an iOS application that is released when it passes App Store validation.
+Another case is when you have deployment windows &mdash; for example, workdays from 10&nbsp;AM to 4&nbsp;PM when the operations team is at full capacity &mdash; but you also merge code at other times.
+In these cases, you can make a production branch that reflects the deployed code.
+You can deploy a new version by merging `master` into the production branch.
+If you need to know what code is in production, you can just checkout the production branch to see.
+The approximate time of deployment is easily visible as the merge commit in the version control system.
+This time is pretty accurate if you automatically deploy your production branch.
+If you need a more exact time, you can have your deployment script create a tag on each deployment.
+This flow prevents the overhead of releasing, tagging, and merging that happens with Git flow.
+
+## Environment branches with GitLab flow
+
+![Multiple branches with the code cascading from one to another](img/gitlab_flow_environment_branches.png)
+
+It might be a good idea to have an environment that is automatically updated to the `master` branch.
+Only, in this case, the name of this environment might differ from the branch name.
+Suppose you have a staging environment, a pre-production environment, and a production environment.
+In this case, deploy the `master` branch to staging.
+To deploy to pre-production, create a merge request from the `master` branch to the pre-production branch.
+Go live by merging the pre-production branch into the production branch.
+This workflow, where commits only flow downstream, ensures that everything is tested in all environments.
+If you need to cherry-pick a commit with a hotfix, it is common to develop it on a feature branch and merge it into `master` with a merge request.
+In this case, do not delete the feature branch yet.
+If `master` passes automatic testing, you then merge the feature branch into the other branches.
+If this is not possible because more manual testing is required, you can send merge requests from the feature branch to the downstream branches.
+
+## Release branches with GitLab flow
+
+![Master and multiple release branches that vary in length with cherry-picks from master](img/gitlab_flow_release_branches.png)
+
+You only need to work with release branches if you need to release software to the outside world.
+In this case, each branch contains a minor version, for example, 2-3-stable, 2-4-stable, etc.
+Create stable branches using `master` as a starting point, and branch as late as possible.
+By doing this, you minimize the length of time during which you have to apply bug fixes to multiple branches.
+After announcing a release branch, only add serious bug fixes to the branch.
+If possible, first merge these bug fixes into `master`, and then cherry-pick them into the release branch.
+If you start by merging into the release branch, you might forget to cherry-pick them into `master`, and then you'd encounter the same bug in subsequent releases.
+Merging into `master` and then cherry-picking into release is called an "upstream first" policy, which is also practiced by [Google](https://www.chromium.org/chromium-os/chromiumos-design-docs/upstream-first) and [Red Hat](https://www.redhat.com/en/blog/a-community-for-using-openstack-with-red-hat-rdo).
+Every time you include a bug fix in a release branch, increase the patch version (to comply with [Semantic Versioning](https://semver.org/)) by setting a new tag.
+Some projects also have a stable branch that points to the same commit as the latest released branch.
+In this flow, it is not common to have a production branch (or Git flow `master` branch).
+
+## Merge/pull requests with GitLab flow
+
+![Merge request with inline comments](img/gitlab_flow_mr_inline_comments.png)
+
+Merge or pull requests are created in a Git management application. They ask an assigned person to merge two branches.
+Tools such as GitHub and Bitbucket choose the name "pull request" since the first manual action is to pull the feature branch.
+Tools such as GitLab and others choose the name "merge request" since the final action is to merge the feature branch.
+In this article, we'll refer to them as merge requests.
+
+If you work on a feature branch for more than a few hours, it is good to share the intermediate result with the rest of the team.
+To do this, create a merge request without assigning it to anyone.
+Instead, mention people in the description or a comment, for example, "/cc @mark @susan."
+This indicates that the merge request is not ready to be merged yet, but feedback is welcome.
+Your team members can comment on the merge request in general or on specific lines with line comments.
+The merge request serves as a code review tool, and no separate code review tools should be needed.
+If the review reveals shortcomings, anyone can commit and push a fix.
+Usually, the person to do this is the creator of the merge request.
+The diff in the merge request automatically updates when new commits are pushed to the branch.
+
+When you are ready for your feature branch to be merged, assign the merge request to the person who knows most about the codebase you are changing.
+Also, mention any other people from whom you would like feedback.
+After the assigned person feels comfortable with the result, they can merge the branch.
+If the assigned person does not feel comfortable, they can request more changes or close the merge request without merging.
+
+In GitLab, it is common to protect the long-lived branches, e.g., the `master` branch, so that [most developers can't modify them](../user/permissions.md).
+So, if you want to merge into a protected branch, assign your merge request to someone with maintainer permissions.
+
+After you merge a feature branch, you should remove it from the source control software.
+In GitLab, you can do this when merging.
+Removing finished branches ensures that the list of branches shows only work in progress.
+It also ensures that if someone reopens the issue, they can use the same branch name without causing problems.
+
+NOTE: **Note:**
+When you reopen an issue you need to create a new merge request.
+
+![Remove checkbox for branch in merge requests](img/gitlab_flow_remove_checkbox.png)
+
+## Issue tracking with GitLab flow
+
+![Merge request with the branch name "15-require-a-password-to-change-it" and assignee field shown](img/gitlab_flow_merge_request.png)
+
+GitLab flow is a way to make the relation between the code and the issue tracker more transparent.
+
+Any significant change to the code should start with an issue that describes the goal.
+Having a reason for every code change helps to inform the rest of the team and to keep the scope of a feature branch small.
+In GitLab, each change to the codebase starts with an issue in the issue tracking system.
+If there is no issue yet, create the issue, as long as the change will take a significant amount of work, i.e., more than 1 hour.
+In many organizations, raising an issue is part of the development process because they are used in sprint planning.
+The issue title should describe the desired state of the system.
+For example, the issue title "As an administrator, I want to remove users without receiving an error" is better than "Admin can't remove users."
+
+When you are ready to code, create a branch for the issue from the `master` branch.
+This branch is the place for any work related to this change.
+
+NOTE: **Note:**
+The name of a branch might be dictated by organizational standards.
+
+When you are done or want to discuss the code, open a merge request.
+A merge request is an online place to discuss the change and review the code.
+
+If you open the merge request but do not assign it to anyone, it is a "Work In Progress" merge request.
+These are used to discuss the proposed implementation but are not ready for inclusion in the `master` branch yet.
+Start the title of the merge request with `[WIP]` or `WIP:` to prevent it from being merged before it's ready.
+
+When you think the code is ready, assign the merge request to a reviewer.
+The reviewer can merge the changes when they think the code is ready for inclusion in the `master` branch.
+When they press the merge button, GitLab merges the code and creates a merge commit that makes this event easily visible later on.
+Merge requests always create a merge commit, even when the branch could be merged without one.
+This merge strategy is called "no fast-forward" in Git.
+After the merge, delete the feature branch since it is no longer needed.
+In GitLab, this deletion is an option when merging.
+
+Suppose that a branch is merged but a problem occurs and the issue is reopened.
+In this case, it is no problem to reuse the same branch name since the first branch was deleted when it was merged.
+At any time, there is at most one branch for every issue.
+It is possible that one feature branch solves more than one issue.
+
+## Linking and closing issues from merge requests
+
+![Merge request showing the linked issues that will be closed](img/gitlab_flow_close_issue_mr.png)
+
+Link to issues by mentioning them in commit messages or the description of a merge request, for example, "Fixes #16" or "Duck typing is preferred. See #12."
+GitLab then creates links to the mentioned issues and creates comments in the issues linking back to the merge request.
+
+To automatically close linked issues, mention them with the words "fixes" or "closes," for example, "fixes #14" or "closes #67." GitLab closes these issues when the code is merged into the default branch.
+
+If you have an issue that spans across multiple repositories, create an issue for each repository and link all issues to a parent issue.
+
+## Squashing commits with rebase
+
+![Vim screen showing the rebase view](img/gitlab_flow_rebase.png)
+
+With Git, you can use an interactive rebase (`rebase -i`) to squash multiple commits into one or reorder them.
+This functionality is useful if you want to replace a couple of small commits with a single commit, or if you want to make the order more logical.
+
+However, you should never rebase commits you have pushed to a remote server.
+Rebasing creates new commits for all your changes, which can cause confusion because the same change would have multiple identifiers.
+It also causes merge errors for anyone working on the same branch because their history would not match with yours.
+Also, if someone has already reviewed your code, rebasing makes it hard to tell what changed since the last review.
+
+You should also never rebase commits authored by other people.
+Not only does this rewrite history, but it also loses authorship information.
+Rebasing prevents the other authors from being attributed and sharing part of the [`git blame`](https://git-scm.com/docs/git-blame).
+
+If a merge involves many commits, it may seem more difficult to undo.
+You might think to solve this by squashing all the changes into one commit before merging, but as discussed earlier, it is a bad idea to rebase commits that you have already pushed.
+Fortunately, there is an easy way to undo a merge with all its commits.
+The way to do this is by reverting the merge commit.
+Preserving this ability to revert a merge is a good reason to always use the "no fast-forward" (`--no-ff`) strategy when you merge manually.
+
+NOTE: **Note:**
+If you revert a merge commit and then change your mind, revert the revert commit to redo the merge.
+Git does not allow you to merge the code again otherwise.
+
+## Reducing merge commits in feature branches
+
+![List of sequential merge commits](img/gitlab_flow_merge_commits.png)
+
+Having lots of merge commits can make your repository history messy.
+Therefore, you should try to avoid merge commits in feature branches.
+Often, people avoid merge commits by just using rebase to reorder their commits after the commits on the `master` branch.
+Using rebase prevents a merge commit when merging `master` into your feature branch, and it creates a neat linear history.
+However, as discussed in [the section about rebasing](#squashing-commits-with-rebase), you should never rebase commits you have pushed to a remote server.
+This restriction makes it impossible to rebase work in progress that you already shared with your team, which is something we recommend.
+
+Rebasing also creates more work, since every time you rebase, you have to resolve similar conflicts.
+Sometimes you can reuse recorded resolutions (`rerere`), but merging is better since you only have to resolve conflicts once.
+Atlassian has a more thorough explanation of the tradeoffs between merging and rebasing [on their blog](https://www.atlassian.com/blog/git/git-team-workflows-merge-or-rebase).
+
+A good way to prevent creating many merge commits is to not frequently merge `master` into the feature branch.
+There are three reasons to merge in `master`: utilizing new code, resolving merge conflicts, and updating long-running branches.
+
+If you need to utilize some code that was introduced in `master` after you created the feature branch, you can often solve this by just cherry-picking a commit.
+
+If your feature branch has a merge conflict, creating a merge commit is a standard way of solving this.
+
+NOTE: **Note:**
+Sometimes you can use .gitattributes to reduce merge conflicts.
+For example, you can set your changelog file to use the [union merge driver](https://git-scm.com/docs/gitattributes#gitattributes-union) so that multiple new entries don't conflict with each other.
+
+The last reason for creating merge commits is to keep long-running feature branches up-to-date with the latest state of the project.
+The solution here is to keep your feature branches short-lived.
+Most feature branches should take less than one day of work.
+If your feature branches often take more than a day of work, try to split your features into smaller units of work.
+
+If you need to keep a feature branch open for more than a day, there are a few strategies to keep it up-to-date.
+One option is to use continuous integration (CI) to merge in `master` at the start of the day.
+Another option is to only merge in from well-defined points in time, for example, a tagged release.
+You could also use [feature toggles](https://martinfowler.com/bliki/FeatureToggle.html) to hide incomplete features so you can still merge back into `master` every day.
+
+> **Note:** Don't confuse automatic branch testing with continuous integration.
+> Martin Fowler makes this distinction in [his article about feature branches](https://martinfowler.com/bliki/FeatureBranch.html):
+>
+> "I've heard people say they are doing CI because they are running builds, perhaps using a CI server, on every branch with every commit.
+> That's continuous building, and a Good Thing, but there's no *integration*, so it's not CI."
+
+In conclusion, you should try to prevent merge commits, but not eliminate them.
+Your codebase should be clean, but your history should represent what actually happened.
+Developing software happens in small, messy steps, and it is OK to have your history reflect this.
+You can use tools to view the network graphs of commits and understand the messy history that created your code.
+If you rebase code, the history is incorrect, and there is no way for tools to remedy this because they can't deal with changing commit identifiers.
+
+## Commit often and push frequently
+
+Another way to make your development work easier is to commit often.
+Every time you have a working set of tests and code, you should make a commit.
+Splitting up work into individual commits provides context for developers looking at your code later.
+Smaller commits make it clear how a feature was developed, and they make it easy to roll back to a specific good point in time or to revert one code change without reverting several unrelated changes.
+
+Committing often also makes it easy to share your work, which is important so that everyone is aware of what you are working on.
+You should push your feature branch frequently, even when it is not yet ready for review.
+By sharing your work in a feature branch or [a merge request](#mergepull-requests-with-gitlab-flow), you prevent your team members from duplicating work.
+Sharing your work before it's complete also allows for discussion and feedback about the changes, which can help improve the code before it gets to review.
+
+## How to write a good commit message
+
+![Good and bad commit message](img/gitlab_flow_good_commit.png)
+
+A commit message should reflect your intention, not just the contents of the commit.
+It is easy to see the changes in a commit, so the commit message should explain why you made those changes.
+An example of a good commit message is: "Combine templates to reduce duplicate code in the user views."
+The words "change," "improve," "fix," and "refactor" don't add much information to a commit message.
+For example, "Improve XML generation" could be better written as "Properly escape special characters in XML generation."
+For more information about formatting commit messages, please see this excellent [blog post by Tim Pope](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
+
+## Testing before merging
+
+![Merge requests showing the test states: red, yellow, and green](img/gitlab_flow_ci_mr.png)
+
+In old workflows, the continuous integration (CI) server commonly ran tests on the `master` branch only.
+Developers had to ensure their code did not break the `master` branch.
+When using GitLab flow, developers create their branches from this `master` branch, so it is essential that it never breaks.
+Therefore, each merge request must be tested before it is accepted.
+CI software like Travis CI and GitLab CI show the build results right in the merge request itself to make this easy.
+
+There is one drawback to testing merge requests: the CI server only tests the feature branch itself, not the merged result.
+Ideally, the server could also test the `master` branch after each change.
+However, retesting on every commit to `master` is computationally expensive and means you are more frequently waiting for test results.
+Since feature branches should be short-lived, testing just the branch is an acceptable risk.
+If new commits in `master` cause merge conflicts with the feature branch, merge `master` back into the branch to make the CI server re-run the tests.
+As said before, if you often have feature branches that last for more than a few days, you should make your issues smaller.
+
+## Working with feature branches
+
+![Shell output showing git pull output](img/gitlab_flow_git_pull.png)
+
+When creating a feature branch, always branch from an up-to-date `master`.
+If you know before you start that your work depends on another branch, you can also branch from there.
+If you need to merge in another branch after starting, explain the reason in the merge commit.
+If you have not pushed your commits to a shared location yet, you can also incorporate changes by rebasing on `master` or another feature branch.
+Do not merge from upstream again if your code can work and merge cleanly without doing so.
+Merging only when needed prevents creating merge commits in your feature branch that later end up littering the `master` history.
diff --git a/doc/workflow/img/gitlab_flow.png b/doc/topics/img/gitlab_flow.png
index a6f3c947843..a6f3c947843 100644
--- a/doc/workflow/img/gitlab_flow.png
+++ b/doc/topics/img/gitlab_flow.png
Binary files differ
diff --git a/doc/workflow/img/ci_mr.png b/doc/topics/img/gitlab_flow_ci_mr.png
index 85a609cb814..85a609cb814 100644
--- a/doc/workflow/img/ci_mr.png
+++ b/doc/topics/img/gitlab_flow_ci_mr.png
Binary files differ
diff --git a/doc/workflow/img/close_issue_mr.png b/doc/topics/img/gitlab_flow_close_issue_mr.png
index 70de2fb6cee..70de2fb6cee 100644
--- a/doc/workflow/img/close_issue_mr.png
+++ b/doc/topics/img/gitlab_flow_close_issue_mr.png
Binary files differ
diff --git a/doc/workflow/img/environment_branches.png b/doc/topics/img/gitlab_flow_environment_branches.png
index 0aff33c6bb8..0aff33c6bb8 100644
--- a/doc/workflow/img/environment_branches.png
+++ b/doc/topics/img/gitlab_flow_environment_branches.png
Binary files differ
diff --git a/doc/workflow/img/four_stages.png b/doc/topics/img/gitlab_flow_four_stages.png
index 3ef6a33d2d4..3ef6a33d2d4 100644
--- a/doc/workflow/img/four_stages.png
+++ b/doc/topics/img/gitlab_flow_four_stages.png
Binary files differ
diff --git a/doc/workflow/img/git_pull.png b/doc/topics/img/gitlab_flow_git_pull.png
index 0e56e59471c..0e56e59471c 100644
--- a/doc/workflow/img/git_pull.png
+++ b/doc/topics/img/gitlab_flow_git_pull.png
Binary files differ
diff --git a/doc/workflow/img/gitdashflow.png b/doc/topics/img/gitlab_flow_gitdashflow.png
index 65900853d84..65900853d84 100644
--- a/doc/workflow/img/gitdashflow.png
+++ b/doc/topics/img/gitlab_flow_gitdashflow.png
Binary files differ
diff --git a/doc/workflow/img/github_flow.png b/doc/topics/img/gitlab_flow_github_flow.png
index 21a22becdb6..21a22becdb6 100644
--- a/doc/workflow/img/github_flow.png
+++ b/doc/topics/img/gitlab_flow_github_flow.png
Binary files differ
diff --git a/doc/workflow/img/good_commit.png b/doc/topics/img/gitlab_flow_good_commit.png
index ceb0d4b1691..ceb0d4b1691 100644
--- a/doc/workflow/img/good_commit.png
+++ b/doc/topics/img/gitlab_flow_good_commit.png
Binary files differ
diff --git a/doc/workflow/img/merge_commits.png b/doc/topics/img/gitlab_flow_merge_commits.png
index 4a80811c6e3..4a80811c6e3 100644
--- a/doc/workflow/img/merge_commits.png
+++ b/doc/topics/img/gitlab_flow_merge_commits.png
Binary files differ
diff --git a/doc/workflow/img/merge_request.png b/doc/topics/img/gitlab_flow_merge_request.png
index 010e95983fc..010e95983fc 100644
--- a/doc/workflow/img/merge_request.png
+++ b/doc/topics/img/gitlab_flow_merge_request.png
Binary files differ
diff --git a/doc/workflow/img/messy_flow.png b/doc/topics/img/gitlab_flow_messy_flow.png
index 4fa22d2bb5d..4fa22d2bb5d 100644
--- a/doc/workflow/img/messy_flow.png
+++ b/doc/topics/img/gitlab_flow_messy_flow.png
Binary files differ
diff --git a/doc/workflow/img/mr_inline_comments.png b/doc/topics/img/gitlab_flow_mr_inline_comments.png
index a18801f56e4..a18801f56e4 100644
--- a/doc/workflow/img/mr_inline_comments.png
+++ b/doc/topics/img/gitlab_flow_mr_inline_comments.png
Binary files differ
diff --git a/doc/workflow/img/production_branch.png b/doc/topics/img/gitlab_flow_production_branch.png
index c132d51bfb6..c132d51bfb6 100644
--- a/doc/workflow/img/production_branch.png
+++ b/doc/topics/img/gitlab_flow_production_branch.png
Binary files differ
diff --git a/doc/workflow/img/rebase.png b/doc/topics/img/gitlab_flow_rebase.png
index fe865177ba8..fe865177ba8 100644
--- a/doc/workflow/img/rebase.png
+++ b/doc/topics/img/gitlab_flow_rebase.png
Binary files differ
diff --git a/doc/workflow/img/release_branches.png b/doc/topics/img/gitlab_flow_release_branches.png
index 0a7f61d0248..0a7f61d0248 100644
--- a/doc/workflow/img/release_branches.png
+++ b/doc/topics/img/gitlab_flow_release_branches.png
Binary files differ
diff --git a/doc/workflow/img/remove_checkbox.png b/doc/topics/img/gitlab_flow_remove_checkbox.png
index fb0e792b37b..fb0e792b37b 100644
--- a/doc/workflow/img/remove_checkbox.png
+++ b/doc/topics/img/gitlab_flow_remove_checkbox.png
Binary files differ
diff --git a/doc/topics/index.md b/doc/topics/index.md
index b51f24b02e4..71048ec5aa4 100644
--- a/doc/topics/index.md
+++ b/doc/topics/index.md
@@ -11,6 +11,7 @@ tutorials, technical overviews, blog posts) and videos.
- [Authentication](authentication/index.md)
- [Continuous Integration (GitLab CI)](../ci/README.md)
- [Git](git/index.md)
+- [GitLab Flow](gitlab_flow.md)
- [GitLab Installation](../install/README.md)
- [GitLab Pages](../user/project/pages/index.md)
diff --git a/doc/university/README.md b/doc/university/README.md
index 8f5a5038bb9..9725cb14fc5 100644
--- a/doc/university/README.md
+++ b/doc/university/README.md
@@ -129,7 +129,7 @@ The GitLab University curriculum is composed of GitLab videos, screencasts, pres
1. [GitLab Flow vs Forking in GitLab - Video](https://www.youtube.com/watch?v=UGotqAUACZA)
1. [GitLab Flow Overview](https://about.gitlab.com/blog/2014/09/29/gitlab-flow/)
1. [Always Start with an Issue](https://about.gitlab.com/blog/2016/03/03/start-with-an-issue/)
-1. [GitLab Flow Documentation](../workflow/gitlab_flow.md)
+1. [GitLab Flow Documentation](../topics/gitlab_flow.md)
### 2.5. GitLab Comparisons
diff --git a/doc/university/support/README.md b/doc/university/support/README.md
index 1c77fbeb8d6..ebdd453ff3c 100644
--- a/doc/university/support/README.md
+++ b/doc/university/support/README.md
@@ -170,7 +170,7 @@ Some tickets need specific knowledge or a deep understanding of a particular com
Move on to understanding some of GitLab's more advanced features. You can make use of GitLab.com to understand the features from an end-user perspective and then use your own instance to understand setup and configuration of the feature from an Administrative perspective
-- Set up and try [Git LFS](../../workflow/lfs/manage_large_binaries_with_git_lfs.md)
+- Set up and try [Git LFS](../../administration/lfs/manage_large_binaries_with_git_lfs.md)
- Get to know the [GitLab API](../../api/README.md), its capabilities and shortcomings
- Learn how to [migrate from SVN to Git](../../user/project/import/svn.md)
- Set up [GitLab CI](../../ci/quick_start/README.md)
diff --git a/doc/university/training/gitlab_flow.md b/doc/university/training/gitlab_flow.md
index 66e645a0af8..b80eb031aee 100644
--- a/doc/university/training/gitlab_flow.md
+++ b/doc/university/training/gitlab_flow.md
@@ -38,7 +38,7 @@ type: reference
## More details
-For more information, read through the [GitLab Flow](../../workflow/gitlab_flow.md)
+For more information, read through the [GitLab Flow](../../topics/gitlab_flow.md)
documentation.
<!-- ## Troubleshooting
diff --git a/doc/update/README.md b/doc/update/README.md
index 965f29bc8aa..6834deb1a85 100644
--- a/doc/update/README.md
+++ b/doc/update/README.md
@@ -69,7 +69,13 @@ before continuing the upgrading procedure. While this won't require downtime
between upgrading major/minor releases, allowing the background migrations to
finish. The time necessary to complete these migrations can be reduced by
increasing the number of Sidekiq workers that can process jobs in the
-`background_migration` queue.
+`background_migration` queue. To check the size of this queue,
+[start a Rails console session](https://docs.gitlab.com/omnibus/maintenance/#starting-a-rails-console-session)
+and run the command below:
+
+```ruby
+Sidekiq::Queue.new('background_migration').size
+```
As a rule of thumb, any database smaller than 10 GB won't take too much time to
upgrade; perhaps an hour at most per minor release. Larger databases however may
diff --git a/doc/user/admin_area/activating_deactivating_users.md b/doc/user/admin_area/activating_deactivating_users.md
new file mode 100644
index 00000000000..78a07f4a04e
--- /dev/null
+++ b/doc/user/admin_area/activating_deactivating_users.md
@@ -0,0 +1,66 @@
+---
+type: howto
+---
+
+# Activating and deactivating users
+
+GitLab administrators can deactivate and activate users.
+
+## Deactivating a user
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/63921) in GitLab 12.4.
+
+In order to temporarily prevent access by a GitLab user that has no recent activity, administrators
+can choose to deactivate the user.
+
+Deactivating a user is functionally identical to [blocking a user](blocking_unblocking_users.md),
+with the following differences:
+
+- It does not prohibit the user from logging back in via the UI.
+- Once a deactivated user logs back into the GitLab UI, their account is set to active.
+
+A deactivated user:
+
+- Cannot access Git repositories or the API.
+- Will not receive any notifications from GitLab.
+- Will not be able to use [slash commands](../../integration/slash_commands.md).
+
+Personal projects, and group and user history of the deactivated user will be left intact.
+
+A user can be deactivated from the Admin Area. To do this:
+
+1. Navigate to **Admin Area > Overview > Users**.
+1. Select a user.
+1. Under the **Account** tab, click **Deactivate user**.
+
+Please note that for the deactivation option to be visible to an admin, the user:
+
+- Must be currently active.
+- Should not have any activity in the last 180 days.
+
+Users can also be deactivated using the [GitLab API](../../api/users.html#deactivate-user).
+
+NOTE: **Note:**
+A deactivated user does not consume a [seat](../../subscriptions/index.md#managing-subscriptions).
+
+## Activating a user
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/63921) in GitLab 12.4.
+
+A deactivated user can be activated from the Admin Area.
+
+To do this:
+
+1. Navigate to **Admin Area > Overview > Users**.
+1. Click on the **Deactivated** tab.
+1. Select a user.
+1. Under the **Account** tab, click **Activate user**.
+
+Users can also be activated using the [GitLab API](../../api/users.html#activate-user).
+
+NOTE: **Note:**
+Activating a user will change the user's state to active and it consumes a
+[seat](../../subscriptions/index.md#managing-subscriptions).
+
+TIP: **Tip:**
+A deactivated user can also activate their account by themselves by simply logging back via the UI.
diff --git a/doc/user/admin_area/blocking_unblocking_users.md b/doc/user/admin_area/blocking_unblocking_users.md
new file mode 100644
index 00000000000..8868170169e
--- /dev/null
+++ b/doc/user/admin_area/blocking_unblocking_users.md
@@ -0,0 +1,48 @@
+---
+type: howto
+---
+
+# Blocking and unblocking users
+
+GitLab administrators block and unblock users.
+
+## Blocking a user
+
+In order to completely prevent access of a user to the GitLab instance, administrators can choose to
+block the user.
+
+Users can be blocked [via an abuse report](abuse_reports.md#blocking-users),
+or directly from the Admin Area. To do this:
+
+1. Navigate to **Admin Area > Overview > Users**.
+1. Select a user.
+1. Under the **Account** tab, click **Block user**.
+
+A blocked user:
+
+- Will not be able to login.
+- Cannot access Git repositories or the API.
+- Will not receive any notifications from GitLab.
+- Will not be able to use [slash commands](../../integration/slash_commands.md).
+
+Personal projects, and group and user history of the blocked user will be left intact.
+
+Users can also be blocked using the [GitLab API](../../api/users.html#block-user).
+
+NOTE: **Note:**
+A blocked user does not consume a [seat](../../subscriptions/index.md#managing-subscriptions).
+
+## Unblocking a user
+
+A blocked user can be unblocked from the Admin Area. To do this:
+
+1. Navigate to **Admin Area > Overview > Users**.
+1. Click on the **Blocked** tab.
+1. Select a user.
+1. Under the **Account** tab, click **Unblock user**.
+
+Users can also be unblocked using the [GitLab API](../../api/users.html#unblock-user).
+
+NOTE: **Note:**
+Unblocking a user will change the user's state to active and it consumes a
+[seat](../../subscriptions/index.md#managing-subscriptions).
diff --git a/doc/user/admin_area/diff_limits.md b/doc/user/admin_area/diff_limits.md
index 5117b5f476f..4e24c25de8f 100644
--- a/doc/user/admin_area/diff_limits.md
+++ b/doc/user/admin_area/diff_limits.md
@@ -6,7 +6,7 @@ type: reference
You can set a maximum size for display of diff files (patches).
-For details about diff files, [View changes between files](../project/merge_requests/index.md#view-changes-between-file-versions).
+For details about diff files, [View changes between files](../project/merge_requests/reviewing_and_managing_merge_requests.md#view-changes-between-file-versions).
## Maximum diff patch size
diff --git a/doc/user/admin_area/index.md b/doc/user/admin_area/index.md
index c75a8bcac79..35cb2b42c56 100644
--- a/doc/user/admin_area/index.md
+++ b/doc/user/admin_area/index.md
@@ -112,8 +112,8 @@ To list users matching a specific criteria, click on one of the following tabs o
- **2FA Enabled**
- **2FA Disabled**
- **External**
-- **Blocked**
-- **Deactivated**
+- **[Blocked](blocking_unblocking_users.md)**
+- **[Deactivated](activating_deactivating_users.md)**
- **Without projects**
For each user, their username, email address, are listed, also the date their account was
diff --git a/doc/user/admin_area/monitoring/health_check.md b/doc/user/admin_area/monitoring/health_check.md
index 6439607de33..103d7ecc573 100644
--- a/doc/user/admin_area/monitoring/health_check.md
+++ b/doc/user/admin_area/monitoring/health_check.md
@@ -13,7 +13,7 @@ type: concepts, howto
GitLab provides liveness and readiness probes to indicate service health and
reachability to required services. These probes report on the status of the
database connection, Redis connection, and access to the filesystem. These
-endpoints [can be provided to schedulers like Kubernetes][kubernetes] to hold
+endpoints [can be provided to schedulers like Kubernetes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) to hold
traffic until the system is ready or restart the container as needed.
## IP whitelist
@@ -39,7 +39,11 @@ GET http://localhost/-/liveness
## Health
-Checks whether the application server is running. It does not verify the database or other services are running.
+Checks whether the application server is running.
+It does not verify the database or other services
+are running. This endpoint circumvents Rails Controllers
+and is implemented as additional middleware `BasicHealthCheck`
+very early into the request processing lifecycle.
```text
GET /-/health
@@ -59,10 +63,17 @@ GitLab OK
## Readiness
-The readiness probe checks whether the GitLab instance is ready to use. It checks the dependent services (Database, Redis, Gitaly etc.) and gives a status for each.
+The readiness probe checks whether the GitLab instance is ready
+to accept traffic via Rails Controllers. The check by default
+does validate only instance-checks.
+
+If the `all=1` parameter is specified, the check will also validate
+the dependent services (Database, Redis, Gitaly etc.)
+and gives a status for each.
```text
GET /-/readiness
+GET /-/readiness?all=1
```
Example request:
@@ -75,37 +86,30 @@ Example response:
```json
{
- "db_check":{
+ "master_check":[{
"status":"failed",
- "message": "unexpected Db check result: 0"
- },
- "redis_check":{
- "status":"ok"
- },
- "cache_check":{
- "status":"ok"
- },
- "queues_check":{
- "status":"ok"
- },
- "shared_state_check":{
- "status":"ok"
- },
- "gitaly_check":{
- "status":"ok",
- "labels":{
- "shard":"default"
- }
- }
- }
+ "message": "unexpected Master check result: false"
+ }],
+ ...
+}
```
+On failure, the endpoint will return a `503` HTTP status code.
+
+This check does hit the database and Redis if authenticated via `token`.
+
+This check is being exempt from Rack Attack.
+
## Liveness
DANGER: **Warning:**
-In Gitlab [12.4](https://about.gitlab.com/upcoming-releases/) the response body of the Liveness check will change to match the example below.
+In Gitlab [12.4](https://about.gitlab.com/upcoming-releases/)
+the response body of the Liveness check was changed
+to match the example below.
-The liveness probe checks whether the application server is alive. Unlike the [`health`](#health) check, this check hits the database.
+Checks whether the application server is running.
+This probe is used to know if Rails Controllers
+are not deadlocked due to a multi-threading.
```text
GET /-/liveness
@@ -127,7 +131,9 @@ On success, the endpoint will return a `200` HTTP status code, and a response li
}
```
-On failure, the endpoint will return a `500` HTTP status code.
+On failure, the endpoint will return a `503` HTTP status code.
+
+This check is being exempt from Rack Attack.
## Access token (Deprecated)
@@ -163,4 +169,3 @@ but commented out to help encourage others to add to it in the future. -->
[pingdom]: https://www.pingdom.com
[nagios-health]: https://nagios-plugins.org/doc/man/check_http.html
[newrelic-health]: https://docs.newrelic.com/docs/alerts/alert-policies/downtime-alerts/availability-monitoring
-[kubernetes]: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/
diff --git a/doc/user/admin_area/settings/account_and_limit_settings.md b/doc/user/admin_area/settings/account_and_limit_settings.md
index a1beee404eb..e443127a8a0 100644
--- a/doc/user/admin_area/settings/account_and_limit_settings.md
+++ b/doc/user/admin_area/settings/account_and_limit_settings.md
@@ -32,7 +32,7 @@ For instance, consider the following workflow:
1. Your team develops apps which require large files to be stored in
the application repository.
-1. Although you have enabled [Git LFS](../../../workflow/lfs/manage_large_binaries_with_git_lfs.md#git-lfs)
+1. Although you have enabled [Git LFS](../../../administration/lfs/manage_large_binaries_with_git_lfs.md#git-lfs)
to your project, your storage has grown significantly.
1. Before you exceed available storage, you set up a limit of 10 GB
per repository.
diff --git a/doc/user/admin_area/settings/continuous_integration.md b/doc/user/admin_area/settings/continuous_integration.md
index c60b3323105..f775dd8bbb4 100644
--- a/doc/user/admin_area/settings/continuous_integration.md
+++ b/doc/user/admin_area/settings/continuous_integration.md
@@ -134,6 +134,19 @@ Once that time passes, the jobs will be archived and no longer able to be
retried. Make it empty to never expire jobs. It has to be no less than 1 day,
for example: <code>15 days</code>, <code>1 month</code>, <code>2 years</code>.
+## Default CI configuration path
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/18073) in GitLab 12.5.
+
+The default CI configuration file path for new projects can be set in the Admin
+area of your GitLab instance (`.gitlab-ci.yml` if not set):
+
+1. Go to **Admin area > Settings > Continuous Integration and Deployment**.
+1. Input the new path in the **Default CI configuration path** field.
+1. Hit **Save changes** for the changes to take effect.
+
+It is also possible to specify a [custom CI configuration path for a specific project](../../project/pipelines/settings.md#custom-ci-configuration-path).
+
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
diff --git a/doc/user/admin_area/settings/email.md b/doc/user/admin_area/settings/email.md
index 6026f9dc735..4611d5f5c77 100644
--- a/doc/user/admin_area/settings/email.md
+++ b/doc/user/admin_area/settings/email.md
@@ -8,7 +8,7 @@ You can customize some of the content in emails sent from your GitLab instance.
## Custom logo
-The logo in the header of some emails can be customized, see the [logo customization section](../../../customization/branded_page_and_email_header.md).
+The logo in the header of some emails can be customized, see the [logo customization section](../appearance.md#navigation-bar).
## Custom additional text **(PREMIUM ONLY)**
diff --git a/doc/user/admin_area/settings/img/two_factor_grace_period.png b/doc/user/admin_area/settings/img/two_factor_grace_period.png
new file mode 100644
index 00000000000..e7fb52969aa
--- /dev/null
+++ b/doc/user/admin_area/settings/img/two_factor_grace_period.png
Binary files differ
diff --git a/doc/user/admin_area/settings/index.md b/doc/user/admin_area/settings/index.md
index 4ca91ae5339..42f496bfbfa 100644
--- a/doc/user/admin_area/settings/index.md
+++ b/doc/user/admin_area/settings/index.md
@@ -14,6 +14,7 @@ include:
- [Continuous Integration and Deployment](continuous_integration.md)
- [Email](email.md)
- [Sign up restrictions](sign_up_restrictions.md)
+- [Sign in restrictions](sign_in_restrictions.md)
- [Terms](terms.md)
- [Third party offers](third_party_offers.md)
- [Usage statistics](usage_statistics.md)
diff --git a/doc/user/admin_area/settings/sign_in_restrictions.md b/doc/user/admin_area/settings/sign_in_restrictions.md
new file mode 100644
index 00000000000..0975766400f
--- /dev/null
+++ b/doc/user/admin_area/settings/sign_in_restrictions.md
@@ -0,0 +1,56 @@
+---
+type: reference
+---
+
+# Sign-in restrictions **(CORE ONLY)**
+
+You can use sign-in restrictions to limit the authentication with password
+for web interface and Git over HTTP(S), two-factor authentication enforcing, as well as
+as configuring the home page URL and after sign-out path.
+
+## Password authentication enabled
+
+You can restrict the password authentication for web interface and Git over HTTP(S):
+
+- **Web interface**: When this feature is disabled, an [external authentication provider](../../../administration/auth/README.md) must be used.
+- **Git over HTTP(S)**: When this feature is disabled, a [Personal Access Token](../../profile/personal_access_tokens.md) must be used to authenticate.
+
+## Two-factor authentication
+
+When this feature enabled, all users will have to use the [two-factor authentication](../../profile/account/two_factor_authentication.md).
+
+Once the two-factor authentication is configured as mandatory, the users will be allowed
+to skip forced configuration of two-factor authentication for the configurable grace
+period in hours.
+
+![Two-factor grace period](img/two_factor_grace_period.png)
+
+## Sign-in information
+
+All users that are not logged-in will be redirected to the page represented by the configured
+"Home page URL" if value is not empty.
+
+All users will be redirect to the page represented by the configured "After sign out path"
+after sign out if value is not empty.
+
+If a "Sign in text" in Markdown format is provided, then every user will be presented with
+this message after logging-in.
+
+## Settings
+
+To access this feature:
+
+1. Navigate to the **Settings > General** in the Admin area.
+1. Expand the **Sign-in restrictions** section.
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/user/admin_area/settings/usage_statistics.md b/doc/user/admin_area/settings/usage_statistics.md
index 98126f72a78..81edd9eac34 100644
--- a/doc/user/admin_area/settings/usage_statistics.md
+++ b/doc/user/admin_area/settings/usage_statistics.md
@@ -31,7 +31,7 @@ patches will need to be backported, making sure active GitLab instances remain
secure.
If you disable version check, this information will not be collected. Enable or
-disable the version check at **Admin area > Settings > Usage statistics**.
+disable the version check at **Admin area > Settings > Metrics and profiling > Usage statistics**.
## Usage ping **(CORE ONLY)**
@@ -85,7 +85,7 @@ will be able to show [usage statistics](../../instance_statistics/index.md)
of your instance to your users.
This can be restricted to admins by selecting "Only admins" in the Instance
-Statistics visibility section under **Admin area > Settings > Usage statistics**.
+Statistics visibility section under **Admin area > Settings > Metrics and profiling > Usage statistics**.
<!-- ## Troubleshooting
diff --git a/doc/user/admin_area/settings/visibility_and_access_controls.md b/doc/user/admin_area/settings/visibility_and_access_controls.md
index f718e31e8bd..73406fd5037 100644
--- a/doc/user/admin_area/settings/visibility_and_access_controls.md
+++ b/doc/user/admin_area/settings/visibility_and_access_controls.md
@@ -177,7 +177,7 @@ For more details, see [SSH key restrictions](../../../security/ssh_keys_restrict
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3586) in GitLab 10.3.
-This option is enabled by default. By disabling it, both [pull and push mirroring](../../../workflow/repository_mirroring.md) will no longer
+This option is enabled by default. By disabling it, both [pull and push mirroring](../../project/repository/repository_mirroring.md) will no longer
work in every repository and can only be re-enabled by an admin on a per-project basis.
![Mirror settings](img/mirror_settings.png)
diff --git a/doc/user/analytics/cycle_analytics.md b/doc/user/analytics/cycle_analytics.md
index e17202645d3..c75f101b0e1 100644
--- a/doc/user/analytics/cycle_analytics.md
+++ b/doc/user/analytics/cycle_analytics.md
@@ -3,9 +3,10 @@
> - Introduced prior to GitLab 12.3 at the project level.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/12077) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.3 at the group level.
-Cycle Analytics measures the time spent to go from an [idea to production] - also known
-as cycle time - for each of your projects. Cycle Analytics displays the median time for an idea to
-reach production, along with the time typically spent in each DevOps stage along the way.
+Cycle Analytics measures the time spent to go from an
+[idea to production](https://about.gitlab.com/blog/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/#from-idea-to-production-with-gitlab)
+(also known as cycle time) for each of your projects. Cycle Analytics displays the median time
+spent in each stage defined in the process.
NOTE: **Note:**
Use the `cycle_analytics` feature flag to enable at the group level.
@@ -14,8 +15,8 @@ Cycle Analytics is useful in order to quickly determine the velocity of a given
project. It points to bottlenecks in the development process, enabling management
to uncover, triage, and identify the root cause of slowdowns in the software development life cycle.
-Cycle Analytics is tightly coupled with the [GitLab flow] and calculates a separate median for each
-stage.
+Cycle Analytics is tightly coupled with the [GitLab flow](../../topics/gitlab_flow.md) and
+calculates a separate median for each stage.
## Overview
@@ -46,6 +47,16 @@ There are seven stages that are tracked as part of the Cycle Analytics calculati
- **Production** (Total)
- Total lifecycle time; i.e. the velocity of the project or team
+## Date ranges
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/13216) in GitLab 12.4.
+
+GitLab provides the ability to filter analytics based on a date range. To filter results:
+
+1. Select a group.
+1. Optionally select a project.
+1. Select a date range using the available date pickers.
+
## How the data is measured
Cycle Analytics records cycle time and data based on the project issues with the
@@ -53,7 +64,8 @@ exception of the staging and production stages, where only data deployed to
production are measured.
Specifically, if your CI is not set up and you have not defined a `production`
-or `production/*` [environment], then you will not have any data for those stages.
+or `production/*` [environment](../../ci/yaml/README.md#environment), then you will not have any
+data for those stages.
Each stage of Cycle Analytics is further described in the table below.
@@ -64,11 +76,9 @@ Each stage of Cycle Analytics is further described in the table below.
| Code | Measures the median time between pushing a first commit (previous stage) and creating a merge request (MR) related to that commit. The key to keep the process tracked is to include the [issue closing pattern](../project/issues/managing_issues.md#closing-issues-automatically) to the description of the merge request (for example, `Closes #xxx`, where `xxx` is the number of the issue related to this merge request). If the issue closing pattern is not present in the merge request description, the MR is not considered to the measurement time of the stage. |
| Test | Measures the median time to run the entire pipeline for that project. It's related to the time GitLab CI takes to run every job for the commits pushed to that merge request defined in the previous stage. It is basically the start->finish time for all pipelines. |
| Review | Measures the median time taken to review the merge request that has closing issue pattern, between its creation and until it's merged. |
-| Staging | Measures the median time between merging the merge request with closing issue pattern until the very first deployment to production. It's tracked by the [environment] set to `production` or matching `production/*` (case-sensitive, `Production` won't work) in your GitLab CI configuration. If there isn't a production environment, this is not tracked. |
+| Staging | Measures the median time between merging the merge request with closing issue pattern until the very first deployment to production. It's tracked by the environment set to `production` or matching `production/*` (case-sensitive, `Production` won't work) in your GitLab CI configuration. If there isn't a production environment, this is not tracked. |
| Production| The sum of all time (medians) taken to run the entire process, from issue creation to deploying the code to production. |
----
-
How this works, behind the scenes:
1. Issues and merge requests are grouped together in pairs, such that for each
@@ -81,12 +91,12 @@ How this works, behind the scenes:
we need for the stages, like issue creation date, merge request merge time,
etc.
-To sum up, anything that doesn't follow [GitLab flow] will not be tracked and the
+To sum up, anything that doesn't follow [GitLab flow](../../workflow/gitlab_flow.md) will not be tracked and the
Cycle Analytics dashboard will not present any data for:
-- merge requests that do not close an issue.
-- issues not labeled with a label present in the Issue Board or for issues not assigned a milestone.
-- staging and production stages, if the project has no `production` or `production/*`
+- Merge requests that do not close an issue.
+- Issues not labeled with a label present in the Issue Board or for issues not assigned a milestone.
+- Staging and production stages, if the project has no `production` or `production/*`
environment.
## Example workflow
@@ -107,7 +117,7 @@ environments is configured.
1. Push branch and create a merge request that contains the [issue closing pattern](../project/issues/managing_issues.md#closing-issues-automatically)
in its description at 14:00 (stop of **Code** stage / start of **Test** and
**Review** stages).
-1. The CI starts running your scripts defined in [`.gitlab-ci.yml`][yml] and
+1. The CI starts running your scripts defined in [`.gitlab-ci.yml`](../../ci/yaml/README.md) and
takes 5min (stop of **Test** stage).
1. Review merge request, ensure that everything is OK and merge the merge
request at 19:00. (stop of **Review** stage / start of **Staging** stage).
@@ -151,7 +161,7 @@ The current permissions on the Project Cycle Analytics dashboard are:
- Internal projects - any authenticated user can access.
- Private projects - any member Guest and above can access.
-You can [read more about permissions][permissions] in general.
+You can [read more about permissions](../../ci/yaml/README.md) in general.
NOTE: **Note:**
As of GitLab 12.3, the project-level page is deprecated. You should access
@@ -169,14 +179,6 @@ For Cycle Analytics functionality introduced in GitLab 12.3 and later:
Learn more about Cycle Analytics in the following resources:
-- [Cycle Analytics feature page](https://about.gitlab.com/product/cycle-analytics/)
-- [Cycle Analytics feature preview](https://about.gitlab.com/blog/2016/09/16/feature-preview-introducing-cycle-analytics/)
-- [Cycle Analytics feature highlight](https://about.gitlab.com/blog/2016/09/21/cycle-analytics-feature-highlight/)
-
-[ce-5986]: https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/5986
-[ce-20975]: https://gitlab.com/gitlab-org/gitlab-foss/issues/20975
-[environment]: ../../ci/yaml/README.md#environment
-[GitLab flow]: ../../workflow/gitlab_flow.md
-[idea to production]: https://about.gitlab.com/blog/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/#from-idea-to-production-with-gitlab
-[permissions]: ../permissions.md
-[yml]: ../../ci/yaml/README.md
+- [Cycle Analytics feature page](https://about.gitlab.com/product/cycle-analytics/).
+- [Cycle Analytics feature preview](https://about.gitlab.com/blog/2016/09/16/feature-preview-introducing-cycle-analytics/).
+- [Cycle Analytics feature highlight](https://about.gitlab.com/blog/2016/09/21/cycle-analytics-feature-highlight/).
diff --git a/doc/user/analytics/productivity_analytics.md b/doc/user/analytics/productivity_analytics.md
index aecbac15c98..40295e47e89 100644
--- a/doc/user/analytics/productivity_analytics.md
+++ b/doc/user/analytics/productivity_analytics.md
@@ -42,10 +42,19 @@ The following metrics and visualizations are available on a project or group lev
- Number of lines of code per commit.
- Number of files touched.
- Scatterplot showing all MRs merged on a certain date, together with the days it took to complete the action and a 30 day rolling median.
- - Users can zoom in and out on specific days of interest.
- Table showing the list of merge requests with their respective time duration metrics.
- Users can sort by any of the above metrics.
+## Date ranges
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/13188) in GitLab 12.4.
+
+GitLab has the ability to filter analytics based on a date range. To filter results:
+
+1. Select a group.
+1. Optionally select a project.
+1. Select a date range using the available date pickers.
+
## Permissions
The **Productivity Analytics** dashboard can be accessed only:
diff --git a/doc/user/application_security/container_scanning/index.md b/doc/user/application_security/container_scanning/index.md
index 14dae56f087..931755c6305 100644
--- a/doc/user/application_security/container_scanning/index.md
+++ b/doc/user/application_security/container_scanning/index.md
@@ -40,10 +40,9 @@ to perform audits for your Docker-based apps.
To enable Container Scanning in your pipeline, you need:
- A GitLab Runner with the
- [`docker`](https://docs.gitlab.com/runner/executors/docker.html#use-docker-in-docker-with-privileged-mode) or
- [`kubernetes`](https://docs.gitlab.com/runner/install/kubernetes.html#running-privileged-containers-for-the-runners)
- executor running in privileged mode. If you're using the shared Runners on GitLab.com,
- this is enabled by default.
+ [`docker`](https://docs.gitlab.com/runner/executors/docker.html) or
+ [`kubernetes`](https://docs.gitlab.com/runner/install/kubernetes.html)
+ executor.
- Docker `18.09.03` or higher installed on the machine where the Runners are
running. If you're using the shared Runners on GitLab.com, this is already
the case.
@@ -150,17 +149,18 @@ container_scanning:
Container Scanning can be [configured](#overriding-the-container-scanning-template)
using environment variables.
-| Environment Variable | Description | Default |
-| ------ | ------ | ------ |
-| `KLAR_TRACE` | Set to true to enable more verbose output from klar. | `"false"` |
-| `DOCKER_USER` | Username for accessing a Docker registry requiring authentication. | `$CI_REGISTRY_USER` |
-| `DOCKER_PASSWORD` | Password for accessing a Docker registry requiring authentication. | `$CI_REGISTRY_PASSWORD` |
-| `CLAIR_OUTPUT` | Severity level threshold. Vulnerabilities with severity level higher than or equal to this threshold will be outputted. Supported levels are `Unknown`, `Negligible`, `Low`, `Medium`, `High`, `Critical` and `Defcon1`. | `Unknown` |
-| `REGISTRY_INSECURE` | Allow [Klar](https://github.com/optiopay/klar) to access insecure registries (HTTP only). Should only be set to `true` when testing the image locally. | `"false"` |
-| `CLAIR_VULNERABILITIES_DB_URL` | This variable is explicitly set in the [services section](https://gitlab.com/gitlab-org/gitlab/blob/30522ca8b901223ac8c32b633d8d67f340b159c1/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml#L17-19) of the `Container-Scanning.gitlab-ci.yml` file and defaults to `clair-vulnerabilities-db`. This value represents the address that the [postgres server hosting the vulnerabilities definitions](https://hub.docker.com/r/arminc/clair-db) is running on and **shouldn't be changed** unless you're running the image locally as described in the [Running the scanning tool](https://gitlab.com/gitlab-org/security-products/analyzers/klar/#running-the-scanning-tool) section of the [klar readme](https://gitlab.com/gitlab-org/security-products/analyzers/klar). | `clair-vulnerabilities-db` |
-| `CI_APPLICATION_REPOSITORY` | Docker repository URL for the image to be scanned. | `$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG` |
-| `CI_APPLICATION_TAG` | Docker respository tag for the image to be scanned. | `$CI_COMMIT_SHA` |
-| `CLAIR_DB_IMAGE_TAG` | The Docker image tag for the [postgres server hosting the vulnerabilities definitions](https://hub.docker.com/r/arminc/clair-db). It can be useful to override this value with a specific version, for example, to provide a consistent set of vulnerabilities for integration testing purposes. | `latest` |
+| Environment Variable | Description | Default |
+| ------ | ------ | ------ |
+| `KLAR_TRACE` | Set to true to enable more verbose output from klar. | `"false"` |
+| `DOCKER_USER` | Username for accessing a Docker registry requiring authentication. | `$CI_REGISTRY_USER` |
+| `DOCKER_PASSWORD` | Password for accessing a Docker registry requiring authentication. | `$CI_REGISTRY_PASSWORD` |
+| `CLAIR_OUTPUT` | Severity level threshold. Vulnerabilities with severity level higher than or equal to this threshold will be outputted. Supported levels are `Unknown`, `Negligible`, `Low`, `Medium`, `High`, `Critical` and `Defcon1`. | `Unknown` |
+| `REGISTRY_INSECURE` | Allow [Klar](https://github.com/optiopay/klar) to access insecure registries (HTTP only). Should only be set to `true` when testing the image locally. | `"false"` |
+| `CLAIR_VULNERABILITIES_DB_URL` | This variable is explicitly set in the [services section](https://gitlab.com/gitlab-org/gitlab/blob/30522ca8b901223ac8c32b633d8d67f340b159c1/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml#L17-19) of the `Container-Scanning.gitlab-ci.yml` file and defaults to `clair-vulnerabilities-db`. This value represents the address that the [postgres server hosting the vulnerabilities definitions](https://hub.docker.com/r/arminc/clair-db) is running on and **shouldn't be changed** unless you're running the image locally as described in the [Running the scanning tool](https://gitlab.com/gitlab-org/security-products/analyzers/klar/#running-the-scanning-tool) section of the [GitLab klar analyzer readme](https://gitlab.com/gitlab-org/security-products/analyzers/klar). | `clair-vulnerabilities-db` |
+| `CI_APPLICATION_REPOSITORY` | Docker repository URL for the image to be scanned. | `$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG` |
+| `CI_APPLICATION_TAG` | Docker respository tag for the image to be scanned. | `$CI_COMMIT_SHA` |
+| `CLAIR_DB_IMAGE` | The Docker image name and tag for the [postgres server hosting the vulnerabilities definitions](https://hub.docker.com/r/arminc/clair-db). It can be useful to override this value with a specific version, for example, to provide a consistent set of vulnerabilities for integration testing purposes, or to refer to a locally hosted vulnerabilities database for an on-premise air-gapped installation. | `arminc/clair-db:latest` |
+| `CLAIR_DB_IMAGE_TAG` | (**DEPRECATED - use `CLAIR_DB_IMAGE` instead**) The Docker image tag for the [postgres server hosting the vulnerabilities definitions](https://hub.docker.com/r/arminc/clair-db). It can be useful to override this value with a specific version, for example, to provide a consistent set of vulnerabilities for integration testing purposes. | `latest` |
## Security Dashboard
@@ -178,6 +178,47 @@ Once a vulnerability is found, you can interact with it. Read more on how to
For more information about the vulnerabilities database update, check the
[maintenance table](../index.md#maintenance-and-update-of-the-vulnerabilities-database).
+## Running Container Scanning in an offline air-gapped installation
+
+Container Scanning can be executed on an offline air-gapped GitLab Ultimate installation using the following process:
+
+1. Host the following Docker images on a [local Docker container registry](../../packages/container_registry/index.md):
+ - [arminc/clair-db vulnerabilities database](https://hub.docker.com/r/arminc/clair-db)
+ - [GitLab klar analyzer](https://gitlab.com/gitlab-org/security-products/analyzers/klar)
+1. [Override the container scanning template](#overriding-the-container-scanning-template) in your `.gitlab-ci.yml` file to refer to the Docker images hosted on your local Docker container registry:
+
+ ```yaml
+ include:
+ - template: Container-Scanning.gitlab-ci.yml
+
+ container_scanning:
+ image: $CI_REGISTRY/namespace/gitlab-klar-analyzer
+ variables:
+ CLAIR_DB_IMAGE: $CI_REGISTRY/namespace/clair-vulnerabilities-db
+ ```
+
+It may be worthwhile to set up a [scheduled pipeline](../../project/pipelines/schedules.md) to automatically build a new version of the vulnerabilities database on a preset schedule. You can use the following `.gitlab-yml.ci` as a template:
+
+```yaml
+image: docker:stable
+
+services:
+ - docker:stable-dind
+
+stages:
+ - build
+
+build_latest_vulnerabilities:
+ stage: build
+ script:
+ - docker pull arminc/clair-db:latest
+ - docker tag arminc/clair-db:latest $CI_REGISTRY/namespace/clair-vulnerabilities-db
+ - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
+ - docker push $CI_REGISTRY/namespace/clair-vulnerabilities-db
+```
+
+The above template will work for a GitLab Docker registry running on a local installation, however, if you're using a non-GitLab Docker registry, you'll need to change the `$CI_REGISTRY` value and the `docker login` credentials to match the details of your local registry.
+
## Troubleshooting
### docker: Error response from daemon: failed to copy xattrs
diff --git a/doc/user/application_security/dast/index.md b/doc/user/application_security/dast/index.md
index 951c4b9dd73..d285b5ff585 100644
--- a/doc/user/application_security/dast/index.md
+++ b/doc/user/application_security/dast/index.md
@@ -339,3 +339,33 @@ questions that you know someone might ask.
Each scenario can be a third-level heading, e.g. `### Getting error message X`.
If you have none to add when creating a doc, leave this section in place
but commented out to help encourage others to add to it in the future. -->
+
+## Troubleshooting
+
+### Running out of memory
+
+By default, ZAProxy, which DAST relies on, is allocated memory that sums to 25%
+of the total memory on the host.
+Since it keeps most of its information in memory during a scan,
+it is possible for DAST to run out of memory while scanning large applications.
+This results in the following error:
+
+```
+[zap.out] java.lang.OutOfMemoryError: Java heap space
+```
+
+Fortunately, it is straightforward to increase the amount of memory available
+for DAST by overwriting the `script` key in the DAST template:
+
+```yaml
+include:
+ template: DAST.gitlab-ci.yml
+
+dast:
+ script:
+ - export DAST_WEBSITE=${DAST_WEBSITE:-$(cat environment_url.txt)}
+ - /analyze -t $DAST_WEBSITE -z"-Xmx3072m"
+```
+
+Here, DAST is being allocated 3072 MB.
+Change the number after `-Xmx` to the required memory amount.
diff --git a/doc/user/application_security/dependency_list/img/dependency_list_v12_4.png b/doc/user/application_security/dependency_list/img/dependency_list_v12_4.png
new file mode 100644
index 00000000000..4687987b763
--- /dev/null
+++ b/doc/user/application_security/dependency_list/img/dependency_list_v12_4.png
Binary files differ
diff --git a/doc/user/application_security/dependency_list/index.md b/doc/user/application_security/dependency_list/index.md
index 8366e943ccc..2828d487153 100644
--- a/doc/user/application_security/dependency_list/index.md
+++ b/doc/user/application_security/dependency_list/index.md
@@ -17,7 +17,7 @@ sidebar.
## Viewing dependencies
-![Dependency List](img/dependency_list_v12_3.png)
+![Dependency List](img/dependency_list_v12_4.png)
Dependencies are displayed with the following information:
diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md
index 9f87d79025e..0e46052b0bd 100644
--- a/doc/user/application_security/dependency_scanning/index.md
+++ b/doc/user/application_security/dependency_scanning/index.md
@@ -37,7 +37,7 @@ The results are sorted by the severity of the vulnerability:
## Requirements
-To run a Dependency Scanning job, you need GitLab Runner with the
+To run a Dependency Scanning job, by default, you need GitLab Runner with the
[`docker`](https://docs.gitlab.com/runner/executors/docker.html#use-docker-in-docker-with-privileged-mode) or
[`kubernetes`](https://docs.gitlab.com/runner/install/kubernetes.html#running-privileged-containers-for-the-runners)
executor running in privileged mode. If you're using the shared Runners on GitLab.com,
@@ -47,6 +47,8 @@ CAUTION: **Caution:**
If you use your own Runners, make sure that the Docker version you have installed
is **not** `19.03.00`. See [troubleshooting information](#error-response-from-daemon-error-processing-tar-file-docker-tar-relocation-error) for details.
+Privileged mode is not necessary if you've [disabled Docker in Docker for Dependency Scanning](#disabling-docker-in-docker-for-dependency-scanning)
+
## Supported languages and package managers
The following languages and dependency managers are supported.
@@ -59,27 +61,10 @@ The following languages and dependency managers are supported.
| Go ([Golang](https://golang.org/)) | not currently ([issue](https://gitlab.com/gitlab-org/gitlab/issues/7132 "Dependency Scanning for Go")) | not available |
| PHP ([Composer](https://getcomposer.org/)) | yes | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
| Python ([pip](https://pip.pypa.io/en/stable/)) | yes | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
-| Python ([Pipfile](https://docs.pipenv.org/en/latest/basics/)) | not currently ([issue](https://gitlab.com/gitlab-org/gitlab/issues/11756 "Pipfile.lock support for Dependency Scanning"))| not available |
+| Python ([Pipfile](https://pipenv.kennethreitz.org/en/latest/basics/)) | not currently ([issue](https://gitlab.com/gitlab-org/gitlab/issues/11756 "Pipfile.lock support for Dependency Scanning"))| not available |
| Python ([poetry](https://poetry.eustace.io/)) | not currently ([issue](https://gitlab.com/gitlab-org/gitlab/issues/7006 "Support Poetry in Dependency Scanning")) | not available |
| Ruby ([gem](https://rubygems.org/)) | yes | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium), [bundler-audit](https://github.com/rubysec/bundler-audit) |
-## Remote checks
-
-While some tools pull a local database to check vulnerabilities, some others
-like Gemnasium require sending data to GitLab central servers to analyze them:
-
-1. Gemnasium scans the dependencies of your project locally and sends a list of
- packages to GitLab central servers.
-1. The servers return the list of known vulnerabilities for all versions of
- these packages.
-1. The client picks up the relevant vulnerabilities by comparing with the versions
- of the packages that are used by the project.
-
-The Gemnasium client does **NOT** send the exact package versions your project relies on.
-
-You can disable the remote checks by [using](#customizing-the-dependency-scanning-settings)
-the `DS_DISABLE_REMOTE_CHECKS` environment variable and setting it to `"true"`.
-
## Configuration
For GitLab 11.9 and later, to enable Dependency Scanning, you must
@@ -116,7 +101,7 @@ include:
template: Dependency-Scanning.gitlab-ci.yml
variables:
- DS_DISABLE_REMOTE_CHECKS: "true"
+ DS_PYTHON_VERSION: 2
```
Because template is [evaluated before](../../../ci/yaml/README.md#include) the pipeline
@@ -150,7 +135,7 @@ using environment variables.
| `DS_PYTHON_VERSION` | Version of Python. If set to 2, dependencies are installed using Python 2.7 instead of Python 3.6. ([Introduced](https://gitlab.com/gitlab-org/gitlab/issues/12296) in GitLab 12.1)| |
| `DS_PIP_DEPENDENCY_PATH` | Path to load Python pip dependencies from. ([Introduced](https://gitlab.com/gitlab-org/gitlab/issues/12412) in GitLab 12.2) | |
| `DS_DEFAULT_ANALYZERS` | Override the names of the official default images. Read more about [customizing analyzers](analyzers.md). | |
-| `DS_DISABLE_REMOTE_CHECKS` | Do not send any data to GitLab. Used in the [Gemnasium analyzer](#remote-checks). | |
+| `DS_DISABLE_DIND` | Disable Docker in Docker and run analyzers [individually](#disabling-docker-in-docker-for-dependency-scanning).| |
| `DS_PULL_ANALYZER_IMAGES` | Pull the images from the Docker registry (set to `0` to disable). | |
| `DS_EXCLUDED_PATHS` | Exclude vulnerabilities from output based on the paths. A comma-separated list of patterns. Patterns can be globs, file or folder paths. Parent directories will also match patterns. | `DS_EXCLUDED_PATHS=doc,spec` |
| `DS_DOCKER_CLIENT_NEGOTIATION_TIMEOUT` | Time limit for Docker client negotiation. Timeouts are parsed using Go's [`ParseDuration`](https://golang.org/pkg/time/#ParseDuration). Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. For example, `300ms`, `1.5h`, or `2h45m`. | |
@@ -158,6 +143,50 @@ using environment variables.
| `DS_RUN_ANALYZER_TIMEOUT` | Time limit when running an analyzer. Timeouts are parsed using Go's [`ParseDuration`](https://golang.org/pkg/time/#ParseDuration). Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. For example, `300ms`, `1.5h`, or `2h45m`. | |
| `PIP_INDEX_URL` | Base URL of Python Package Index (default `https://pypi.org/simple`). | |
| `PIP_EXTRA_INDEX_URL` | Array of [extra URLs](https://pip.pypa.io/en/stable/reference/pip_install/#cmdoption-extra-index-url) of package indexes to use in addition to `PIP_INDEX_URL`. Comma separated. | |
+| `MAVEN_CLI_OPTS` | List of command line arguments that will be passed to the maven analyzer during the project's build phase (see example for [using private repos](#using-private-maven-repos)). | |
+
+### Using private Maven repos
+
+If you have a private Maven repository which requires login credentials,
+you can use the `MAVEN_CLI_OPTS` environment variable to pass variables
+specified in your settings (e.g., username, password, etc.).
+
+For example, if you have a settings file in your project source (e.g., `mysettings.xml`)
+that looks like the following, you can specify the variables
+[by adding an entry under your project's settings](../../../ci/variables/README.md#via-the-ui),
+so that you don't have to expose your private data in `.gitlab-ci.yml` (e.g., adding
+`MAVEN_CLI_OPTS` with value `--settings mysettings.xml -Dprivate.username=foo -Dprivate.password=bar`).
+
+```xml
+<!-- mysettings.xml -->
+<settings>
+ ...
+ <servers>
+ <server>
+ <id>private_server</id>
+ <username>${private.username}</username>
+ <password>${private.password}</password>
+ </server>
+ </servers>
+</settings>
+```
+
+### Disabling Docker in Docker for Dependency Scanning
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/12487) in GitLab Ultimate 12.5.
+
+You can avoid the need for Docker in Docker by running the individual analyzers.
+This does not require running the executor in privileged mode. For example:
+
+```yaml
+include:
+ template: Dependency-Scanning.gitlab-ci.yml
+
+variables:
+ DS_DISABLE_DIND: "true"
+```
+
+This will create individual `<analyzer-name>-dependency_scanning` jobs for each analyzer that runs in your CI/CD pipeline.
## Interacting with the vulnerabilities
diff --git a/doc/user/application_security/index.md b/doc/user/application_security/index.md
index e9f5898950e..dbbcb606ac7 100644
--- a/doc/user/application_security/index.md
+++ b/doc/user/application_security/index.md
@@ -203,14 +203,34 @@ An approval will be optional when a license report:
- Contains no software license violations.
- Contains only new licenses that are `approved` or unknown.
-<!-- ## Troubleshooting
+## Troubleshooting
-Include any troubleshooting steps that you can foresee. If you know beforehand what issues
-one might have when setting this up, or when something is changed, or on upgrading, it's
-important to describe those, too. Think of things that may go wrong and include them here.
-This is important to minimize requests for support, and to avoid doc comments with
-questions that you know someone might ask.
+### Getting error message `sast job: stage parameter should be [some stage name here]`
-Each scenario can be a third-level heading, e.g. `### Getting error message X`.
-If you have none to add when creating a doc, leave this section in place
-but commented out to help encourage others to add to it in the future. -->
+When including a security job template like [`SAST`](sast/index.md#configuration),
+the following error can be raised, depending on your GitLab CI/CD configuration:
+
+```
+Found errors in your .gitlab-ci.yml:
+
+* sast job: stage parameter should be unit-tests
+```
+
+This error appears when the stage (nammed `test`) of the included job isn't declared
+in `.gitlab-ci.yml`.
+To fix this issue, you can either:
+
+- Add a `test` stage in your `.gitlab-ci.yml`.
+- Change the default stage of the included security jobs. For example, with `SAST`:
+
+ ```yaml
+ include:
+ template: SAST.gitlab-ci.yml
+
+ sast:
+ stage: unit-tests
+ ```
+
+[Learn more on overriding the SAST template](sast/index.md#overriding-the-sast-template).
+All the security scanning tools define their stage, so this error can occur with
+all of them.
diff --git a/doc/user/application_security/license_compliance/index.md b/doc/user/application_security/license_compliance/index.md
index 75a3b33e32e..3cf8301adca 100644
--- a/doc/user/application_security/license_compliance/index.md
+++ b/doc/user/application_security/license_compliance/index.md
@@ -94,8 +94,20 @@ always take the latest License Compliance artifact available. Behind the scenes,
[GitLab License Compliance Docker image](https://gitlab.com/gitlab-org/security-products/license-management)
is used to detect the languages/frameworks and in turn analyzes the licenses.
-The License Compliance settings can be changed through environment variables by using the
-[`variables`](../../../ci/yaml/README.md#variables) parameter in `.gitlab-ci.yml`. These variables are documented in the [License Compliance documentation](https://gitlab.com/gitlab-org/security-products/license-management#settings).
+The License Compliance settings can be changed through [environment variables](#available-variables) by using the
+[`variables`](../../../ci/yaml/README.md#variables) parameter in `.gitlab-ci.yml`.
+
+### Available variables
+
+License Compliance can be configured using environment variables.
+
+| Environment variable | Required | Description |
+|-----------------------|----------|-------------|
+| `MAVEN_CLI_OPTS` | no | Additional arguments for the mvn executable. If not supplied, defaults to `-DskipTests`. |
+| `LICENSE_FINDER_CLI_OPTS` | no | Additional arguments for the `license_finder` executable. For example, if your project has both Golang and Ruby code stored in different directories and you want to only scan the Ruby code, you can update your `.gitlab-ci-yml` template to specify which project directories to scan, like `LICENSE_FINDER_CLI_OPTS: '--debug --aggregate-paths=. ruby'`. |
+| `LM_JAVA_VERSION` | no | Version of Java. If set to `11`, Maven and Gradle use Java 11 instead of Java 8. |
+| `LM_PYTHON_VERSION` | no | Version of Python. If set to `3`, dependencies are installed using Python 3 instead of Python 2.7. |
+| `SETUP_CMD` | no | Custom setup for the dependency installation. (experimental) |
### Installing custom dependencies
diff --git a/doc/user/application_security/sast/analyzers.md b/doc/user/application_security/sast/analyzers.md
index 76a566f7514..6eb2ca71e71 100644
--- a/doc/user/application_security/sast/analyzers.md
+++ b/doc/user/application_security/sast/analyzers.md
@@ -25,7 +25,7 @@ SAST supports the following official analyzers:
- [`security-code-scan`](https://gitlab.com/gitlab-org/security-products/analyzers/security-code-scan) (Security Code Scan (.NET))
- [`sobelow`](https://gitlab.com/gitlab-org/security-products/analyzers/sobelow) (Sobelow (Elixir Phoenix))
- [`spotbugs`](https://gitlab.com/gitlab-org/security-products/analyzers/spotbugs) (SpotBugs with the Find Sec Bugs plugin (Ant, Gradle and wrapper, Grails, Maven and wrapper, SBT))
-- [`tslint`](https://gitlab.com/gitlab-org/security-products/analyzers/tslint) (TSLint (Typescript))
+- [`tslint`](https://gitlab.com/gitlab-org/security-products/analyzers/tslint) (TSLint (TypeScript))
The analyzers are published as Docker images that SAST will use to launch
dedicated containers for each analysis.
@@ -111,6 +111,9 @@ This configuration doesn't benefit from the integrated detection step.
SAST has to fetch and spawn each Docker image to establish whether the
custom analyzer can scan the source code.
+CAUTION: **Caution:**
+Custom analyzers are not spawned automatically when [Docker In Docker](index.md#disabling-docker-in-docker-for-sast) is disabled.
+
## Analyzers Data
| Property \ Tool | Apex | Bandit | Brakeman | ESLint security | Find Sec Bugs | Flawfinder | Go AST Scanner | NodeJsScan | Php CS Security Audit | Security code Scan (.NET) | TSLint Security | Sobelow |
diff --git a/doc/user/application_security/sast/index.md b/doc/user/application_security/sast/index.md
index cb54d9f3853..615eb072ea7 100644
--- a/doc/user/application_security/sast/index.md
+++ b/doc/user/application_security/sast/index.md
@@ -78,7 +78,7 @@ The following table shows which languages, package managers and frameworks are s
| Python ([pip](https://pip.pypa.io/en/stable/)) | [bandit](https://github.com/PyCQA/bandit) | 10.3 |
| Ruby on Rails | [brakeman](https://brakemanscanner.org) | 10.3 |
| Scala ([Ant](https://ant.apache.org/), [Gradle](https://gradle.org/), [Maven](https://maven.apache.org/) and [SBT](https://www.scala-sbt.org/)) | [SpotBugs](https://spotbugs.github.io/) with the [find-sec-bugs](https://find-sec-bugs.github.io/) plugin | 11.0 (SBT) & 11.9 (Ant, Gradle, Maven) |
-| Typescript | [TSLint config security](https://github.com/webschik/tslint-config-security/) | 11.9 |
+| TypeScript | [TSLint config security](https://github.com/webschik/tslint-config-security/) | 11.9 |
NOTE: **Note:**
The Java analyzers can also be used for variants like the
@@ -146,7 +146,15 @@ sast:
CI_DEBUG_TRACE: "true"
```
-### Using a variable to pass username and password to a private Maven repository
+### Using environment variables to pass credentials for private repositories
+
+Some analyzers require downloading the project's dependencies in order to
+perform the analysis. In turn, such dependencies may live in private Git
+repositories and thus require credentials like username and password to download them.
+Depending on the analyzer, such credentials can be provided to
+it via [custom environment variables](#custom-environment-variables).
+
+#### Using a variable to pass username and password to a private Maven repository
If you have a private Apache Maven repository that requires login credentials,
you can use the `MAVEN_CLI_OPTS` [environment variable](#available-variables)
@@ -184,14 +192,14 @@ SAST can be [configured](#customizing-the-sast-settings) using environment varia
The following are Docker image-related variables.
-| Environment variable | Description |
-|-------------------------------|--------------------------------------------------------------------------------|
-| `SAST_ANALYZER_IMAGES` | Comma separated list of custom images. Default images are still enabled. Read more about [customizing analyzers](analyzers.md). |
-| `SAST_ANALYZER_IMAGE_PREFIX` | Override the name of the Docker registry providing the default images (proxy). Read more about [customizing analyzers](analyzers.md). |
-| `SAST_ANALYZER_IMAGE_TAG` | Override the Docker tag of the default images. Read more about [customizing analyzers](analyzers.md). |
-| `SAST_DEFAULT_ANALYZERS` | Override the names of default images. Read more about [customizing analyzers](analyzers.md). |
-| `SAST_DISABLE_DIND` | Disable Docker in Docker and run analyzers [individually](#disabling-docker-in-docker-for-sast). |
-| `SAST_PULL_ANALYZER_IMAGES` | Pull the images from the Docker registry (set to 0 to disable). Read more about [customizing analyzers](analyzers.md). |
+| Environment variable | Description |
+|------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `SAST_ANALYZER_IMAGES` | Comma separated list of custom images. Default images are still enabled. Read more about [customizing analyzers](analyzers.md). Not available when [Docker in Docker is disabled](#disabling-docker-in-docker-for-sast). |
+| `SAST_ANALYZER_IMAGE_PREFIX` | Override the name of the Docker registry providing the default images (proxy). Read more about [customizing analyzers](analyzers.md). |
+| `SAST_ANALYZER_IMAGE_TAG` | Override the Docker tag of the default images. Read more about [customizing analyzers](analyzers.md). |
+| `SAST_DEFAULT_ANALYZERS` | Override the names of default images. Read more about [customizing analyzers](analyzers.md). |
+| `SAST_DISABLE_DIND` | Disable Docker in Docker and run analyzers [individually](#disabling-docker-in-docker-for-sast). |
+| `SAST_PULL_ANALYZER_IMAGES` | Pull the images from the Docker registry (set to 0 to disable). Read more about [customizing analyzers](analyzers.md). Not available when [Docker in Docker is disabled](#disabling-docker-in-docker-for-sast). |
#### Vulnerability filters
@@ -216,6 +224,9 @@ The following variables configure timeouts.
| `SAST_PULL_ANALYZER_IMAGE_TIMEOUT` | 5m | Time limit when pulling the image of an analyzer. Timeouts are parsed using Go's [`ParseDuration`](https://golang.org/pkg/time/#ParseDuration). Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". For example, "300ms", "1.5h" or "2h45m". |
| `SAST_RUN_ANALYZER_TIMEOUT` | 20m | Time limit when running an analyzer. Timeouts are parsed using Go's [`ParseDuration`](https://golang.org/pkg/time/#ParseDuration). Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". For example, "300ms", "1.5h" or "2h45m".|
+NOTE: **Note:**
+Timeout variables are not applicable for setups with [disabled Docker In Docker](index.md#disabling-docker-in-docker-for-sast).
+
#### Analyzer settings
Some analyzers can be customized with environment variables.
@@ -234,6 +245,19 @@ Some analyzers can be customized with environment variables.
| `SBT_PATH` | spotbugs | Path to the `sbt` executable. |
| `FAIL_NEVER` | spotbugs | Set to `1` to ignore compilation failure. |
+#### Custom environment variables
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/18193) in GitLab Ultimate 12.5.
+
+In addition to the aforementioned SAST configuration variables,
+all [custom environment variables](../../../ci/variables/README.md#creating-a-custom-environment-variable) are propagated
+to the underlying SAST analyzer images if
+[the SAST vendored template](#configuration) is used.
+
+CAUTION: **Caution:**
+Variables having names starting with these prefixes will **not** be propagated to the SAST Docker container and/or
+analyzer containers: `DOCKER_`, `CI`, `GITLAB_`, `FF_`, `HOME`, `PWD`, `OLDPWD`, `PATH`, `SHLVL`, `HOSTNAME`.
+
## Reports JSON format
CAUTION: **Caution:**
diff --git a/doc/user/application_security/security_dashboard/img/group_security_dashboard_v12_3.png b/doc/user/application_security/security_dashboard/img/group_security_dashboard_v12_3.png
deleted file mode 100644
index 1fe76a9e08f..00000000000
--- a/doc/user/application_security/security_dashboard/img/group_security_dashboard_v12_3.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/application_security/security_dashboard/img/group_security_dashboard_v12_4.png b/doc/user/application_security/security_dashboard/img/group_security_dashboard_v12_4.png
new file mode 100644
index 00000000000..682dcbec63f
--- /dev/null
+++ b/doc/user/application_security/security_dashboard/img/group_security_dashboard_v12_4.png
Binary files differ
diff --git a/doc/user/application_security/security_dashboard/index.md b/doc/user/application_security/security_dashboard/index.md
index 0e26206f070..688d231d568 100644
--- a/doc/user/application_security/security_dashboard/index.md
+++ b/doc/user/application_security/security_dashboard/index.md
@@ -71,12 +71,12 @@ Once you're on the dashboard, at the top you should see a series of filters for:
- Report type
- Project
-To the right of the filters, you should see a **Hide dismissed** toggle button.
+To the right of the filters, you should see a **Hide dismissed** toggle button ([available in GitLab Ultimate 12.5](https://gitlab.com/gitlab-org/gitlab/issues/9102)).
NOTE: **Note:**
The dashboard only shows projects with [security reports](#supported-reports) enabled in a group.
-![dashboard with action buttons and metrics](img/group_security_dashboard_v12_3.png)
+![dashboard with action buttons and metrics](img/group_security_dashboard_v12_4.png)
Selecting one or more filters will filter the results in this page. Disabling the **Hide dismissed**
toggle button will let you also see vulnerabilities that have been dismissed.
diff --git a/doc/user/clusters/applications.md b/doc/user/clusters/applications.md
index dc6f859e881..c3e2e6bca5b 100644
--- a/doc/user/clusters/applications.md
+++ b/doc/user/clusters/applications.md
@@ -7,7 +7,7 @@ These applications are needed for [Review Apps](../../ci/review_apps/index.md)
and [deployments](../../ci/environments.md) when using [Auto DevOps](../../topics/autodevops/index.md).
You can install them after you
-[create a cluster](../project/clusters/index.md#adding-and-removing-clusters).
+[create a cluster](../project/clusters/add_remove_clusters.md).
## Installing applications
@@ -40,6 +40,7 @@ The following applications can be installed:
- [GitLab Runner](#gitlab-runner)
- [JupyterHub](#jupyterhub)
- [Knative](#knative)
+- [Crossplane](#crossplane)
With the exception of Knative, the applications will be installed in a dedicated
namespace called `gitlab-managed-apps`.
@@ -82,19 +83,21 @@ certificates. Installing Cert-Manager on your cluster will issue a
certificate by [Let's Encrypt](https://letsencrypt.org/) and ensure that
certificates are valid and up-to-date.
-NOTE: **Note:**
-The
-[jetstack/cert-manager](https://github.com/jetstack/cert-manager)
-chart is used to install this application with a
-[`values.yaml`](https://gitlab.com/gitlab-org/gitlab/blob/master/vendor/cert_manager/values.yaml)
-file. Prior to GitLab 12.3,
-the [stable/cert-manager](https://github.com/helm/charts/tree/master/stable/cert-manager)
-chart was used.
+The chart used to install this application depends on the version of GitLab used. In:
-NOTE: **Note:**
-If you have installed cert-manager prior to GitLab 12.3, Let's Encrypt will
-[block requests from older versions of cert-manager](https://community.letsencrypt.org/t/blocking-old-cert-manager-versions/98753).
-To resolve this, uninstall cert-manager (consider [backing up any additional configuration](https://docs.cert-manager.io/en/latest/tasks/backup-restore-crds.html)), then install cert-manager again.
+- GitLab 12.3 and newer, the [jetstack/cert-manager](https://github.com/jetstack/cert-manager)
+ chart is used with a [`values.yaml`](https://gitlab.com/gitlab-org/gitlab/blob/master/vendor/cert_manager/values.yaml)
+ file.
+- GitLab 12.2 and older, the [stable/cert-manager](https://github.com/helm/charts/tree/master/stable/cert-manager)
+ chart was used.
+
+If you have installed Cert-Manager prior to GitLab 12.3, Let's Encrypt will
+[block requests from older versions of Cert-Manager](https://community.letsencrypt.org/t/blocking-old-cert-manager-versions/98753).
+
+To resolve this:
+
+1. Uninstall Cert-Manager (consider [backing up any additional configuration](https://docs.cert-manager.io/en/latest/tasks/backup-restore-crds.html)).
+1. Install Cert-Manager again.
### GitLab Runner
@@ -105,10 +108,20 @@ To resolve this, uninstall cert-manager (consider [backing up any additional con
project that is used to run your jobs and send the results back to
GitLab. It is used in conjunction with [GitLab
CI/CD](../../ci/README.md), the open-source continuous integration
-service included with GitLab that coordinates the jobs. When installing
-the GitLab Runner via the applications, it will run in **privileged
-mode** by default. Make sure you read the [security
-implications](../project/clusters/index.md#security-implications) before doing so.
+service included with GitLab that coordinates the jobs.
+
+If the project is on GitLab.com, shared Runners are available
+(the first 2000 minutes are free, you can
+[buy more later](../../subscriptions/index.md#extra-shared-runners-pipeline-minutes))
+and you do not have to deploy one if they are enough for your needs. If a
+project-specific Runner is desired, or there are no shared Runners, it is easy
+to deploy one.
+
+Note that the deployed Runner will be set as **privileged**, which means it will essentially
+have root access to the underlying machine. This is required to build Docker images,
+so it is the default. Make sure you read the
+[security implications](../project/clusters/index.md#security-implications)
+before deploying one.
NOTE: **Note:**
The [`runner/gitlab-runner`](https://gitlab.com/gitlab-org/charts/gitlab-runner)
@@ -127,11 +140,112 @@ web proxy for your applications and is useful if you want to use [Auto
DevOps](../../topics/autodevops/index.md) or deploy your own web apps.
NOTE: **Note:**
+With the following procedure, a load balancer must be installed in your cluster
+to obtain the endpoint. You can use either
+Ingress, or Knative's own load balancer ([Istio](https://istio.io)) if using Knative.
+
+In order to publish your web application, you first need to find the endpoint which will be either an IP
+address or a hostname associated with your load balancer.
+
+To install it, click on the **Install** button for Ingress. GitLab will attempt
+to determine the external endpoint and it should be available within a few minutes.
+
+#### Determining the external endpoint automatically
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/17052) in GitLab 10.6.
+
+After you install Ingress, the external endpoint should be available within a few minutes.
+
+TIP: **Tip:**
+This endpoint can be used for the
+[Auto DevOps base domain](../../topics/autodevops/index.md#auto-devops-base-domain)
+using the `KUBE_INGRESS_BASE_DOMAIN` environment variable.
+
+If the endpoint doesn't appear and your cluster runs on Google Kubernetes Engine:
+
+1. Check your [Kubernetes cluster on Google Kubernetes Engine](https://console.cloud.google.com/kubernetes) to ensure there are no errors on its nodes.
+1. Ensure you have enough [Quotas](https://console.cloud.google.com/iam-admin/quotas) on Google Kubernetes Engine. For more information, see [Resource Quotas](https://cloud.google.com/compute/quotas).
+1. Check [Google Cloud's Status](https://status.cloud.google.com/) to ensure they are not having any disruptions.
+
+Once installed, you may see a `?` for "Ingress IP Address" depending on the
+cloud provider. For EKS specifically, this is because the ELB is created
+with a DNS name, not an IP address. If GitLab is still unable to
+determine the endpoint of your Ingress or Knative application, you can
+[determine it manually](#determining-the-external-endpoint-manually).
+
+NOTE: **Note:**
The [`stable/nginx-ingress`](https://github.com/helm/charts/tree/master/stable/nginx-ingress)
chart is used to install this application with a
[`values.yaml`](https://gitlab.com/gitlab-org/gitlab/blob/master/vendor/ingress/values.yaml)
file.
+#### Determining the external endpoint manually
+
+If the cluster is on GKE, click the **Google Kubernetes Engine** link in the
+**Advanced settings**, or go directly to the
+[Google Kubernetes Engine dashboard](https://console.cloud.google.com/kubernetes/)
+and select the proper project and cluster. Then click **Connect** and execute
+the `gcloud` command in a local terminal or using the **Cloud Shell**.
+
+If the cluster is not on GKE, follow the specific instructions for your
+Kubernetes provider to configure `kubectl` with the right credentials.
+The output of the following examples will show the external endpoint of your
+cluster. This information can then be used to set up DNS entries and forwarding
+rules that allow external access to your deployed applications.
+
+If you installed Ingress via the **Applications**, run the following command:
+
+```bash
+kubectl get service --namespace=gitlab-managed-apps ingress-nginx-ingress-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
+```
+
+Some Kubernetes clusters return a hostname instead, like [Amazon EKS](https://aws.amazon.com/eks/). For these platforms, run:
+
+```bash
+kubectl get service --namespace=gitlab-managed-apps ingress-nginx-ingress-controller -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'
+```
+
+For Istio/Knative, the command will be different:
+
+```bash
+kubectl get svc --namespace=istio-system knative-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip} '
+```
+
+Otherwise, you can list the IP addresses of all load balancers:
+
+```bash
+kubectl get svc --all-namespaces -o jsonpath='{range.items[?(@.status.loadBalancer.ingress)]}{.status.loadBalancer.ingress[*].ip} '
+```
+
+NOTE: **Note:**
+If EKS is used, an [Elastic Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/)
+will also be created, which will incur additional AWS costs.
+
+NOTE: **Note:**
+You may see a trailing `%` on some Kubernetes versions, **do not include it**.
+
+The Ingress is now available at this address and will route incoming requests to
+the proper service based on the DNS name in the request. To support this, a
+wildcard DNS CNAME record should be created for the desired domain name. For example,
+`*.myekscluster.com` would point to the Ingress hostname obtained earlier.
+
+#### Using a static IP
+
+By default, an ephemeral external IP address is associated to the cluster's load
+balancer. If you associate the ephemeral IP with your DNS and the IP changes,
+your apps will not be able to be reached, and you'd have to change the DNS
+record again. In order to avoid that, you should change it into a static
+reserved IP.
+
+Read how to [promote an ephemeral external IP address in GKE](https://cloud.google.com/compute/docs/ip-addresses/reserve-static-external-ip-address#promote_ephemeral_ip).
+
+#### Pointing your DNS at the external endpoint
+
+Once you've set up the external endpoint, you should associate it with a [wildcard DNS
+record](https://en.wikipedia.org/wiki/Wildcard_DNS_record) such as `*.example.com.`
+in order to be able to reach your apps. If your external endpoint is an IP address,
+use an A record. If your external endpoint is a hostname, use a CNAME record.
+
#### Web Application Firewall (ModSecurity)
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/65192) in GitLab 12.3 (enabled using `ingress_modsecurity` [feature flag](../../development/feature_flags/development.md#enabling-a-feature-flag-in-development)).
@@ -150,7 +264,7 @@ This feature:
For example:
```sh
- kubectl -n gitlab-managed-apps exec -it $(kubectl get pods -n gitlab-managed-apps | grep 'ingress-controller' | awk '{print $1}') -- tail -f /var/log/modsec_audit.log
+ kubectl -n gitlab-managed-apps exec -it $(kubectl get pods -n gitlab-managed-apps | grep 'ingress-controller' | awk '{print $1}') -- tail -f /var/log/modsec/audit.log
```
There is a small performance overhead by enabling `modsecurity`. However, if this is
@@ -242,7 +356,7 @@ server to use the external IP address for that domain. For any
application created and installed, they will be accessible as
`<program_name>.<kubernetes_namespace>.<domain_name>`. This will require
your Kubernetes cluster to have [RBAC
-enabled](../project/clusters/index.md#rbac-cluster-resources).
+enabled](../project/clusters/add_remove_clusters.md#rbac-cluster-resources).
NOTE: **Note:**
The [`knative/knative`](https://storage.googleapis.com/triggermesh-charts)
@@ -257,12 +371,52 @@ chart is used to install this application.
open-source monitoring and alerting system useful to supervise your
deployed applications.
+GitLab is able to monitor applications automatically, using the
+[Prometheus integration](../project/integrations/prometheus.md). Kubernetes container CPU and
+memory metrics are automatically collected, and response metrics are retrieved
+from NGINX Ingress as well.
+
+To enable monitoring, simply install Prometheus into the cluster with the
+**Install** button.
+
NOTE: **Note:**
The [`stable/prometheus`](https://github.com/helm/charts/tree/master/stable/prometheus)
chart is used to install this application with a
[`values.yaml`](https://gitlab.com/gitlab-org/gitlab/blob/master/vendor/prometheus/values.yaml)
file.
+### Crossplane
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/34702) in GitLab 12.5 for project-level clusters.
+
+[Crossplane](https://crossplane.io/docs) is a multi-cloud control plane useful for
+managing applications and infrastructure across multiple clouds. It extends the
+Kubernetes API using:
+
+- Custom resources.
+- Controllers that watch those custom resources.
+
+Crossplane allows provisioning and lifecycle management of infrastructure components
+across cloud providers in a uniform manner by abstracting cloud provider-specific
+configurations.
+
+The Crossplane GitLab-managed application:
+
+- Installs Crossplane with a provider of choice on a Kubernetes cluster attached to the
+ project repository.
+- Can then be used to provision infrastructure or managed applications such as
+ PostgreSQL (for example, CloudSQL from GCP or RDS from AWS) and other services
+ required by the application via the Auto DevOps pipeline.
+
+For information on configuring Crossplane installed on the cluster, see
+[Crossplane configuration](crossplane.md).
+
+NOTE: **Note:**
+[`alpha/crossplane`](https://charts.crossplane.io/alpha/) chart v0.4.1 is used to
+install Crossplane using the
+[`values.yaml`](https://github.com/crossplaneio/crossplane/blob/master/cluster/charts/crossplane/values.yaml.tmpl)
+file.
+
## Upgrading applications
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/24789) in GitLab 11.8.
@@ -296,13 +450,14 @@ The applications below can be uninstalled.
| Application | GitLab version | Notes |
| ----------- | -------------- | ----- |
-| Cert-Manager | 12.2+ | The associated private key will be deleted and cannot be restored. Deployed applications will continue to use HTTPS, but certificates will not be renewed. Before uninstalling, you may wish to [back up your configuration](https://docs.cert-manager.io/en/latest/tasks/backup-restore-crds.html) or [revoke your certificates](https://letsencrypt.org/docs/revoking/) |
+| Cert-Manager | 12.2+ | The associated private key will be deleted and cannot be restored. Deployed applications will continue to use HTTPS, but certificates will not be renewed. Before uninstalling, you may wish to [back up your configuration](https://docs.cert-manager.io/en/latest/tasks/backup-restore-crds.html) or [revoke your certificates](https://letsencrypt.org/docs/revoking/). |
| GitLab Runner | 12.2+ | Any running pipelines will be canceled. |
| Helm | 12.2+ | The associated Tiller pod, the `gitlab-managed-apps` namespace, and all of its resources will be deleted and cannot be restored. |
| Ingress | 12.1+ | The associated load balancer and IP will be deleted and cannot be restored. Furthermore, it can only be uninstalled if JupyterHub is not installed. |
| JupyterHub | 12.1+ | All data not committed to GitLab will be deleted and cannot be restored. |
| Knative | 12.1+ | The associated IP will be deleted and cannot be restored. |
| Prometheus | 11.11+ | All data will be deleted and cannot be restored. |
+| Crossplane | 12.5+ | All data will be deleted and cannot be restored. |
To uninstall an application:
diff --git a/doc/user/clusters/crossplane.md b/doc/user/clusters/crossplane.md
new file mode 100644
index 00000000000..37210b22f6f
--- /dev/null
+++ b/doc/user/clusters/crossplane.md
@@ -0,0 +1,292 @@
+# Crossplane configuration
+
+Once Crossplane [is installed](applications.md#crossplane), it must be configured for
+use.
+
+The process of configuring Crossplane includes:
+
+1. Configuring RBAC permissions.
+1. Configuring Crossplane with a cloud provider.
+1. Configure managed service access.
+1. Setting up Resource classes.
+1. Using Auto DevOps configuration options.
+1. Connect to the PostgreSQL instance.
+
+To allow Crossplane to provision cloud services such as PostgreSQL, the cloud provider
+stack must be configured with a user account. For example:
+
+- A service account for GCP.
+- An IAM user for AWS.
+
+Important notes:
+
+- This guide uses GCP as an example. However, the process for AWS and Azure will be
+similar.
+- Crossplane requires the Kubernetes cluster to be VPC native with Alias IPs enabled so
+that the IP address of the pods are routable within the GCP network.
+
+First, we need to declare some environment variables with configuration that will be used throughout this guide:
+
+```sh
+export PROJECT_ID=crossplane-playground # the GCP project where all resources reside.
+export NETWORK_NAME=default # the GCP network where your GKE is provisioned.
+export REGION=us-central1 # the GCP region where the GKE cluster is provisioned.
+```
+
+## Configure RBAC permissions
+
+- For a non-GitLab managed cluster(s), ensure that the service account for the token provided can manage resources in the `database.crossplane.io` API group.
+Manually grant GitLab's service account the ability to manage resources in the
+`database.crossplane.io` API group. The Aggregated ClusterRole allows us to do that.
+​
+NOTE: **Note:**
+For a non-GitLab managed cluster, ensure that the service account for the token provided can manage resources in the `database.crossplane.io` API group.
+​1. Save the following YAML as `crossplane-database-role.yaml`:
+
+```sh
+cat > crossplane-database-role.yaml <<EOF
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ name: crossplane-database-role
+ labels:
+ rbac.authorization.k8s.io/aggregate-to-edit: "true"
+rules:
+- apiGroups:
+ - database.crossplane.io
+ resources:
+ - postgresqlinstances
+ verbs:
+ - get
+ - list
+ - create
+ - update
+ - delete
+ - patch
+ - watch
+EOF
+```
+
+Once the file is created, apply it with the following command in order to create the necessary role:
+
+```sh
+kubectl apply -f crossplane-database-role.yaml
+```
+
+## Configure Crossplane with a cloud provider
+
+See [Configure Your Cloud Provider Account](https://crossplane.io/docs/v0.4/cloud-providers.html)
+to configure the installed cloud provider stack with a user account.
+
+Note that the Secret and the Provider resource referencing the Secret needs to be
+applied to the `gitlab-managed-apps` namespace in the guide. Make sure you change that
+while following the process.
+
+[Configure Providers](https://crossplane.io/docs/v0.4/cloud-providers.html)
+
+## Configure Managed Service Access
+
+We need to configure connectivity between the PostgreSQL database and the GKE cluster.
+This can done by either:
+
+- Using Crossplane as demonstrated below.
+- Directly in the GCP console by
+[configuring private services access](https://cloud.google.com/vpc/docs/configure-private-services-access).
+Create a GlobalAddress and Connection resources:
+
+```sh
+cat > network.yaml <<EOF
+---
+# gitlab-ad-globaladdress defines the IP range that will be allocated for cloud services connecting to the instances in the given Network.
+
+apiVersion: compute.gcp.crossplane.io/v1alpha3
+kind: GlobalAddress
+metadata:
+ name: gitlab-ad-globaladdress
+spec:
+ providerRef:
+ name: gcp-provider
+ reclaimPolicy: Delete
+ name: gitlab-ad-globaladdress
+ purpose: VPC_PEERING
+ addressType: INTERNAL
+ prefixLength: 16
+ network: projects/$PROJECT_ID/global/networks/$NETWORK_NAME
+---
+# gitlab-ad-connection is what allows cloud services to use the allocated GlobalAddress for communication. Behind
+# the scenes, it creates a VPC peering to the network that those service instances actually live.
+
+apiVersion: servicenetworking.gcp.crossplane.io/v1alpha3
+kind: Connection
+metadata:
+ name: gitlab-ad-connection
+spec:
+ providerRef:
+ name: gcp-provider
+ reclaimPolicy: Delete
+ parent: services/servicenetworking.googleapis.com
+ network: projects/$PROJECT_ID/global/networks/$NETWORK_NAME
+ reservedPeeringRangeRefs:
+ - name: gitlab-ad-globaladdress
+EOF
+```
+
+Apply the settings specified in the file with the following command:
+
+```sh
+kubectl apply -f network.yaml
+```
+
+You can verify creation of the network resources with the following commands.
+Verify that the status of both of these resources is ready and is synced.
+
+```sh
+kubectl describe connection.servicenetworking.gcp.crossplane.io gitlab-ad-connection
+kubectl describe globaladdress.compute.gcp.crossplane.io gitlab-ad-globaladdress
+```
+
+## Setting up Resource classes
+
+Resource classes are a way of defining a configuration for the required managed service. We will define the Postgres Resource class
+
+- Define a gcp-postgres-standard.yaml resourceclass which contains
+
+1. A default CloudSQLInstanceClass.
+1. A CloudSQLInstanceClass with labels.
+
+```sh
+cat > gcp-postgres-standard.yaml <<EOF
+apiVersion: database.gcp.crossplane.io/v1beta1
+kind: CloudSQLInstanceClass
+metadata:
+ name: cloudsqlinstancepostgresql-standard
+ labels:
+ gitlab-ad-demo: "true"
+specTemplate:
+ writeConnectionSecretsToNamespace: gitlab-managed-apps
+ forProvider:
+ databaseVersion: POSTGRES_9_6
+ region: $REGION
+ settings:
+ tier: db-custom-1-3840
+ dataDiskType: PD_SSD
+ dataDiskSizeGb: 10
+ ipConfiguration:
+ privateNetwork: projects/$PROJECT_ID/global/networks/$NETWORK_NAME
+ # this should match the name of the provider created in the above step
+ providerRef:
+ name: gcp-provider
+ reclaimPolicy: Delete
+---
+apiVersion: database.gcp.crossplane.io/v1beta1
+kind: CloudSQLInstanceClass
+metadata:
+ name: cloudsqlinstancepostgresql-standard-default
+ annotations:
+ resourceclass.crossplane.io/is-default-class: "true"
+specTemplate:
+ writeConnectionSecretsToNamespace: gitlab-managed-apps
+ forProvider:
+ databaseVersion: POSTGRES_9_6
+ region: $REGION
+ settings:
+ tier: db-custom-1-3840
+ dataDiskType: PD_SSD
+ dataDiskSizeGb: 10
+ ipConfiguration:
+ privateNetwork: projects/$PROJECT_ID/global/networks/$NETWORK_NAME
+ # this should match the name of the provider created in the above step
+ providerRef:
+ name: gcp-provider
+ reclaimPolicy: Delete
+EOF
+```
+
+Apply the resource class configuration with the following command:
+
+```sh
+kubectl apply -f gcp-postgres-standard.yaml
+```
+
+Verify creation of the Resource class with the following command:
+
+```sh
+kubectl get cloudsqlinstanceclasses
+```
+
+The Resource Classes allow you to define classes of service for a managed service. We could create another `CloudSQLInstanceClass` which requests for a larger or a faster disk. It could also request for a specific version of the database.
+
+## Auto DevOps Configuration Options
+
+The Auto DevOps pipeline can be run with the following options:
+
+The Environment variables, `AUTO_DEVOPS_POSTGRES_MANAGED` and `AUTO_DEVOPS_POSTGRES_MANAGED_CLASS_SELECTOR` need to be set to provision PostgresQL using Crossplane
+
+Alertnatively, the following options can be overridden from the values for the helm chart.
+
+- `postgres.managed` set to true which will select a default resource class.
+ The resource class needs to be marked with the annotation
+ `resourceclass.crossplane.io/is-default-class: "true"`. The CloudSQLInstanceClass
+ `cloudsqlinstancepostgresql-standard-default` will be used to satisfy the claim.
+
+- `postgres.managed` set to `true` with `postgres.managedClassSelector`
+ providing the resource class to choose based on labels. In this case, the
+ value of `postgres.managedClassSelector.matchLabels.gitlab-ad-demo="true"`
+ will select the CloudSQLInstance class `cloudsqlinstancepostgresql-standard`
+ to satisfy the claim request.
+
+The Auto DevOps pipeline should provision a PostgresqlInstance when it runs succesfully.
+
+Verify creation of the PostgresQL Instance.
+
+```sh
+kubectl get postgresqlinstance
+```
+
+Sample Output: The `STATUS` field of the PostgresqlInstance transitions to `BOUND` when it is successfully provisioned.
+
+```
+NAME STATUS CLASS-KIND CLASS-NAME RESOURCE-KIND RESOURCE-NAME AGE
+staging-test8 Bound CloudSQLInstanceClass cloudsqlinstancepostgresql-standard CloudSQLInstance xp-ad-demo-24-staging-staging-test8-jj55c 9m
+```
+
+The endpoint of the PostgreSQL instance, and the user credentials, are present in a secret called `app-postgres` within the same project namespace.
+
+Verify the secret with the database information is created with the following command:
+
+```sh
+kubectl describe secret app-postgres
+```
+
+Sample Output:
+
+```
+Name: app-postgres
+Namespace: xp-ad-demo-24-staging
+Labels: <none>
+Annotations: crossplane.io/propagate-from-name: 108e460e-06c7-11ea-b907-42010a8000bd
+ crossplane.io/propagate-from-namespace: gitlab-managed-apps
+ crossplane.io/propagate-from-uid: 10c79605-06c7-11ea-b907-42010a8000bd
+
+Type: Opaque
+
+Data
+====
+privateIP: 8 bytes
+publicIP: 13 bytes
+serverCACertificateCert: 1272 bytes
+serverCACertificateCertSerialNumber: 1 bytes
+serverCACertificateCreateTime: 24 bytes
+serverCACertificateExpirationTime: 24 bytes
+username: 8 bytes
+endpoint: 8 bytes
+password: 27 bytes
+serverCACertificateCommonName: 98 bytes
+serverCACertificateInstance: 41 bytes
+serverCACertificateSha1Fingerprint: 40 bytes
+```
+
+## Connect to the PostgresQL instance
+
+Follow this [GCP guide](https://cloud.google.com/sql/docs/postgres/connect-kubernetes-engine) if you
+would like to connect to the newly provisioned Postgres database instance on CloudSQL.
diff --git a/doc/user/clusters/img/advanced-settings-cluster-management-project-v12_5.png b/doc/user/clusters/img/advanced-settings-cluster-management-project-v12_5.png
new file mode 100644
index 00000000000..63e2d1cd4e8
--- /dev/null
+++ b/doc/user/clusters/img/advanced-settings-cluster-management-project-v12_5.png
Binary files differ
diff --git a/doc/user/clusters/management_project.md b/doc/user/clusters/management_project.md
index 37308ad7175..83b6f6fe300 100644
--- a/doc/user/clusters/management_project.md
+++ b/doc/user/clusters/management_project.md
@@ -4,7 +4,7 @@ CAUTION: **Warning:**
This is an _alpha_ feature, and it is subject to change at any time without
prior notice.
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/17866) in GitLab 12.4
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/32810) in GitLab 12.5
A project can be designated as the management project for a cluster.
A management project can be used to run deployment jobs with
@@ -20,14 +20,37 @@ This can be useful for:
## Permissions
Only the management project will receive `cluster-admin` privileges. All
-other projects will continue to receive [namespace scoped `edit` level privileges](../project/clusters/index.md#rbac-cluster-resources).
+other projects will continue to receive [namespace scoped `edit` level privileges](../project/clusters/add_remove_clusters.md#rbac-cluster-resources).
+
+Management projects are restricted to the following:
+
+- For project-level clusters, the management project must in the same
+ namespace (or descendants) as the cluster's project.
+- For group-level clusters, the management project must in the same
+ group (or descendants) as as the cluster's group.
+- For instance-level clusters, there are no such restrictions.
## Usage
+To use a cluster management project for a cluster:
+
+1. Select the project.
+1. Configure your pipelines.
+1. Set an environment scope.
+
### Selecting a cluster management project
-This will be implemented as part of [this
-issue](https://gitlab.com/gitlab-org/gitlab/issues/32810).
+To select a cluster management project to use:
+
+1. Navigate to the appropriate configuration page. For a:
+ - [Project-level cluster](../project/clusters/index.md), navigate to your project's
+ **Operations > Kubernetes** page.
+ - [Group-level cluster](../group/clusters/index.md), navigate to your group's **Kubernetes**
+ page.
+1. Select the project using **Cluster management project field** in the **Advanced settings**
+ section.
+
+![Selecting a cluster management project under Advanced settings](img/advanced-settings-cluster-management-project-v12_5.png)
### Configuring your pipeline
@@ -60,7 +83,7 @@ to a management project:
| Staging | `staging` |
| Production | `production` |
-The the following environments set in
+The following environments set in
[`.gitlab-ci.yml`](../../ci/yaml/README.md) will deploy to the
Development, Staging, and Production cluster respectively.
@@ -86,16 +109,3 @@ configure production cluster:
environment:
name: production
```
-
-## Disabling this feature
-
-This feature is enabled by default. To disable this feature, disable the
-feature flag `:cluster_management_project`.
-
-To check if the feature flag is enabled on your GitLab instance,
-please ask an administrator to execute the following in a Rails console:
-
-```ruby
-Feature.enabled?(:cluster_management_project) # Check if it's enabled or not.
-Feature.disable(:cluster_management_project) # Disable the feature flag.
-```
diff --git a/doc/user/group/clusters/index.md b/doc/user/group/clusters/index.md
index 4742e7189b7..1fe456902a2 100644
--- a/doc/user/group/clusters/index.md
+++ b/doc/user/group/clusters/index.md
@@ -58,13 +58,18 @@ differentiate the new cluster from the rest.
You can choose to allow GitLab to manage your cluster for you. If your cluster is
managed by GitLab, resources for your projects will be automatically created. See the
-[Access controls](../../project/clusters/index.md#access-controls) section for details on which resources will
+[Access controls](../../project/clusters/add_remove_clusters.md#access-controls) section for details on which resources will
be created.
-If you choose to manage your own cluster, project-specific resources will not be created
-automatically. If you are using [Auto DevOps](../../../topics/autodevops/index.md), you will
-need to explicitly provide the `KUBE_NAMESPACE` [deployment variable](../../project/clusters/index.md#deployment-variables)
-that will be used by your deployment jobs.
+For clusters not managed by GitLab, project-specific resources will not be created
+automatically. If you are using [Auto DevOps](../../../topics/autodevops/index.md)
+for deployments with a cluster not managed by GitLab, you must ensure:
+
+- The project's deployment service account has permissions to deploy to
+ [`KUBE_NAMESPACE`](../../project/clusters/index.md#deployment-variables).
+- `KUBECONFIG` correctly reflects any changes to `KUBE_NAMESPACE`
+ (this is [not automatic](https://gitlab.com/gitlab-org/gitlab/issues/31519)). Editing
+ `KUBE_NAMESPACE` directly is discouraged.
NOTE: **Note:**
If you [install applications](#installing-applications) on your cluster, GitLab will create
@@ -147,7 +152,7 @@ are deployed to the Kubernetes cluster, see the documentation for
For important information about securely configuring GitLab Runners, see
[Security of
-Runners](../../project/clusters/index.md#security-of-gitlab-runners)
+Runners](../../project/clusters/add_remove_clusters.md#security-of-gitlab-runners)
documentation for project-level clusters.
<!-- ## Troubleshooting
diff --git a/doc/user/group/epics/img/epic_view_roadmap_v12.3.png b/doc/user/group/epics/img/epic_view_roadmap_v12.3.png
index a17c56c618b..a17c56c618b 100755..100644
--- a/doc/user/group/epics/img/epic_view_roadmap_v12.3.png
+++ b/doc/user/group/epics/img/epic_view_roadmap_v12.3.png
Binary files differ
diff --git a/doc/user/group/epics/img/epic_view_v12.3.png b/doc/user/group/epics/img/epic_view_v12.3.png
index 79758cf3d52..79758cf3d52 100755..100644
--- a/doc/user/group/epics/img/epic_view_v12.3.png
+++ b/doc/user/group/epics/img/epic_view_v12.3.png
Binary files differ
diff --git a/doc/user/group/epics/img/epics_list_view_v12.3.png b/doc/user/group/epics/img/epics_list_view_v12.3.png
deleted file mode 100755
index c6817a503e7..00000000000
--- a/doc/user/group/epics/img/epics_list_view_v12.3.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/group/epics/img/epics_list_view_v12.5.png b/doc/user/group/epics/img/epics_list_view_v12.5.png
new file mode 100644
index 00000000000..2520ee67abc
--- /dev/null
+++ b/doc/user/group/epics/img/epics_list_view_v12.5.png
Binary files differ
diff --git a/doc/user/group/epics/index.md b/doc/user/group/epics/index.md
index f9690d4edfe..0753df70bc2 100644
--- a/doc/user/group/epics/index.md
+++ b/doc/user/group/epics/index.md
@@ -10,7 +10,7 @@ Epics let you manage your portfolio of projects more efficiently and with less
effort by tracking groups of issues that share a theme, across projects and
milestones.
-![epics list view](img/epics_list_view_v12.3.png)
+![epics list view](img/epics_list_view_v12.5.png)
## Use cases
@@ -92,24 +92,44 @@ To remove a child epic from a parent epic:
## Start date and due date
-To set a **Start date** and **Due date** for an epic, you can choose either of the following:
+To set a **Start date** and **Due date** for an epic, select one of the following:
- **Fixed**: Enter a fixed value.
-- **From milestones:** Inherit a dynamic value from the issues added to the epic.
+- **From milestones**: Inherit a dynamic value from the issues added to the epic.
+- **Inherited**: Inherit a dynamic value from the issues added to the epic. ([Introduced](https://gitlab.com/gitlab-org/gitlab/issues/7332) in GitLab 12.5 to replace **From milestones**).
-If you select **From milestones** for the start date, GitLab will automatically set the
-date to be earliest start date across all milestones that are currently assigned
-to the issues that are added to the epic. Similarly, if you select "From milestones"
-for the due date, GitLab will set it to be the latest due date across all
-milestones that are currently assigned to those issues.
+### Milestones
-These are dynamic dates which are recalculated immediately if any of the following occur:
+If you select **From milestones** for the start date, GitLab will automatically set the date to be earliest
+start date across all milestones that are currently assigned to the issues that are added to the epic.
+Similarly, if you select **From milestones** for the due date, GitLab will set it to be the latest due date across
+all milestones that are currently assigned to those issues.
+
+These are dynamic dates which are recalculated if any of the following occur:
- Milestones are re-assigned to the issues.
- Milestone dates change.
- Issues are added or removed from the epic.
-## Roadmap
+### Inherited
+
+If you select **Inherited** for the start date, GitLab will scan all child epics and issues assigned to the epic,
+and will set the start date to match the earliest found start date or milestone. Similarly, if you select
+**Inherited** for the due date, GitLab will set the due date to match the latest due date or milestone
+found among its child epics and issues.
+
+These are dynamic dates and recalculated if any of the following occur:
+
+- A child epic's dates change.
+- Milestones are reassigned to an issue.
+- A milestone's dates change.
+- Issues are added to, or removed from, the epic.
+
+Because the epic's dates can inherit dates from its children, the start date and due date propagate from the bottom to the top.
+If the start date of a child epic on the lowest level changes, that becomes the earliest possible start date for its parent epic,
+then the parent epic's start date will reflect the change and this will propagate upwards to the top epic.
+
+## Roadmap in epics
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/7327) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.10.
@@ -121,6 +141,8 @@ have a [start or due date](#start-date-and-due-date), a
## Reordering issues and child epics
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/9367) in GitLab 12.5.
+
New issues and child epics are added to the top of their respective lists in the **Epics and Issues** tab. You can reorder the list of issues and the list of child epics. Issues and child epics cannot be intermingled.
To reorder issues assigned to an epic:
@@ -267,7 +289,7 @@ Once you wrote your comment, you can either:
## Notifications
-- [Receive notifications](../../../workflow/notifications.md) for epic events.
+- [Receive notifications](../../profile/notifications.md) for epic events.
<!-- ## Troubleshooting
diff --git a/doc/user/group/index.md b/doc/user/group/index.md
index c4be08c842b..5f45a462f94 100644
--- a/doc/user/group/index.md
+++ b/doc/user/group/index.md
@@ -75,7 +75,7 @@ By doing so:
## Issues and merge requests within a group
Issues and merge requests are part of projects. For a given group, you can view all of the
-[issues](../project/issues/index.md#issues-list) and [merge requests](../project/merge_requests/index.md#merge-requests-per-group) across all projects in that group,
+[issues](../project/issues/index.md#issues-list) and [merge requests](../project/merge_requests/reviewing_and_managing_merge_requests.md#view-merge-requests-for-all-projects-in-a-group) across all projects in that group,
together in a single list view.
### Bulk editing issues and merge requests
@@ -123,7 +123,7 @@ For more details on creating groups, watch the video [GitLab Namespaces (users,
## Add users to a group
A benefit of putting multiple projects in one group is that you can
-give a user to access to all projects in the group with one action.
+give a user access to all projects in the group with one action.
Add members to a group by navigating to the group's dashboard and clicking **Members**.
@@ -135,14 +135,14 @@ Consider a group with two projects:
- On the **Group Members** page, you can now add a new user to the group.
- Now, because this user is a **Developer** member of the group, they automatically
- gets **Developer** access to **all projects** within that group.
+ get **Developer** access to **all projects** within that group.
To increase the access level of an existing user for a specific project,
add them again as a new member to the project with the desired permission level.
## Request access to a group
-As a group owner, you can enable or disable the ability for non members to request access to
+As a group owner, you can enable or disable the ability for non-members to request access to
your group. Go to the group settings, and click **Allow users to request access**.
As a user, you can request to be a member of a group, if that setting is enabled. Go to the group for which you'd like to be a member, and click the **Request Access** button on the right
@@ -353,10 +353,10 @@ content.
Restriction currently applies to:
- UI.
-- API access.
+- [From GitLab 12.3](https://gitlab.com/gitlab-org/gitlab/issues/12874), API access.
- [From GitLab 12.4](https://gitlab.com/gitlab-org/gitlab/issues/32113), Git actions via SSH.
-To avoid accidental lock-out, admins and group owners are are able to access
+To avoid accidental lock-out, admins and group owners are able to access
the group regardless of the IP restriction.
#### Allowed domain restriction **(PREMIUM)**
@@ -385,7 +385,7 @@ Some domains cannot be restricted. These are the most popular public email domai
To enable this feature:
1. Navigate to the group's **Settings > General** page.
-1. Expand the **Permissions, LFS, 2FA** section, and enter domain name into **Restrict membership by email** field.
+1. Expand the **Permissions, LFS, 2FA** section, and enter the domain name into **Restrict membership by email** field.
1. Click **Save changes**.
This will enable the domain-checking for all new users added to the group from this moment on.
@@ -421,8 +421,9 @@ Define project templates at a group level by setting a group as the template sou
#### Disabling email notifications
-You can disable all email notifications related to the group, which also includes
-it's subgroups and projects.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/23585) in GitLab 12.2.
+
+You can disable all email notifications related to the group, which includes its subgroups and projects.
To enable this feature:
@@ -444,7 +445,7 @@ To enable this feature:
> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/13294) in [GitLab Starter](https://about.gitlab.com/pricing/) 12.0.
-A group owner can check the aggregated storage usage for all the project in a group, sub-groups included, in the **Storage** tab of the **Usage Quotas** page available to the group page settings list.
+A group owner can check the aggregated storage usage for all the projects in a group, sub-groups included, in the **Storage** tab of the **Usage Quotas** page available to the group page settings list.
![Group storage usage quota](img/group_storage_usage_quota.png)
diff --git a/doc/user/group/roadmap/index.md b/doc/user/group/roadmap/index.md
index bcd79bd04bf..a72cd990706 100644
--- a/doc/user/group/roadmap/index.md
+++ b/doc/user/group/roadmap/index.md
@@ -26,7 +26,7 @@ Epics in the view can be sorted by:
Each option contains a button that toggles the sort order between **ascending** and **descending**. The sort option and order will be persisted when browsing Epics,
including the [epics list view](../epics/index.md).
-Roadmaps can also be [visualized inside an epic](../epics/index.md#roadmap).
+Roadmaps can also be [visualized inside an epic](../epics/index.md#roadmap-in-epics).
## Timeline duration
diff --git a/doc/user/group/saml_sso/index.md b/doc/user/group/saml_sso/index.md
index ecf2934b877..6fd56414796 100644
--- a/doc/user/group/saml_sso/index.md
+++ b/doc/user/group/saml_sso/index.md
@@ -26,6 +26,23 @@ SAML SSO for GitLab.com groups does not sync users between providers without usi
![Issuer and callback for configuring SAML identity provider with GitLab.com](img/group_saml_configuration_information.png)
+### NameID
+
+GitLab.com uses the SAML NameID to identify users. The NameID element:
+
+- Is a required field in the SAML response.
+- Must be unique to each user.
+- Must be a persistent value that will never change, such as a randomly generated unique user ID.
+- Is case sensitive. The NameID must match exactly on subsequent login attempts, so should not rely on user input that could change between upper and lower case.
+- Should not be an email address or username. We strongly recommend against these as it is hard to guarantee they will never change, for example when a person's name changes. Email addresses are also case-insensitive, which can result in users being unable to sign in.
+
+CAUTION: **Warning:**
+Once users have signed into GitLab using the SSO SAML setup, changing the `NameID` will break the configuration and potentially lock users out of the GitLab group.
+
+#### NameID Format
+
+We recommend setting the NameID format to `Persistent` unless using a field (such as email) that requires a different format.
+
### SSO enforcement
SSO enforcement was:
@@ -58,25 +75,16 @@ Since use of the group managed account requires the use of SSO, users of group m
- The user will be unable to access the group (their credentials will no longer work on the identity provider when prompted to SSO).
- Contributions in the group (e.g. issues, merge requests) will remain intact.
-### NameID
+#### Assertions
-GitLab.com uses the SAML NameID to identify users. The NameID element:
+When using Group Manged Accounts, the following user details need to be passed to GitLab as SAML Assertions in order for us to be able to create a user:
-- Is a required field in the SAML response.
-- Must be unique to each user.
-- Must be a persistent value that will never change, such as a randomly generated unique user ID.
-- Is case sensitive. The NameID must match exactly on subsequent login attempts, so should not rely on user input that could change between upper and lower case.
-
-We strongly recommend against using Email as the NameID as it is hard to guarantee it will never change, for example when a person's name changes. Similarly usernames should be avoided if possible.
-
-### Assertions
-
-| Field | Supported keys |
-|-------|----------------|
+| Field | Supported keys |
+|-----------------|----------------|
| Email (required)| `email`, `mail` |
-| Full Name | `name` |
-| First Name | `first_name`, `firstname`, `firstName` |
-| Last Name | `last_name`, `lastname`, `lastName` |
+| Full Name | `name` |
+| First Name | `first_name`, `firstname`, `firstName` |
+| Last Name | `last_name`, `lastname`, `lastName` |
## Metadata configuration
@@ -108,17 +116,28 @@ NOTE: **Note:** GitLab is unable to provide support for IdPs that are not listed
| Azure | [Configuring single sign-on to applications](https://docs.microsoft.com/en-us/azure/active-directory/manage-apps/configure-single-sign-on-non-gallery-applications) |
| Auth0 | [Auth0 as Identity Provider](https://auth0.com/docs/protocols/saml/saml-idp-generic) |
| G Suite | [Set up your own custom SAML application](https://support.google.com/a/answer/6087519?hl=en) |
-| JumpCloud | [Single Sign On (SSO) with GitLab](https://support.jumpcloud.com/customer/en/portal/articles/2810701-single-sign-on-sso-with-gitlab) |
+| JumpCloud | [Single Sign On (SSO) with GitLab](https://support.jumpcloud.com/support/s/article/single-sign-on-sso-with-gitlab-2019-08-21-10-36-47) |
| Okta | [Setting up a SAML application in Okta](https://developer.okta.com/docs/guides/saml-application-setup/overview/) |
| OneLogin | [Use the OneLogin SAML Test Connector](https://onelogin.service-now.com/support?id=kb_article&sys_id=93f95543db109700d5505eea4b96198f) |
| Ping Identity | [Add and configure a new SAML application](https://support.pingidentity.com/s/document-item?bundleId=pingone&topicId=xsh1564020480660-1.html) |
When [configuring your identify provider](#configuring-your-identity-provider), please consider the notes below for specific providers to help avoid common issues and as a guide for terminology used.
+### Okta setup notes
+
+| GitLab Setting | Okta Field |
+|--------------|----------------|
+| Identifier | Audience URI |
+| Assertion consumer service URL | Single sign on URL |
+
+Under Okta's **Single sign on URL** field, check the option **Use this for Recipient URL and Destination URL**.
+
+Set attribute statements according to the [assertions table](#assertions).
+
### OneLogin setup notes
-NOTE: **Note:**
-The GitLab app listed in the directory is for self-managed GitLab instances. Please use a generic SAML Test Connector.
+The GitLab app listed in the OneLogin app catalog is for self-managed GitLab instances.
+For GitLab.com, use a generic SAML Test Connector such as the SAML Test Connector (Advanced).
| GitLab Setting | OneLogin Field |
|--------------|----------------|
diff --git a/doc/user/group/saml_sso/scim_setup.md b/doc/user/group/saml_sso/scim_setup.md
index 60b779b3f70..392b27bb42f 100644
--- a/doc/user/group/saml_sso/scim_setup.md
+++ b/doc/user/group/saml_sso/scim_setup.md
@@ -25,25 +25,6 @@ The following identity providers are supported:
## Requirements
- [Group SSO](index.md) needs to be configured.
-- The `scim_group` feature flag must be enabled:
-
- Run the following commands in a Rails console:
-
- ```sh
- # Omnibus GitLab
- gitlab-rails console
-
- # Installation from source
- cd /home/git/gitlab
- sudo -u git -H bin/rails console RAILS_ENV=production
- ```
-
- To enable SCIM for a group named `group_name`:
-
- ```ruby
- group = Group.find_by_full_path('group_name')
- Feature.enable(:group_scim, group)
- ```
## GitLab configuration
@@ -85,8 +66,13 @@ You can then test the connection by clicking on **Test Connection**. If the conn
1. Click **Delete** next to the `mail` mapping.
1. Map `userPrincipalName` to `emails[type eq "work"].value` and change it's **Matching precedence** to `2`.
1. Map `mailNickname` to `userName`.
-1. Create a new mapping by clicking **Add New Mapping** then set **Source attribute** to `objectId`, **Target attribute** to `id`, **Match objects using this attribute** to `Yes`, and **Matching precedence** to `1`.
-1. Create a new mapping by clicking **Add New Mapping** then set **Source attribute** to `objectId`, and **Target attribute** to `externalId`.
+1. Determine how GitLab will uniquely identify users.
+
+ - Use `objectId` unless users already have SAML linked for your group.
+ - If you already have users with SAML linked then use the `Name ID` value from the [SAML configuration](#azure). Using a different value will likely cause duplicate users and prevent users from accessing the GitLab group.
+
+1. Create a new mapping by clicking **Add New Mapping** then set **Source attribute** to the unique identifier determined above, **Target attribute** to `id`, **Match objects using this attribute** to `Yes`, and **Matching precedence** to `1`.
+1. Create a new mapping by clicking **Add New Mapping** then set **Source attribute** to the unique identifier determined above, and **Target attribute** to `externalId`.
1. Click the `userPrincipalName` mapping and change **Match objects using this attribute** to `No`.
Save your changes and you should have the following configuration:
@@ -118,6 +104,9 @@ You can then test the connection by clicking on **Test Connection**. If the conn
Once enabled, the synchronization details and any errors will appear on the
bottom of the **Provisioning** screen, together with a link to the audit logs.
+CAUTION: **Warning:**
+Once synchronized, changing the field mapped to `id` and `externalId` will likely cause provisioning errors, duplicate users, and prevent existing users from accessing the GitLab group.
+
## Troubleshooting
### Testing Azure connection: invalid credentials
diff --git a/doc/user/group/subgroups/index.md b/doc/user/group/subgroups/index.md
index a3606fadb89..52b7035389a 100644
--- a/doc/user/group/subgroups/index.md
+++ b/doc/user/group/subgroups/index.md
@@ -176,7 +176,7 @@ Here's a list of what you can't do with subgroups:
- [GitLab Pages](../../project/pages/index.md) supports projects hosted under
a subgroup, but not subgroup websites.
That means that only the highest-level group supports
- [group websites](../../project/pages/getting_started_part_one.md#gitlab-pages-domain-names),
+ [group websites](../../project/pages/getting_started_part_one.md#gitlab-pages-default-domain-names),
although you can have project websites under a subgroup.
- It is not possible to share a project with a group that's an ancestor of
the group the project is in. That means you can only share as you walk down
diff --git a/doc/workflow/img/todos_add_todo_sidebar.png b/doc/user/img/todos_add_todo_sidebar.png
index aefec7a2d9c..aefec7a2d9c 100644
--- a/doc/workflow/img/todos_add_todo_sidebar.png
+++ b/doc/user/img/todos_add_todo_sidebar.png
Binary files differ
diff --git a/doc/workflow/img/todos_icon.png b/doc/user/img/todos_icon.png
index 9fee4337a75..9fee4337a75 100644
--- a/doc/workflow/img/todos_icon.png
+++ b/doc/user/img/todos_icon.png
Binary files differ
diff --git a/doc/workflow/img/todos_index.png b/doc/user/img/todos_index.png
index 99c1575d157..99c1575d157 100644
--- a/doc/workflow/img/todos_index.png
+++ b/doc/user/img/todos_index.png
Binary files differ
diff --git a/doc/workflow/img/todos_mark_done_sidebar.png b/doc/user/img/todos_mark_done_sidebar.png
index 2badd880b40..2badd880b40 100644
--- a/doc/workflow/img/todos_mark_done_sidebar.png
+++ b/doc/user/img/todos_mark_done_sidebar.png
Binary files differ
diff --git a/doc/workflow/img/todo_list_item.png b/doc/user/img/todos_todo_list_item.png
index 91bbf9e5373..91bbf9e5373 100644
--- a/doc/workflow/img/todo_list_item.png
+++ b/doc/user/img/todos_todo_list_item.png
Binary files differ
diff --git a/doc/user/incident_management/img/incident_management_settings.png b/doc/user/incident_management/img/incident_management_settings.png
new file mode 100644
index 00000000000..25ad4fd08b7
--- /dev/null
+++ b/doc/user/incident_management/img/incident_management_settings.png
Binary files differ
diff --git a/doc/user/incident_management/index.md b/doc/user/incident_management/index.md
new file mode 100644
index 00000000000..5ac27d227a1
--- /dev/null
+++ b/doc/user/incident_management/index.md
@@ -0,0 +1,131 @@
+---
+description: "GitLab - Incident Management. GitLab offers solutions for handling incidents in your applications and services"
+---
+
+# Incident Management
+
+GitLab offers solutions for handling incidents in your applications and services,
+from setting up an alert with Prometheus, to receiving a notification via a
+monitoring tool like Slack, and automatically setting up Zoom calls with your
+support team.
+
+## Configuring incidents **(ULTIMATE)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/4925) in GitLab Ultimate 11.11.
+
+The Incident Management features can be enabled and disabled via your project's
+**Settings > Operations > Incidents**.
+
+![Incident Management Settings](img/incident_management_settings.png)
+
+### Automatically create issues from alerts
+
+GitLab issues can automatically be created as a result of an alert notification.
+An issue created this way will contain the error information to help you further
+debug it.
+
+### Issue templates
+
+You can create your own [issue templates](../project/description_templates.md#creating-issue-templates)
+that can be [used within Incident Management](../project/integrations/prometheus.md#taking-action-on-incidents-ultimate).
+
+To select your issue template for use within Incident Management:
+
+1. Visit your project's **Settings > Operations > Incidents**.
+1. Select the template from the **Issue Template** dropdown.
+
+## Alerting
+
+GitLab can react to the alerts that your applications and services may be
+triggering by automatically creating issues, and alerting developers via email.
+
+### Prometheus alerts
+
+Prometheus alerts can be set up in both:
+
+- [GitLab-managed Prometheus](../project/integrations/prometheus.md#setting-up-alerts-for-prometheus-metrics-ultimate) and
+- [Self-managed Prometheus](../project/integrations/prometheus.md#external-prometheus-instances) installations.
+
+### Alert endpoint
+
+GitLab can accept alerts from any source via a generic webhook receiver. When
+you set up the generic alerts integration, a unique endpoint will
+be created which can receive a payload in JSON format.
+
+[Read more on setting this up, including how to customize the payload](../project/integrations/generic_alerts.md).
+
+### Recovery alerts
+
+GitLab can [automatically close issues](../project/integrations/prometheus.md#taking-action-on-incidents-ultimate)
+that have been automatically created when you receive notification that the
+alert is resolved.
+
+## Embedded metrics
+
+Metrics can be embedded anywhere where GitLab Markdown is used, for example,
+descriptions and comments on issues and merge requests.
+
+TIP: **Tip:**
+Both GitLab-hosted and Grafana metrics can also be
+[embedded in issue templates](../project/integrations/prometheus.md#embedding-metrics-in-issue-templates).
+
+### GitLab-hosted metrics
+
+Learn how to embed [GitLab hosted metric charts](../project/integrations/prometheus.md#embedding-metric-charts-within-gitlab-flavored-markdown).
+
+### Grafana metrics
+
+Learn how to embed [Grafana hosted metric charts](../project/integrations/prometheus.md#embedding-grafana-charts).
+
+## Slack integration
+
+Slack slash commands allow you to control GitLab and view content right inside
+Slack, without having to leave it.
+
+Learn how to [set up Slack slash commands](../project/integrations/slack_slash_commands.md)
+and how to [use them](../../integration/slash_commands.md).
+
+### Slash commands
+
+Please refer to a list of [available slash commands](../../integration/slash_commands.md) and associated descriptions.
+
+## Zoom in issues
+
+In order to communicate synchronously for incidents management, GitLab allows to
+associate a Zoom meeting with an issue. Once you start a Zoom call for a fire-fight,
+you need a way to associate the conference call with an issue, so that your team
+members can join swiftly without requesting a link.
+
+Read more how to [add or remove a zoom meeting](../project/issues/associate_zoom_meeting.md).
+
+### Alerting
+
+You can let GitLab know of alerts that may be triggering in your applications and services. GitLab can react to these by automatically creating Issues, and alerting developers via Email.
+
+#### Prometheus Alerts
+
+Prometheus alerts can be setup in both GitLab-managed Prometheus installs and self-managed Prometheus installs.
+
+Documentation for each method can be found here:
+
+- [GitLab-managed Prometheus](../project/integrations/prometheus.md#setting-up-alerts-for-prometheus-metrics-ultimate)
+- [Self-managed Prometheus](../project/integrations/prometheus.md#external-prometheus-instances)
+
+#### Alert Endpoint
+
+GitLab can accept alerts from any source via a generic webhook receiver. When you set up the generic alerts integration, a unique endpoint will
+be created which can receive a payload in JSON format.
+
+More information on setting this up, including how to customize the payload [can be found here](../project/integrations/generic_alerts.md).
+
+#### Recovery Alerts
+
+Coming soon: GitLab can automatically close Issues that have been automatically created when we receive notification that the alert is resolved.
+
+### Configuring Incidents
+
+Incident Management features can be easily enabled & disabled via the Project settings page. Head to Project -> Settings -> Operations -> Incidents.
+
+#### Auto-creation
+
+GitLab Issues can automatically be created as a result of an Alert notification. An Issue created this way will contain error information to help you further debug the error.
diff --git a/doc/user/index.md b/doc/user/index.md
index ee5d4a0a07b..ab953b6d8bf 100644
--- a/doc/user/index.md
+++ b/doc/user/index.md
@@ -50,15 +50,15 @@ GitLab is a Git-based platform that integrates a great number of essential tools
With GitLab Enterprise Edition, you can also:
- Provide support with [Service Desk](project/service_desk.md).
-- Improve collaboration with
- [Merge Request Approvals](project/merge_requests/index.md#merge-request-approvals-starter),
- [Multiple Assignees for Issues](project/issues/multiple_assignees_for_issues.md),
- and [Multiple Issue Boards](project/issue_board.md#multiple-issue-boards).
+- Improve collaboration with:
+ - [Merge Request Approvals](project/merge_requests/merge_request_approvals.md). **(STARTER)**
+ - [Multiple Assignees for Issues](project/issues/multiple_assignees_for_issues.md). **(STARTER)**
+ - [Multiple Issue Boards](project/issue_board.md#multiple-issue-boards).
- Create formal relationships between issues with [Related Issues](project/issues/related_issues.md).
- Use [Burndown Charts](project/milestones/burndown_charts.md) to track progress during a sprint or while working on a new version of their software.
- Leverage [Elasticsearch](../integration/elasticsearch.md) with [Advanced Global Search](search/advanced_global_search.md) and [Advanced Syntax Search](search/advanced_search_syntax.md) for faster, more advanced code search across your entire GitLab instance.
- [Authenticate users with Kerberos](../integration/kerberos.md).
-- [Mirror a repository](../workflow/repository_mirroring.md) from elsewhere on your local server.
+- [Mirror a repository](project/repository/repository_mirroring.md) from elsewhere on your local server.
- [Export issues as CSV](project/issues/csv_export.md).
- View your entire CI/CD pipeline involving more than one project with [Multiple-Project Pipelines](../ci/multi_project_pipeline_graphs.md).
- [Lock files](project/file_lock.md) to prevent conflicts.
@@ -130,12 +130,12 @@ gather feedback through [resolvable threads](discussions/index.md#resolvable-com
Read through the [GFM documentation](markdown.md) to learn how to apply
the best of GitLab Flavored Markdown in your threads, comments,
-issues and merge requests descriptions, and everywhere else GMF is
+issues and merge requests descriptions, and everywhere else GFM is
supported.
## Todos
-Never forget to reply to your collaborators. [GitLab Todos](../workflow/todos.md)
+Never forget to reply to your collaborators. [GitLab Todos](todos.md)
are a tool for working faster and more effectively with your team,
by listing all user or group mentions, as well as issues and merge
requests you're assigned to.
@@ -150,6 +150,11 @@ requests you're assigned to.
you have quick access to. You can also gather feedback on them through
[Discussions](#Discussions).
+## Keyboard shortcuts
+
+There are many [keyboard shortcuts](shortcuts.md) in GitLab to help you navigate between
+pages and accomplish tasks faster.
+
## Integrations
[Integrate GitLab](../integration/README.md) with your preferred tool,
diff --git a/doc/user/markdown.md b/doc/user/markdown.md
index 0b4bb43b4bf..3bd0dcafc19 100644
--- a/doc/user/markdown.md
+++ b/doc/user/markdown.md
@@ -405,6 +405,7 @@ GFM will recognize the following:
| label by ID | `~123` | `namespace/project~123` | `project~123` |
| one-word label by name | `~bug` | `namespace/project~bug` | `project~bug` |
| multi-word label by name | `~"feature request"` | `namespace/project~"feature request"` | `project~"feature request"` |
+| scoped label by name | `~"priority::high"` | `namespace/project~"priority::high"` | `project~"priority::high"` |
| project milestone by ID | `%123` | `namespace/project%123` | `project%123` |
| one-word milestone by name | `%v1.23` | `namespace/project%v1.23` | `project%v1.23` |
| multi-word milestone by name | `%"release candidate"` | `namespace/project%"release candidate"` | `project%"release candidate"` |
@@ -417,9 +418,10 @@ GFM will recognize the following:
> If this is not rendered correctly, [view it in GitLab itself](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#task-lists).
-You can add task lists anywhere markdown is supported, but you can only "click" to
-toggle the boxes if they are in issues, merge requests, or comments. In other places
-you must edit the markdown manually to change the status by adding or removing the `x`.
+You can add task lists anywhere Markdown is supported, but you can only "click"
+to toggle the boxes if they are in issues, merge requests, or comments. In other
+places you must edit the Markdown manually to change the status by adding or
+removing an `x` within the square brackets.
To create a task list, add a specially-formatted Markdown list. You can use either
unordered or ordered lists:
diff --git a/doc/user/operations_dashboard/img/index_operations_dashboard_top_bar_icon.png b/doc/user/operations_dashboard/img/index_operations_dashboard_top_bar_icon.png
deleted file mode 100644
index d4db5e88672..00000000000
--- a/doc/user/operations_dashboard/img/index_operations_dashboard_top_bar_icon.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/operations_dashboard/index.md b/doc/user/operations_dashboard/index.md
index 649a95a5f3a..cdb80cca6f7 100644
--- a/doc/user/operations_dashboard/index.md
+++ b/doc/user/operations_dashboard/index.md
@@ -5,10 +5,7 @@
The Operations Dashboard provides a summary of each project's operational health,
including pipeline and alert status.
-The dashboard can be accessed via the top bar, by clicking on the new
-dashboard icon:
-
-![Operations Dashboard icon in top bar](img/index_operations_dashboard_top_bar_icon.png)
+The dashboard can be accessed via the top bar, by clicking **More > Operations**.
## Adding a project to the dashboard
@@ -28,6 +25,10 @@ last commit, pipeline status, and when it was last deployed.
![Operations Dashboard with projects](img/index_operations_dashboard_with_projects.png)
+## Arranging projects on a dashboard
+
+You can drag project cards to change their order. The card order is currently only saved to your browser, so will not change the dashboard for other people.
+
## Making it the default dashboard when you sign in
The Operations Dashboard can also be made the default GitLab dashboard shown when
diff --git a/doc/user/packages/conan_repository/index.md b/doc/user/packages/conan_repository/index.md
index f81756f7979..953c7472f4d 100644
--- a/doc/user/packages/conan_repository/index.md
+++ b/doc/user/packages/conan_repository/index.md
@@ -1,6 +1,6 @@
# GitLab Conan Repository **(PREMIUM)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/8248) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.4.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/8248) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.5.
With the GitLab Conan Repository, every
project can have its own space to store Conan packages.
diff --git a/doc/user/packages/dependency_proxy/index.md b/doc/user/packages/dependency_proxy/index.md
index d6358d72348..60f4dbc0abb 100644
--- a/doc/user/packages/dependency_proxy/index.md
+++ b/doc/user/packages/dependency_proxy/index.md
@@ -1,4 +1,4 @@
-# Dependency Proxy **(PREMIUM)**
+# Dependency Proxy **(PREMIUM ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/7934) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.11.
diff --git a/doc/user/packages/npm_registry/index.md b/doc/user/packages/npm_registry/index.md
index 5f5d86ab17e..d8b59ae63d0 100644
--- a/doc/user/packages/npm_registry/index.md
+++ b/doc/user/packages/npm_registry/index.md
@@ -42,6 +42,9 @@ it is not possible due to a naming collision. For example:
| `gitlab-org/gitlab` | `@gitlab-org/gitlab` | Yes |
| `gitlab-org/gitlab` | `@foo/bar` | No |
+CAUTION: **When updating the path of a user/group or transferring a (sub)group/project:**
+If you update the root namespace of a project with NPM packages, your changes will be rejected. To be allowed to do that, make sure to remove any NPM package first. Don't forget to update your `.npmrc` files to follow the above naming convention and run `npm publish` if necessary.
+
Now, you can configure your project to authenticate with the GitLab NPM
Registry.
@@ -105,6 +108,21 @@ Then, you could run `npm publish` either locally or via GitLab CI/CD:
- **GitLab CI/CD:** Set an `NPM_TOKEN` [variable](../../../ci/variables/README.md)
under your project's **Settings > CI/CD > Variables**.
+
+### Authenticating with a CI job token
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/9104) in GitLab Premium 12.5.
+
+If you’re using NPM with GitLab CI/CD, a CI job token can be used instead of a personal access token.
+The token will inherit the permissions of the user that generates the pipeline.
+
+Add a corresponding section to your `.npmrc` file:
+
+```ini
+@foo:registry=https://gitlab.com/api/v4/packages/npm/
+//gitlab.com/api/v4/packages/npm/:_authToken=${env.CI_JOB_TOKEN}
+//gitlab.com/api/v4/projects/{env.CI_PROJECT_ID>/packages/npm/:_authToken=${env.CI_JOB_TOKEN}
+```
## Uploading packages
diff --git a/doc/user/permissions.md b/doc/user/permissions.md
index 90874eca2eb..70660e5e22f 100644
--- a/doc/user/permissions.md
+++ b/doc/user/permissions.md
@@ -51,11 +51,11 @@ The following table depicts the various user permission levels in a project.
| View Security reports **(ULTIMATE)** | ✓ (*3*) | ✓ | ✓ | ✓ | ✓ |
| View Dependency list **(ULTIMATE)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
| View licenses in Dependency list **(ULTIMATE)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
-| View [Design Management](project/issues/design_management.md) pages **(PREMIUM)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
+| View [Design Management](project/issues/design_management.md) pages **(PREMIUM)** | ✓ | ✓ | ✓ | ✓ | ✓ |
| View project code | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
| Pull project code | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
| View GitLab Pages protected by [access control](project/pages/introduction.md#gitlab-pages-access-control-core) | ✓ | ✓ | ✓ | ✓ | ✓ |
-| View wiki pages | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
+| View wiki pages | ✓ | ✓ | ✓ | ✓ | ✓ |
| See a list of jobs | ✓ (*3*) | ✓ | ✓ | ✓ | ✓ |
| See a job log | ✓ (*3*) | ✓ | ✓ | ✓ | ✓ |
| Download and browse job artifacts | ✓ (*3*) | ✓ | ✓ | ✓ | ✓ |
@@ -83,7 +83,7 @@ The following table depicts the various user permission levels in a project.
| Push to non-protected branches | | | ✓ | ✓ | ✓ |
| Force push to non-protected branches | | | ✓ | ✓ | ✓ |
| Remove non-protected branches | | | ✓ | ✓ | ✓ |
-| Create new merge request | | | ✓ | ✓ | ✓ |
+| Create new merge request | | ✓ | ✓ | ✓ | ✓ |
| Assign merge requests | | | ✓ | ✓ | ✓ |
| Label merge requests | | | ✓ | ✓ | ✓ |
| Lock merge request threads | | | ✓ | ✓ | ✓ |
@@ -103,6 +103,7 @@ The following table depicts the various user permission levels in a project.
| Apply code change suggestions | | | ✓ | ✓ | ✓ |
| Create and edit wiki pages | | | ✓ | ✓ | ✓ |
| Rewrite/remove Git tags | | | ✓ | ✓ | ✓ |
+| Manage Feature Flags **(PREMIUM)** | | | ✓ | ✓ | ✓ |
| Use environment terminals | | | | ✓ | ✓ |
| Run Web IDE's Interactive Web Terminals **(ULTIMATE ONLY)** | | | | ✓ | ✓ |
| Add new team members | | | | ✓ | ✓ |
@@ -120,6 +121,7 @@ The following table depicts the various user permission levels in a project.
| Manage GitLab Pages domains and certificates | | | | ✓ | ✓ |
| Remove GitLab Pages | | | | ✓ | ✓ |
| Manage clusters | | | | ✓ | ✓ |
+| View Pods logs **(ULTIMATE)** | | | | ✓ | ✓ |
| Manage license policy **(ULTIMATE)** | | | | ✓ | ✓ |
| Edit comments (posted by any user) | | | | ✓ | ✓ |
| Manage Error Tracking | | | | ✓ | ✓ |
@@ -168,7 +170,7 @@ the [documentation on Cycle Analytics permissions](analytics/cycle_analytics.md#
Developers and users with higher permission level can use all
the functionality of the Issue Board, that is create/delete lists
-and drag issues around. Read though the
+and drag issues around. Read through the
[documentation on Issue Boards permissions](project/issue_board.md#permissions)
to learn more.
diff --git a/doc/user/profile/account/delete_account.md b/doc/user/profile/account/delete_account.md
index be761ca7558..beea063672e 100644
--- a/doc/user/profile/account/delete_account.md
+++ b/doc/user/profile/account/delete_account.md
@@ -32,63 +32,6 @@ As an administrator, you can delete a user account by:
- **Delete user and contributions** to delete the user and
their associated records.
-### Blocking a user
-
-In addition to blocking a user
-[via an abuse report](../../admin_area/abuse_reports.md#blocking-users),
-a user can be blocked directly from the Admin area. To do this:
-
-1. Navigate to **Admin Area > Overview > Users**.
-1. Selecting a user.
-1. Under the **Account** tab, click **Block user**.
-
-### Deactivating a user
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/63921) in GitLab 12.4.
-
-A user can be deactivated from the Admin area. Deactivating a user is functionally identical to blocking a user, with the following differences:
-
-- It does not prohibit the user from logging back in via the UI.
-- Once a deactivated user logs back into the GitLab UI, their account is set to active.
-
-A deactivated user:
-
-- Cannot access Git repositories or the API.
-- Will not receive any notifications from GitLab.
-- Will not be able to use [slash commands](../../../integration/slash_commands.md).
-
-Personal projects, group and user history of the deactivated user will be left intact.
-
-NOTE: **Note:**
-A deactivated user does not consume a [seat](../../../subscriptions/index.md#managing-subscriptions).
-
-To do this:
-
-1. Navigate to **Admin Area > Overview > Users**.
-1. Select a user.
-1. Under the **Account** tab, click **Deactivate user**.
-
-Please note that for the deactivation option to be visible to an admin, the user:
-
-- Must be currently active.
-- Should not have any activity in the last 180 days.
-
-### Activating a user
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/63921) in GitLab 12.4.
-
-A deactivated user can be activated from the Admin area. Activating a user sets their account to active state.
-
-To do this:
-
-1. Navigate to **Admin Area > Overview > Users**.
-1. Click on the **Deactivated** tab.
-1. Select a user.
-1. Under the **Account** tab, click **Activate user**.
-
-TIP: **Tip:**
-A deactivated user can also activate their account by themselves by simply logging back via the UI.
-
## Associated Records
> - Introduced for issues in
diff --git a/doc/workflow/img/notification_global_settings.png b/doc/user/profile/img/notification_global_settings.png
index 699f726c442..699f726c442 100644
--- a/doc/workflow/img/notification_global_settings.png
+++ b/doc/user/profile/img/notification_global_settings.png
Binary files differ
diff --git a/doc/workflow/img/notification_group_settings.png b/doc/user/profile/img/notification_group_settings.png
index ed5e9459216..ed5e9459216 100644
--- a/doc/workflow/img/notification_group_settings.png
+++ b/doc/user/profile/img/notification_group_settings.png
Binary files differ
diff --git a/doc/workflow/img/notification_project_settings.png b/doc/user/profile/img/notification_project_settings.png
index e2db2037d94..e2db2037d94 100644
--- a/doc/workflow/img/notification_project_settings.png
+++ b/doc/user/profile/img/notification_project_settings.png
Binary files differ
diff --git a/doc/user/profile/index.md b/doc/user/profile/index.md
index 9c4001f0a79..06e4eac6623 100644
--- a/doc/user/profile/index.md
+++ b/doc/user/profile/index.md
@@ -53,7 +53,7 @@ From there, you can:
[use GitLab as an OAuth provider](../../integration/oauth_provider.md#introduction-to-oauth)
- Manage [personal access tokens](personal_access_tokens.md) to access your account via API and authorized applications
- Add and delete emails linked to your account
-- Choose which email to use for notifications, web-based commits, and display on your public profile
+- Choose which email to use for [notifications](notifications.md), web-based commits, and display on your public profile
- Manage [SSH keys](../../ssh/README.md) to access your account via SSH
- Manage your [preferences](preferences.md#syntax-highlighting-theme)
to customize your own GitLab experience
diff --git a/doc/user/profile/notifications.md b/doc/user/profile/notifications.md
new file mode 100644
index 00000000000..388576a48db
--- /dev/null
+++ b/doc/user/profile/notifications.md
@@ -0,0 +1,231 @@
+---
+disqus_identifier: 'https://docs.gitlab.com/ee/workflow/notifications.html'
+---
+
+# GitLab Notification Emails
+
+GitLab Notifications allow you to stay informed about what's happening in GitLab. With notifications enabled, you can receive updates about activity in issues, merge requests, and epics. Notifications are sent via email.
+
+## Receiving notifications
+
+You will receive notifications for one of the following reasons:
+
+- You participate in an issue, merge request, or epic. In this context, _participate_ means comment, or edit.
+- You enable notifications in an issue, merge request, or epic. To enable notifications, click the **Notifications** toggle in the sidebar to _on_.
+
+While notifications are enabled, you will receive notification of actions occurring in that issue, merge request, or epic.
+
+NOTE: **Note:**
+Notifications can be blocked by an admin, preventing them from being sent.
+
+## Tuning your notifications
+
+The quantity of notifications can be overwhelming. GitLab allows you to tune the notifications you receive. For example, you may want to be notified about all activity in a specific project, but for others, only be notified when you are mentioned by name.
+
+You can tune the notifications you receive by combining your notification settings:
+
+- [Global notification settings](#global-notification-settings)
+- [Notification scope](#notification-scope)
+- [Notification levels](#notification-levels)
+
+### Editing notification settings
+
+To edit your notification settings:
+
+1. Click on your profile picture and select **Settings**.
+1. Click **Notifications** in the left sidebar.
+1. Edit the desired notification settings. Edited settings are automatically saved and enabled.
+
+These notification settings apply only to you. They do not affect the notifications received by anyone else in the same project or group.
+
+![notification settings](img/notification_global_settings.png)
+
+## Global notification settings
+
+Your **Global notification settings** are the default settings unless you select different values for a project or a group.
+
+- Notification email
+ - This is the email address your notifications will be sent to.
+- Global notification level
+ - This is the default [notification level](#notification-levels) which applies to all your notifications.
+- Receive notifications about your own activity.
+ - Check this checkbox if you want to receive notification about your own activity. Default: Not checked.
+
+### Notification scope
+
+You can tune the scope of your notifications by selecting different notification levels for each project and group.
+
+Notification scope is applied in order of precedence (highest to lowest):
+
+- Project
+ - For each project, you can select a notification level. Your project setting overrides the group setting.
+- Group
+ - For each group, you can select a notification level. Your group setting overrides your default setting.
+- Global (default)
+ - Your global, or _default_, notification level applies if you have not selected a notification level for the project or group in which the activity occurred.
+
+#### Project notifications
+
+You can select a notification level for each project. This can be useful if you need to closely monitor activity in select projects.
+
+![notification settings](img/notification_project_settings.png)
+
+To select a notification level for a project, use either of these methods:
+
+1. Click on your profile picture and select **Settings**.
+1. Click **Notifications** in the left sidebar.
+1. Locate the project in the **Projects** section.
+1. Select the desired [notification level](#notification-levels).
+
+Or:
+
+1. Navigate to the project's page.
+1. Click the notification dropdown, marked with a bell icon.
+1. Select the desired [notification level](#notification-levels).
+
+#### Group notifications
+
+You can select a notification level and email address for each group.
+
+![notification settings](img/notification_group_settings.png)
+
+##### Group notification level
+
+To select a notification level for a group, use either of these methods:
+
+1. Click on your profile picture and select **Settings**.
+1. Click **Notifications** in the left sidebar.
+1. Locate the project in the **Groups** section.
+1. Select the desired [notification level](#notification-levels).
+
+---
+
+1. Navigate to the group's page.
+1. Click the notification dropdown, marked with a bell icon.
+1. Select the desired [notification level](#notification-levels).
+
+##### Group notification email address
+
+> Introduced in GitLab 12.0
+
+You can select an email address to receive notifications for each group you belong to. This could be useful, for example, if you work freelance, and want to keep email about clients' projects separate.
+
+1. Click on your profile picture and select **Settings**.
+1. Click **Notifications** in the left sidebar.
+1. Locate the project in the **Groups** section.
+1. Select the desired email address.
+
+### Notification levels
+
+For each project and group you can select one of the following levels:
+
+| Level | Description |
+|:------------|:------------|
+| Global | Your global settings apply. |
+| Watch | Receive notifications for any activity. |
+| On mention | Receive notifications when `@mentioned` in comments. |
+| Participate | Receive notifications for threads you have participated in. |
+| Disabled | Turns off notifications. |
+| Custom | Receive notifications for custom selected events. |
+
+## Notification events
+
+Users will be notified of the following events:
+
+| Event | Sent to | Settings level |
+|------------------------------|---------------------|------------------------------|
+| New SSH key added | User | Security email, always sent. |
+| New email added | User | Security email, always sent. |
+| Email changed | User | Security email, always sent. |
+| Password changed | User | Security email, always sent. |
+| New user created | User | Sent on user creation, except for OmniAuth (LDAP)|
+| User added to project | User | Sent when user is added to project |
+| Project access level changed | User | Sent when user project access level is changed |
+| User added to group | User | Sent when user is added to group |
+| Group access level changed | User | Sent when user group access level is changed |
+| Project moved | Project members (1) | (1) not disabled |
+| New release | Project members | Custom notification |
+
+## Issue / Epics / Merge request events
+
+In most of the below cases, the notification will be sent to:
+
+- Participants:
+ - the author and assignee of the issue/merge request
+ - authors of comments on the issue/merge request
+ - anyone mentioned by `@username` in the title or description of the issue, merge request or epic **(ULTIMATE)**
+ - anyone with notification level "Participating" or higher that is mentioned by `@username` in any of the comments on the issue, merge request, or epic **(ULTIMATE)**
+- Watchers: users with notification level "Watch"
+- Subscribers: anyone who manually subscribed to the issue, merge request, or epic **(ULTIMATE)**
+- Custom: Users with notification level "custom" who turned on notifications for any of the events present in the table below
+
+| Event | Sent to |
+|------------------------|---------|
+| New issue | |
+| Close issue | |
+| Reassign issue | The above, plus the old assignee |
+| Reopen issue | |
+| Due issue | Participants and Custom notification level with this event selected |
+| Change milestone issue | Subscribers, participants mentioned, and Custom notification level with this event selected |
+| Remove milestone issue | Subscribers, participants mentioned, and Custom notification level with this event selected |
+| New merge request | |
+| Push to merge request | Participants and Custom notification level with this event selected |
+| Reassign merge request | The above, plus the old assignee |
+| Close merge request | |
+| Reopen merge request | |
+| Merge merge request | |
+| Change milestone merge request | Subscribers, participants mentioned, and Custom notification level with this event selected |
+| Remove milestone merge request | Subscribers, participants mentioned, and Custom notification level with this event selected |
+| New comment | The above, plus anyone mentioned by `@username` in the comment, with notification level "Mention" or higher |
+| Failed pipeline | The author of the pipeline |
+| Successful pipeline | The author of the pipeline, if they have the custom notification setting for successful pipelines set |
+| New epic **(ULTIMATE)** | |
+| Close epic **(ULTIMATE)** | |
+| Reopen epic **(ULTIMATE)** | |
+
+In addition, if the title or description of an Issue or Merge Request is
+changed, notifications will be sent to any **new** mentions by `@username` as
+if they had been mentioned in the original text.
+
+You won't receive notifications for Issues, Merge Requests or Milestones created
+by yourself (except when an issue is due). You will only receive automatic
+notifications when somebody else comments or adds changes to the ones that
+you've created or mentions you.
+
+If an open merge request becomes unmergeable due to conflict, its author will be notified about the cause.
+If a user has also set the merge request to automatically merge once pipeline succeeds,
+then that user will also be notified.
+
+## Email Headers
+
+Notification emails include headers that provide extra content about the notification received:
+
+| Header | Description |
+|-----------------------------|-------------------------------------------------------------------------|
+| X-GitLab-Project | The name of the project the notification belongs to |
+| X-GitLab-Project-Id | The ID of the project |
+| X-GitLab-Project-Path | The path of the project |
+| X-GitLab-(Resource)-ID | The ID of the resource the notification is for, where resource is `Issue`, `MergeRequest`, `Commit`, etc|
+| X-GitLab-Discussion-ID | Only in comment emails, the ID of the thread the comment is from |
+| X-GitLab-Pipeline-Id | Only in pipeline emails, the ID of the pipeline the notification is for |
+| X-GitLab-Reply-Key | A unique token to support reply by email |
+| X-GitLab-NotificationReason | The reason for being notified. "mentioned", "assigned", etc |
+| List-Id | The path of the project in a RFC 2919 mailing list identifier useful for email organization, for example, with Gmail filters |
+
+### X-GitLab-NotificationReason
+
+This header holds the reason for the notification to have been sent out,
+where reason can be `mentioned`, `assigned`, `own_activity`, etc.
+Only one reason is sent out according to its priority:
+
+- `own_activity`
+- `assigned`
+- `mentioned`
+
+The reason in this header will also be shown in the footer of the notification email. For example an email with the
+reason `assigned` will have this sentence in the footer:
+`"You are receiving this email because you have been assigned an item on {configured GitLab hostname}"`
+
+NOTE: **Note:**
+Only reasons listed above have been implemented so far.
+Further implementation is [being discussed](https://gitlab.com/gitlab-org/gitlab/issues/20689).
diff --git a/doc/user/profile/preferences.md b/doc/user/profile/preferences.md
index 82a6d2b3703..b299c74c8f4 100644
--- a/doc/user/profile/preferences.md
+++ b/doc/user/profile/preferences.md
@@ -82,7 +82,7 @@ You have 8 options here that you can use for your default dashboard view:
- Your projects' activity
- Starred projects' activity
- Your groups
-- Your [Todos](../../workflow/todos.md)
+- Your [Todos](../todos.md)
- Assigned Issues
- Assigned Merge Requests
- Operations Dashboard **(PREMIUM)**
@@ -128,6 +128,19 @@ You can choose one of the following options as the first day of the week:
If you select **System Default**, the system-wide default setting will be used.
+## Integrations
+
+Configure your preferences with third-party services which provide enhancements to your GitLab experience.
+
+### Sourcegraph
+
+NOTE: **Note:**
+This setting is only visible if Sourcegraph has been enabled by a GitLab administrator.
+
+Manage the availability of integrated code intelligence features powered by
+Sourcegraph. View [the Sourcegraph feature documentation](../../integration/sourcegraph.md#enable-sourcegraph-in-user-preferences)
+for more information.
+
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
diff --git a/doc/user/project/clusters/add_remove_clusters.md b/doc/user/project/clusters/add_remove_clusters.md
new file mode 100644
index 00000000000..150a451dfe5
--- /dev/null
+++ b/doc/user/project/clusters/add_remove_clusters.md
@@ -0,0 +1,730 @@
+# Adding and removing Kubernetes clusters
+
+GitLab can integrate with the following Kubernetes providers:
+
+- Google Kubernetes Engine (GKE).
+- Amazon Elastic Kubernetes Service (EKS).
+
+TIP: **Tip:**
+Every new Google Cloud Platform (GCP) account receives [$300 in credit upon sign up](https://console.cloud.google.com/freetrial),
+and in partnership with Google, GitLab is able to offer an additional $200 for new GCP accounts to get started with GitLab's
+Google Kubernetes Engine Integration. All you have to do is [follow this link](https://cloud.google.com/partners/partnercredit/?pcn_code=0014M00001h35gDQAQ#contact-form) and apply for credit.
+
+## Access controls
+
+When creating a cluster in GitLab, you will be asked if you would like to create either:
+
+- A [Role-based access control (RBAC)](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) cluster.
+- An [Attribute-based access control (ABAC)](https://kubernetes.io/docs/reference/access-authn-authz/abac/) cluster.
+
+NOTE: **Note:**
+[RBAC](#rbac-cluster-resources) is recommended and the GitLab default.
+
+GitLab creates the necessary service accounts and privileges to install and run
+[GitLab managed applications](index.md#installing-applications). When GitLab creates the cluster,
+a `gitlab` service account with `cluster-admin` privileges is created in the `default` namespace
+to manage the newly created cluster.
+
+NOTE: **Note:**
+Restricted service account for deployment was [introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/51716) in GitLab 11.5.
+
+When you install Helm into your cluster, the `tiller` service account
+is created with `cluster-admin` privileges in the `gitlab-managed-apps`
+namespace.
+
+This service account will be:
+
+- Added to the installed Helm Tiller
+- Used by Helm to install and run [GitLab managed applications](index.md#installing-applications).
+
+Helm will also create additional service accounts and other resources for each
+installed application. Consult the documentation of the Helm charts for each application
+for details.
+
+If you are [adding an existing Kubernetes cluster](add_remove_clusters.md#add-existing-cluster),
+ensure the token of the account has administrator privileges for the cluster.
+
+The resources created by GitLab differ depending on the type of cluster.
+
+### Important notes
+
+Note the following about access controls:
+
+- Environment-specific resources are only created if your cluster is
+ [managed by GitLab](index.md#gitlab-managed-clusters).
+- If your cluster was created before GitLab 12.2, it will use a single namespace for all project
+ environments.
+
+### RBAC cluster resources
+
+GitLab creates the following resources for RBAC clusters.
+
+| Name | Type | Details | Created when |
+|:----------------------|:---------------------|:-----------------------------------------------------------------------------------------------------------|:-----------------------|
+| `gitlab` | `ServiceAccount` | `default` namespace | Creating a new cluster |
+| `gitlab-admin` | `ClusterRoleBinding` | [`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) roleRef | Creating a new cluster |
+| `gitlab-token` | `Secret` | Token for `gitlab` ServiceAccount | Creating a new cluster |
+| `tiller` | `ServiceAccount` | `gitlab-managed-apps` namespace | Installing Helm Tiller |
+| `tiller-admin` | `ClusterRoleBinding` | `cluster-admin` roleRef | Installing Helm Tiller |
+| Environment namespace | `Namespace` | Contains all environment-specific resources | Deploying to a cluster |
+| Environment namespace | `ServiceAccount` | Uses namespace of environment | Deploying to a cluster |
+| Environment namespace | `Secret` | Token for environment ServiceAccount | Deploying to a cluster |
+| Environment namespace | `RoleBinding` | [`edit`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) roleRef | Deploying to a cluster |
+
+### ABAC cluster resources
+
+GitLab creates the following resources for ABAC clusters.
+
+| Name | Type | Details | Created when |
+|:----------------------|:---------------------|:-------------------------------------|:---------------------------|
+| `gitlab` | `ServiceAccount` | `default` namespace | Creating a new cluster |
+| `gitlab-token` | `Secret` | Token for `gitlab` ServiceAccount | Creating a new cluster |
+| `tiller` | `ServiceAccount` | `gitlab-managed-apps` namespace | Installing Helm Tiller |
+| `tiller-admin` | `ClusterRoleBinding` | `cluster-admin` roleRef | Installing Helm Tiller |
+| Environment namespace | `Namespace` | Contains all environment-specific resources | Deploying to a cluster |
+| Environment namespace | `ServiceAccount` | Uses namespace of environment | Deploying to a cluster |
+| Environment namespace | `Secret` | Token for environment ServiceAccount | Deploying to a cluster |
+
+### Security of GitLab Runners
+
+GitLab Runners have the [privileged mode](https://docs.gitlab.com/runner/executors/docker.html#the-privileged-mode)
+enabled by default, which allows them to execute special commands and running
+Docker in Docker. This functionality is needed to run some of the
+[Auto DevOps](../../../topics/autodevops/index.md)
+jobs. This implies the containers are running in privileged mode and you should,
+therefore, be aware of some important details.
+
+The privileged flag gives all capabilities to the running container, which in
+turn can do almost everything that the host can do. Be aware of the
+inherent security risk associated with performing `docker run` operations on
+arbitrary images as they effectively have root access.
+
+If you don't want to use GitLab Runner in privileged mode, either:
+
+- Use shared Runners on GitLab.com. They don't have this security issue.
+- Set up your own Runners using configuration described at
+ [Shared Runners](../../gitlab_com/index.md#shared-runners). This involves:
+ 1. Making sure that you don't have it installed via
+ [the applications](index.md#installing-applications).
+ 1. Installing a Runner
+ [using `docker+machine`](https://docs.gitlab.com/runner/executors/docker_machine.html).
+
+## Add new cluster
+
+### GKE cluster
+
+GitLab supports:
+
+- Creating a new GKE cluster using the GitLab UI.
+- Providing credentials to add an [existing Kubernetes cluster](#add-existing-cluster).
+
+Starting from [GitLab 12.4](https://gitlab.com/gitlab-org/gitlab/issues/25925), all the GKE clusters provisioned by GitLab are [VPC-native](https://cloud.google.com/kubernetes-engine/docs/how-to/alias-ips).
+
+NOTE: **Note:**
+The [Google authentication integration](../../../integration/google.md) must
+be enabled in GitLab at the instance level. If that's not the case, ask your
+GitLab administrator to enable it. On GitLab.com, this is enabled.
+
+#### GKE Requirements
+
+Before creating your first cluster on Google Kubernetes Engine with GitLab's
+integration, make sure the following requirements are met:
+
+- A [billing account](https://cloud.google.com/billing/docs/how-to/manage-billing-account)
+ is set up and you have permissions to access it.
+- The Kubernetes Engine API and related service are enabled. It should work immediately but may take up to 10 minutes after you create a project. For more information see the
+ ["Before you begin" section of the Kubernetes Engine docs](https://cloud.google.com/kubernetes-engine/docs/quickstart#before-you-begin).
+
+Also note the following:
+
+- Starting from [GitLab 12.1](https://gitlab.com/gitlab-org/gitlab-foss/issues/55902), all GKE clusters
+ created by GitLab are RBAC-enabled. Take a look at the [RBAC section](#rbac-cluster-resources) for
+ more information.
+- Starting from [GitLab 12.5](https://gitlab.com/gitlab-org/gitlab/merge_requests/18341), the
+ cluster's pod address IP range will be set to /16 instead of the regular /14. /16 is a CIDR
+ notation.
+
+NOTE: **Note:**
+GitLab requires basic authentication enabled and a client certificate issued for the cluster in
+order to setup an [initial service account](#access-controls). Starting from [GitLab
+11.10](https://gitlab.com/gitlab-org/gitlab-foss/issues/58208), the cluster creation process will
+explicitly request that basic authentication and client certificate is enabled.
+
+#### Creating the cluster on GKE
+
+If all of the above requirements are met, you can proceed to create and add a
+new Kubernetes cluster to your project:
+
+1. Navigate to your project's **Operations > Kubernetes** page.
+
+ NOTE: **Note:**
+ You need Maintainer [permissions](../../permissions.md) and above to access the Kubernetes page.
+
+1. Click **Add Kubernetes cluster**.
+1. Click **Create with Google Kubernetes Engine**.
+1. Connect your Google account if you haven't done already by clicking the
+ **Sign in with Google** button.
+1. Choose your cluster's settings:
+ - **Kubernetes cluster name** - The name you wish to give the cluster.
+ - **Environment scope** - The [associated environment](index.md#setting-the-environment-scope-premium) to this cluster.
+ - **Google Cloud Platform project** - Choose the project you created in your GCP
+ console that will host the Kubernetes cluster. Learn more about
+ [Google Cloud Platform projects](https://cloud.google.com/resource-manager/docs/creating-managing-projects).
+ - **Zone** - Choose the [region zone](https://cloud.google.com/compute/docs/regions-zones/)
+ under which the cluster will be created.
+ - **Number of nodes** - Enter the number of nodes you wish the cluster to have.
+ - **Machine type** - The [machine type](https://cloud.google.com/compute/docs/machine-types)
+ of the Virtual Machine instance that the cluster will be based on.
+ - **Enable Cloud Run on GKE (beta)** - Check this if you want to use Cloud Run on GKE for this cluster.
+ See the [Cloud Run on GKE section](#cloud-run-on-gke) for more information.
+ - **GitLab-managed cluster** - Leave this checked if you want GitLab to manage namespaces and service accounts for this cluster.
+ See the [Managed clusters section](index.md#gitlab-managed-clusters) for more information.
+1. Finally, click the **Create Kubernetes cluster** button.
+
+After a couple of minutes, your cluster will be ready to go. You can now proceed
+to install some [pre-defined applications](index.md#installing-applications).
+
+#### Cloud Run on GKE
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/16566) in GitLab 12.4.
+
+You can choose to use Cloud Run on GKE in place of installing Knative and Istio
+separately after the cluster has been created. This means that Cloud Run
+(Knative), Istio, and HTTP Load Balancing will be enabled on the cluster at
+create time and cannot be [installed or uninstalled](../../clusters/applications.md) separately.
+
+### EKS Cluster
+
+GitLab supports:
+
+- Creating a new EKS cluster using the GitLab UI
+ ([Introduced](https://gitlab.com/gitlab-org/gitlab/issues/22392) in GitLab 12.5).
+- Providing credentials to add an [existing Kubernetes cluster](#add-existing-cluster).
+
+#### EKS Requirements
+
+Before creating your first cluster on Amazon EKS with GitLab's integration,
+make sure the following requirements are met:
+
+- An [Amazon Web Services](https://aws.amazon.com/) account is set up and you are able to log in.
+- You have permissions to manage IAM resources.
+
+##### Additional requirements for self-managed instances
+
+If you are using a self-managed GitLab instance, GitLab must first
+be configured with a set of Amazon credentials. These credentials
+will be used to assume an Amazon IAM role provided by the user
+creating the cluster. Create an IAM user and ensure it has permissions
+to assume the role(s) that your users will use to create EKS clusters.
+
+For example, the following policy document allows assuming a role whose name starts with
+`gitlab-eks-` in account `123456789012`:
+
+```json
+{
+ "Version": "2012-10-17",
+ "Statement": {
+ "Effect": "Allow",
+ "Action": "sts:AssumeRole",
+ "Resource": "arn:aws:iam::123456789012:role/gitlab-eks-*"
+ }
+}
+```
+
+Generate an access key for the IAM user, and configure GitLab with the credentials:
+
+1. Navigate to **Admin Area > Settings > Integrations** and expand the **Amazon EKS** section.
+1. Check **Enable Amazon EKS integration**.
+1. Enter the account ID and access key credentials into the respective
+ `Account ID`, `Access key ID` and `Secret access key` fields.
+1. Click **Save changes**.
+
+#### Creating the cluster on EKS
+
+If all of the above requirements are met, you can proceed to create and add a
+new Kubernetes cluster to your project:
+
+1. Navigate to your project's **Operations > Kubernetes** page.
+
+ NOTE: **Note:**
+ You need Maintainer [permissions](../../permissions.md) and above to access the Kubernetes page.
+
+1. Click **Add Kubernetes cluster**.
+1. Click **Amazon EKS**. You will be provided with an `Account ID` and `External ID` to use in the next step.
+1. In the [IAM Management Console](https://console.aws.amazon.com/iam/home), create an IAM role:
+ 1. From the left panel, select **Roles**.
+ 1. Click **Create role**.
+ 1. Under `Select type of trusted entity`, select **Another AWS account**.
+ 1. Enter the Account ID from GitLab into the `Account ID` field.
+ 1. Check **Require external ID**.
+ 1. Enter the External ID from GitLab into the `External ID` field.
+ 1. Click **Next: Permissions**.
+ 1. Click **Create Policy**, which will open a new window.
+ 1. Select the **JSON** tab, and paste in the following snippet in place of the existing content:
+
+ ```json
+ {
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Action": [
+ "autoscaling:CreateAutoScalingGroup",
+ "autoscaling:DescribeAutoScalingGroups",
+ "autoscaling:DescribeScalingActivities",
+ "autoscaling:UpdateAutoScalingGroup",
+ "autoscaling:CreateLaunchConfiguration",
+ "autoscaling:DescribeLaunchConfigurations",
+ "cloudformation:CreateStack",
+ "cloudformation:DescribeStacks",
+ "ec2:AuthorizeSecurityGroupEgress",
+ "ec2:AuthorizeSecurityGroupIngress",
+ "ec2:RevokeSecurityGroupEgress",
+ "ec2:RevokeSecurityGroupIngress",
+ "ec2:CreateSecurityGroup",
+ "ec2:createTags",
+ "ec2:DescribeImages",
+ "ec2:DescribeKeyPairs",
+ "ec2:DescribeRegions",
+ "ec2:DescribeSecurityGroups",
+ "ec2:DescribeSubnets",
+ "ec2:DescribeVpcs",
+ "eks:CreateCluster",
+ "eks:DescribeCluster",
+ "iam:AddRoleToInstanceProfile",
+ "iam:AttachRolePolicy",
+ "iam:CreateRole",
+ "iam:CreateInstanceProfile",
+ "iam:GetRole",
+ "iam:ListRoles",
+ "iam:PassRole",
+ "ssm:GetParameters"
+ ],
+ "Resource": "*"
+ }
+ ]
+ }
+ ```
+
+ NOTE: **Note:**
+ These permissions give GitLab the ability to create resources, but not delete them.
+ This means that if an error is encountered during the creation process, changes will
+ not be rolled back and you must remove resources manually. You can do this by deleting
+ the relevant [CloudFormation stack](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-console-delete-stack.html)
+
+ 1. Click **Review policy**.
+ 1. Enter a suitable name for this policy, and click **Create Policy**. You can now close this window.
+ 1. Switch back to the "Create role" window, and select the policy you just created.
+ 1. Click **Next: Tags**, and optionally enter any tags you wish to associate with this role.
+ 1. Click **Next: Review**.
+ 1. Enter a role name and optional description into the fields provided.
+ 1. Click **Create role**, the new role name will appear at the top. Click on its name and copy the `Role ARN` from the newly created role.
+1. In GitLab, enter the copied role ARN into the `Role ARN` field.
+1. Click **Authenticate with AWS**.
+1. Choose your cluster's settings:
+ - **Kubernetes cluster name** - The name you wish to give the cluster.
+ - **Environment scope** - The [associated environment](index.md#setting-the-environment-scope-premium) to this cluster.
+ - **Kubernetes version** - The Kubernetes version to use. Currently the only version supported is 1.14.
+ - **Role name** - Select the [IAM role](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html)
+ to allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf.
+ - **Region** - The [region](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html)
+ in which the cluster will be created.
+ - **Key pair name** - Select the [key pair](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html)
+ that you can use to connect to your worker nodes if required.
+ - **VPC** - Select a [VPC](https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html)
+ to use for your EKS Cluster resources.
+ - **Subnets** - Choose the [subnets](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Subnets.html)
+ in your VPC where your worker nodes will run.
+ - **Security group** - Choose the [security group](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html)
+ to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets.
+ - **Instance type** - The [instance type](https://aws.amazon.com/ec2/instance-types/) of your worker nodes.
+ - **Node count** - The number of worker nodes.
+ - **GitLab-managed cluster** - Leave this checked if you want GitLab to manage namespaces and service accounts for this cluster.
+ See the [Managed clusters section](index.md#gitlab-managed-clusters) for more information.
+1. Finally, click the **Create Kubernetes cluster** button.
+
+After about 10 minutes, your cluster will be ready to go. You can now proceed
+to install some [pre-defined applications](index.md#installing-applications).
+
+## Add existing cluster
+
+If you have either of the following types of clusters already, you can add them to a project:
+
+- [Google Kubernetes Engine cluster](#add-existing-gke-cluster).
+- [Amazon Elastic Kubernetes Service](#add-existing-eks-cluster).
+
+NOTE: **Note:**
+Kubernetes integration is not supported for arm64 clusters. See the issue
+[Helm Tiller fails to install on arm64 cluster](https://gitlab.com/gitlab-org/gitlab-foss/issues/64044) for details.
+
+### Add existing GKE cluster
+
+To add an existing Kubernetes cluster to your project:
+
+1. Navigate to your project's **Operations > Kubernetes** page.
+
+ NOTE: **Note:**
+ You need Maintainer [permissions](../../permissions.md) and above to access the Kubernetes page.
+
+1. Click **Add Kubernetes cluster**.
+1. Click **Add an existing Kubernetes cluster** and fill in the details:
+ - **Kubernetes cluster name** (required) - The name you wish to give the cluster.
+ - **Environment scope** (required) - The
+ [associated environment](index.md#setting-the-environment-scope-premium) to this cluster.
+ - **API URL** (required) -
+ It's the URL that GitLab uses to access the Kubernetes API. Kubernetes
+ exposes several APIs, we want the "base" URL that is common to all of them,
+ e.g., `https://kubernetes.example.com` rather than `https://kubernetes.example.com/api/v1`.
+
+ Get the API URL by running this command:
+
+ ```sh
+ kubectl cluster-info | grep 'Kubernetes master' | awk '/http/ {print $NF}'
+ ```
+
+ - **CA certificate** (required) - A valid Kubernetes certificate is needed to authenticate to the cluster. We will use the certificate created by default.
+ - List the secrets with `kubectl get secrets`, and one should named similar to
+ `default-token-xxxxx`. Copy that token name for use below.
+ - Get the certificate by running this command:
+
+ ```sh
+
+ kubectl get secret <secret name> -o jsonpath="{['data']['ca\.crt']}" | base64 --decode
+
+ ```
+
+ NOTE: **Note:**
+ If the command returns the entire certificate chain, you need copy the *root ca*
+ certificate at the bottom of the chain.
+
+ - **Token** -
+ GitLab authenticates against Kubernetes using service tokens, which are
+ scoped to a particular `namespace`.
+ **The token used should belong to a service account with
+ [`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles)
+ privileges.** To create this service account:
+
+ 1. Create a file called `gitlab-admin-service-account.yaml` with contents:
+
+ ```yaml
+ apiVersion: v1
+ kind: ServiceAccount
+ metadata:
+ name: gitlab-admin
+ namespace: kube-system
+ ---
+ apiVersion: rbac.authorization.k8s.io/v1beta1
+ kind: ClusterRoleBinding
+ metadata:
+ name: gitlab-admin
+ roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: cluster-admin
+ subjects:
+ - kind: ServiceAccount
+ name: gitlab-admin
+ namespace: kube-system
+ ```
+
+ 1. Apply the service account and cluster role binding to your cluster:
+
+ ```bash
+ kubectl apply -f gitlab-admin-service-account.yaml
+ ```
+
+ You will need the `container.clusterRoleBindings.create` permission
+ to create cluster-level roles. If you do not have this permission,
+ you can alternatively enable Basic Authentication and then run the
+ `kubectl apply` command as an admin:
+
+ ```bash
+ kubectl apply -f gitlab-admin-service-account.yaml --username=admin --password=<password>
+ ```
+
+ NOTE: **Note:**
+ Basic Authentication can be turned on and the password credentials
+ can be obtained using the Google Cloud Console.
+
+ Output:
+
+ ```bash
+ serviceaccount "gitlab-admin" created
+ clusterrolebinding "gitlab-admin" created
+ ```
+
+ 1. Retrieve the token for the `gitlab-admin` service account:
+
+ ```bash
+ kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep gitlab-admin | awk '{print $1}')
+ ```
+
+ Copy the `<authentication_token>` value from the output:
+
+ ```yaml
+ Name: gitlab-admin-token-b5zv4
+ Namespace: kube-system
+ Labels: <none>
+ Annotations: kubernetes.io/service-account.name=gitlab-admin
+ kubernetes.io/service-account.uid=bcfe66ac-39be-11e8-97e8-026dce96b6e8
+
+ Type: kubernetes.io/service-account-token
+
+ Data
+ ====
+ ca.crt: 1025 bytes
+ namespace: 11 bytes
+ token: <authentication_token>
+ ```
+
+ NOTE: **Note:**
+ For GKE clusters, you will need the
+ `container.clusterRoleBindings.create` permission to create a cluster
+ role binding. You can follow the [Google Cloud
+ documentation](https://cloud.google.com/iam/docs/granting-changing-revoking-access)
+ to grant access.
+
+ - **GitLab-managed cluster** - Leave this checked if you want GitLab to manage namespaces and service accounts for this cluster.
+ See the [Managed clusters section](index.md#gitlab-managed-clusters) for more information.
+
+ - **Project namespace** (optional) - You don't have to fill it in; by leaving
+ it blank, GitLab will create one for you. Also:
+ - Each project should have a unique namespace.
+ - The project namespace is not necessarily the namespace of the secret, if
+ you're using a secret with broader permissions, like the secret from `default`.
+ - You should **not** use `default` as the project namespace.
+ - If you or someone created a secret specifically for the project, usually
+ with limited permissions, the secret's namespace and project namespace may
+ be the same.
+
+1. Finally, click the **Create Kubernetes cluster** button.
+
+After a couple of minutes, your cluster will be ready to go. You can now proceed
+to install some [pre-defined applications](index.md#installing-applications).
+
+### Add existing EKS cluster
+
+In this section, we will show how to integrate an [Amazon EKS](https://aws.amazon.com/eks/) cluster with GitLab and begin
+deploying applications.
+
+#### Requirements
+
+To integrate with with EKS, you will need:
+
+- An account on GitLab, like [GitLab.com](https://gitlab.com).
+- An Amazon EKS cluster (with worker nodes properly configured).
+- `kubectl` [installed and configured for access to the EKS cluster](https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html#get-started-kubectl).
+
+If you don't have an Amazon EKS cluster, one can be created by following the
+[EKS getting started guide](https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html).
+
+#### Configuring and connecting the EKS cluster
+
+From the left side bar, hover over **Operations > Kubernetes > Add Kubernetes cluster**,
+then click **Add an existing Kubernetes cluster**.
+
+A few details from the EKS cluster will be required to connect it to GitLab:
+
+1. **Retrieve the certificate**: A valid Kubernetes certificate is needed to
+ authenticate to the EKS cluster. We will use the certificate created by default.
+ Open a shell and use `kubectl` to retrieve it:
+
+ - List the secrets with `kubectl get secrets`, and one should named similar to
+ `default-token-xxxxx`. Copy that token name for use below.
+ - Get the certificate with:
+
+ ```sh
+ kubectl get secret <secret name> -o jsonpath="{['data']['ca\.crt']}" | base64 --decode
+ ```
+
+1. **Create admin token**: A `cluster-admin` token is required to install and
+ manage Helm Tiller. GitLab establishes mutual SSL auth with Helm Tiller
+ and creates limited service accounts for each application. To create the
+ token we will create an admin service account as follows:
+
+ 1. Create a file called `eks-admin-service-account.yaml` with contents:
+
+ ```yaml
+ apiVersion: v1
+ kind: ServiceAccount
+ metadata:
+ name: eks-admin
+ namespace: kube-system
+ ```
+
+ 1. Apply the service account to your cluster:
+
+ ```bash
+ kubectl apply -f eks-admin-service-account.yaml
+ ```
+
+ Output:
+
+ ```bash
+ serviceaccount "eks-admin" created
+ ```
+
+ 1. Create a file called `eks-admin-cluster-role-binding.yaml` with contents:
+
+ ```yaml
+ apiVersion: rbac.authorization.k8s.io/v1beta1
+ kind: ClusterRoleBinding
+ metadata:
+ name: eks-admin
+ roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: cluster-admin
+ subjects:
+ - kind: ServiceAccount
+ name: eks-admin
+ namespace: kube-system
+ ```
+
+ 1. Apply the cluster role binding to your cluster:
+
+ ```bash
+ kubectl apply -f eks-admin-cluster-role-binding.yaml
+ ```
+
+ Output:
+
+ ```bash
+ clusterrolebinding "eks-admin" created
+ ```
+
+ 1. Retrieve the token for the `eks-admin` service account:
+
+ ```bash
+ kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep eks-admin | awk '{print $1}')
+ ```
+
+ Copy the `<authentication_token>` value from the output:
+
+ ```yaml
+ Name: eks-admin-token-b5zv4
+ Namespace: kube-system
+ Labels: <none>
+ Annotations: kubernetes.io/service-account.name=eks-admin
+ kubernetes.io/service-account.uid=bcfe66ac-39be-11e8-97e8-026dce96b6e8
+
+ Type: kubernetes.io/service-account-token
+
+ Data
+ ====
+ ca.crt: 1025 bytes
+ namespace: 11 bytes
+ token: <authentication_token>
+ ```
+
+1. The API server endpoint is also required, so GitLab can connect to the cluster.
+ This is displayed on the AWS EKS console, when viewing the EKS cluster details.
+
+You now have all the information needed to connect the EKS cluster:
+
+- Kubernetes cluster name: Provide a name for the cluster to identify it within GitLab.
+- Environment scope: Leave this as `*` for now, since we are only connecting a single cluster.
+- API URL: Paste in the API server endpoint retrieved above.
+- CA Certificate: Paste the certificate data from the earlier step, as-is.
+- Paste the admin token value.
+- Project namespace: This can be left blank to accept the default namespace, based on the project name.
+
+![Add Cluster](img/add_cluster.png)
+
+Click on **Add Kubernetes cluster**, the cluster is now connected to GitLab.
+At this point, [Kubernetes deployment variables](index.md#deployment-variables) will
+automatically be available during CI/CD jobs, making it easy to interact with the cluster.
+
+If you would like to utilize your own CI/CD scripts to deploy to the cluster, you can stop here.
+
+#### Disable Role-Based Access Control (RBAC) (optional)
+
+When connecting a cluster via GitLab integration, you may specify whether the
+cluster is RBAC-enabled or not. This will affect how GitLab interacts with the
+cluster for certain operations. If you **did not** check the "RBAC-enabled cluster"
+checkbox at creation time, GitLab will assume RBAC is disabled for your cluster
+when interacting with it. If so, you must disable RBAC on your cluster for the
+integration to work properly.
+
+![rbac](img/rbac.png)
+
+NOTE: **Note**: Disabling RBAC means that any application running in the cluster,
+or user who can authenticate to the cluster, has full API access. This is a
+[security concern](index.md#security-implications), and may not be desirable.
+
+To effectively disable RBAC, global permissions can be applied granting full access:
+
+```bash
+kubectl create clusterrolebinding permissive-binding \
+ --clusterrole=cluster-admin \
+ --user=admin \
+ --user=kubelet \
+ --group=system:serviceaccounts
+```
+
+#### Create a default Storage Class
+
+Amazon EKS doesn't have a default Storage Class out of the box, which means
+requests for persistent volumes will not be automatically fulfilled. As part
+of Auto DevOps, the deployed Postgres instance requests persistent storage,
+and without a default storage class it will fail to start.
+
+If a default Storage Class doesn't already exist and is desired, follow Amazon's
+[guide on storage classes](https://docs.aws.amazon.com/eks/latest/userguide/storage-classes.html)
+to create one.
+
+Alternatively, disable Postgres by setting the project variable
+[`POSTGRES_ENABLED`](../../../topics/autodevops/#environment-variables) to `false`.
+
+#### Deploy the app to EKS
+
+With RBAC disabled and services deployed,
+[Auto DevOps](../../../topics/autodevops/index.md) can now be leveraged
+to build, test, and deploy the app.
+
+[Enable Auto DevOps](../../../topics/autodevops/index.md#at-the-project-level)
+if not already enabled. If a wildcard DNS entry was created resolving to the
+Load Balancer, enter it in the `domain` field under the Auto DevOps settings.
+Otherwise, the deployed app will not be externally available outside of the cluster.
+
+![Deploy Pipeline](img/pipeline.png)
+
+A new pipeline will automatically be created, which will begin to build, test,
+and deploy the app.
+
+After the pipeline has finished, your app will be running in EKS and available
+to users. Click on **CI/CD > Environments**.
+
+![Deployed Environment](img/environment.png)
+
+You will see a list of the environments and their deploy status, as well as
+options to browse to the app, view monitoring metrics, and even access a shell
+on the running pod.
+
+## Enabling or disabling integration
+
+After you have successfully added your cluster information, you can enable the
+Kubernetes cluster integration:
+
+1. Click the **Enabled/Disabled** switch
+1. Hit **Save** for the changes to take effect
+
+To disable the Kubernetes cluster integration, follow the same procedure.
+
+## Removing integration
+
+To remove the Kubernetes cluster integration from your project, simply click the
+**Remove integration** button. You will then be able to follow the procedure
+and add a Kubernetes cluster again.
+
+When removing the cluster integration, note:
+
+- You need Maintainer [permissions](../../permissions.md) and above to remove a Kubernetes cluster
+ integration.
+- When you remove a cluster, you only remove its relationship to GitLab, not the cluster itself. To
+ remove the cluster, you can do so by visiting the GKE dashboard or using `kubectl`.
+
+## Learn more
+
+To learn more on automatically deploying your applications,
+read about [Auto DevOps](../../../topics/autodevops/index.md).
diff --git a/doc/user/project/clusters/eks_and_gitlab/img/create_dns.png b/doc/user/project/clusters/eks_and_gitlab/img/create_dns.png
deleted file mode 100644
index 61ed85e5cd9..00000000000
--- a/doc/user/project/clusters/eks_and_gitlab/img/create_dns.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/clusters/eks_and_gitlab/img/create_project.png b/doc/user/project/clusters/eks_and_gitlab/img/create_project.png
deleted file mode 100644
index b02ab4b9064..00000000000
--- a/doc/user/project/clusters/eks_and_gitlab/img/create_project.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/clusters/eks_and_gitlab/img/deploy_apps.png b/doc/user/project/clusters/eks_and_gitlab/img/deploy_apps.png
deleted file mode 100644
index 0d9fcc838d9..00000000000
--- a/doc/user/project/clusters/eks_and_gitlab/img/deploy_apps.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/clusters/eks_and_gitlab/index.md b/doc/user/project/clusters/eks_and_gitlab/index.md
index 22576b84926..fda8cd6340e 100644
--- a/doc/user/project/clusters/eks_and_gitlab/index.md
+++ b/doc/user/project/clusters/eks_and_gitlab/index.md
@@ -1,278 +1,5 @@
-# Connecting and deploying to an Amazon EKS cluster
+---
+redirect_to: '../add_remove_clusters.md#add-existing-eks-cluster'
+---
-In this tutorial, we will show how to integrate an
-[Amazon EKS](https://aws.amazon.com/eks/) cluster with GitLab and begin
-deploying applications.
-
-## Introduction
-
-For an end-to-end walkthrough we will:
-
-1. Start with a new project based on the sample Ruby on Rails template.
-1. Integrate an EKS cluster.
-1. Utilize [Auto DevOps](../../../../topics/autodevops/) to build, test, and deploy our application.
-
-You will need:
-
-1. An account on GitLab, like [GitLab.com](https://gitlab.com).
-1. An Amazon EKS cluster (with worker nodes properly configured).
-1. `kubectl` [installed and configured for access to the EKS cluster](https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html#get-started-kubectl).
-
-If you don't have an Amazon EKS cluster, one can be created by following the
-[EKS getting started guide](https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html).
-
-## Creating a new project
-
-On GitLab, create a new project by clicking on the `+` icon in the top navigation
-bar and selecting **New project**.
-
-On the new project screen, click on the **Create from template** tab, and select
-"Use template" for the Ruby on Rails sample project.
-
-Give the project a name, and then select **Create project**.
-
-![Create Project](img/create_project.png)
-
-## Configuring and connecting the EKS cluster
-
-From the left side bar, hover over **Operations > Kubernetes > Add Kubernetes cluster**,
-then click **Add an existing Kubernetes cluster**.
-
-A few details from the EKS cluster will be required to connect it to GitLab:
-
-1. **Retrieve the certificate**: A valid Kubernetes certificate is needed to
- authenticate to the EKS cluster. We will use the certificate created by default.
- Open a shell and use `kubectl` to retrieve it:
-
- - List the secrets with `kubectl get secrets`, and one should named similar to
- `default-token-xxxxx`. Copy that token name for use below.
- - Get the certificate with:
-
- ```sh
- kubectl get secret <secret name> -o jsonpath="{['data']['ca\.crt']}" | base64 --decode
- ```
-
-1. **Create admin token**: A `cluster-admin` token is required to install and
- manage Helm Tiller. GitLab establishes mutual SSL auth with Helm Tiller
- and creates limited service accounts for each application. To create the
- token we will create an admin service account as follows:
-
- 2.1. Create a file called `eks-admin-service-account.yaml` with contents:
-
- ```yaml
- apiVersion: v1
- kind: ServiceAccount
- metadata:
- name: eks-admin
- namespace: kube-system
- ```
-
- 2.2. Apply the service account to your cluster:
-
- ```bash
- kubectl apply -f eks-admin-service-account.yaml
- ```
-
- Output:
-
- ```bash
- serviceaccount "eks-admin" created
- ```
-
- 2.3. Create a file called `eks-admin-cluster-role-binding.yaml` with contents:
-
- ```yaml
- apiVersion: rbac.authorization.k8s.io/v1beta1
- kind: ClusterRoleBinding
- metadata:
- name: eks-admin
- roleRef:
- apiGroup: rbac.authorization.k8s.io
- kind: ClusterRole
- name: cluster-admin
- subjects:
- - kind: ServiceAccount
- name: eks-admin
- namespace: kube-system
- ```
-
- 2.4. Apply the cluster role binding to your cluster:
-
- ```bash
- kubectl apply -f eks-admin-cluster-role-binding.yaml
- ```
-
- Output:
-
- ```bash
- clusterrolebinding "eks-admin" created
- ```
-
- 2.5. Retrieve the token for the `eks-admin` service account:
-
- ```bash
- kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep eks-admin | awk '{print $1}')
- ```
-
- Copy the `<authentication_token>` value from the output:
-
- ```yaml
- Name: eks-admin-token-b5zv4
- Namespace: kube-system
- Labels: <none>
- Annotations: kubernetes.io/service-account.name=eks-admin
- kubernetes.io/service-account.uid=bcfe66ac-39be-11e8-97e8-026dce96b6e8
-
- Type: kubernetes.io/service-account-token
-
- Data
- ====
- ca.crt: 1025 bytes
- namespace: 11 bytes
- token: <authentication_token>
- ```
-
-1. The API server endpoint is also required, so GitLab can connect to the cluster.
- This is displayed on the AWS EKS console, when viewing the EKS cluster details.
-
-You now have all the information needed to connect the EKS cluster:
-
-- Kubernetes cluster name: Provide a name for the cluster to identify it within GitLab.
-- Environment scope: Leave this as `*` for now, since we are only connecting a single cluster.
-- API URL: Paste in the API server endpoint retrieved above.
-- CA Certificate: Paste the certificate data from the earlier step, as-is.
-- Paste the admin token value.
-- Project namespace: This can be left blank to accept the default namespace, based on the project name.
-
-![Add Cluster](img/add_cluster.png)
-
-Click on **Add Kubernetes cluster**, the cluster is now connected to GitLab.
-At this point, [Kubernetes deployment variables](../#deployment-variables) will
-automatically be available during CI/CD jobs, making it easy to interact with the cluster.
-
-If you would like to utilize your own CI/CD scripts to deploy to the cluster, you can stop here.
-
-## Disable Role-Based Access Control (RBAC) (optional)
-
-When connecting a cluster via GitLab integration, you may specify whether the
-cluster is RBAC-enabled or not. This will affect how GitLab interacts with the
-cluster for certain operations. If you **did not** check the "RBAC-enabled cluster"
-checkbox at creation time, GitLab will assume RBAC is disabled for your cluster
-when interacting with it. If so, you must disable RBAC on your cluster for the
-integration to work properly.
-
-![rbac](img/rbac.png)
-
-NOTE: **Note**: Disabling RBAC means that any application running in the cluster,
-or user who can authenticate to the cluster, has full API access. This is a
-[security concern](../index.md#security-implications), and may not be desirable.
-
-To effectively disable RBAC, global permissions can be applied granting full access:
-
-```bash
-kubectl create clusterrolebinding permissive-binding \
- --clusterrole=cluster-admin \
- --user=admin \
- --user=kubelet \
- --group=system:serviceaccounts
-```
-
-## Deploy services to the cluster
-
-GitLab supports one-click deployment of helpful services to the cluster, many of
-which support Auto DevOps. Back on the Kubernetes cluster screen in GitLab, a
-list of applications is now available to deploy.
-
-First, install Helm Tiller, a package manager for Kubernetes. This enables
-deployment of the other applications.
-
-![Deploy Apps](img/deploy_apps.png)
-
-### Deploying NGINX Ingress (optional)
-
-Next, if you would like the deployed app to be reachable on the internet, deploy
-the Ingress. Note that this will also cause an
-[Elastic Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/)
-to be created, which will incur additional AWS costs.
-
-Once installed, you may see a `?` for "Ingress IP Address". This is because the
-created ELB is available at a DNS name, not an IP address. To get the DNS name,
-run:
-
-```sh
-kubectl get service ingress-nginx-ingress-controller -n gitlab-managed-apps -o jsonpath="{.status.loadBalancer.ingress[0].hostname}"
-```
-
-Note that you may see a trailing `%` on some Kubernetes versions, **do not include it**.
-
-The Ingress is now available at this address and will route incoming requests to
-the proper service based on the DNS name in the request. To support this, a
-wildcard DNS CNAME record should be created for the desired domain name. For example,
-`*.myekscluster.com` would point to the Ingress hostname obtained earlier.
-
-![Create DNS](img/create_dns.png)
-
-### Deploying the GitLab Runner (optional)
-
-If the project is on GitLab.com, free shared Runners are available and you do
-not have to deploy one. If a project specific Runner is desired, or there are no
-shared Runners, it is easy to deploy one.
-
-Simply click on the **Install** button for the GitLab Runner. It is important to
-note that the Runner deployed is set as **privileged**, which means it essentially
-has root access to the underlying machine. This is required to build docker images,
-and so is on by default.
-
-### Deploying Prometheus (optional)
-
-GitLab is able to monitor applications automatically, utilizing
-[Prometheus](../../integrations/prometheus.html). Kubernetes container CPU and
-memory metrics are automatically collected, and response metrics are retrieved
-from NGINX Ingress as well.
-
-To enable monitoring, simply install Prometheus into the cluster with the
-**Install** button.
-
-## Create a default Storage Class
-
-Amazon EKS doesn't have a default Storage Class out of the box, which means
-requests for persistent volumes will not be automatically fulfilled. As part
-of Auto DevOps, the deployed Postgres instance requests persistent storage,
-and without a default storage class it will fail to start.
-
-If a default Storage Class doesn't already exist and is desired, follow Amazon's
-[guide on storage classes](https://docs.aws.amazon.com/eks/latest/userguide/storage-classes.html)
-to create one.
-
-Alternatively, disable Postgres by setting the project variable
-[`POSTGRES_ENABLED`](../../../../topics/autodevops/#environment-variables) to `false`.
-
-## Deploy the app to EKS
-
-With RBAC disabled and services deployed,
-[Auto DevOps](../../../../topics/autodevops/index.md) can now be leveraged
-to build, test, and deploy the app.
-
-[Enable Auto DevOps](../../../../topics/autodevops/index.md#at-the-project-level)
-if not already enabled. If a wildcard DNS entry was created resolving to the
-Load Balancer, enter it in the `domain` field under the Auto DevOps settings.
-Otherwise, the deployed app will not be externally available outside of the cluster.
-
-![Deploy Pipeline](img/pipeline.png)
-
-A new pipeline will automatically be created, which will begin to build, test,
-and deploy the app.
-
-After the pipeline has finished, your app will be running in EKS and available
-to users. Click on **CI/CD > Environments**.
-
-![Deployed Environment](img/environment.png)
-
-You will see a list of the environments and their deploy status, as well as
-options to browse to the app, view monitoring metrics, and even access a shell
-on the running pod.
-
-## Learn more
-
-To learn more on automatically deploying your applications,
-read about [Auto DevOps](../../../../topics/autodevops/index.md).
+This document was moved to [another location](../add_remove_clusters.md#add-existing-eks-cluster).
diff --git a/doc/user/project/clusters/eks_and_gitlab/img/add_cluster.png b/doc/user/project/clusters/img/add_cluster.png
index 94ec83f1514..94ec83f1514 100644
--- a/doc/user/project/clusters/eks_and_gitlab/img/add_cluster.png
+++ b/doc/user/project/clusters/img/add_cluster.png
Binary files differ
diff --git a/doc/user/project/clusters/eks_and_gitlab/img/environment.png b/doc/user/project/clusters/img/environment.png
index 4714c447026..4714c447026 100644
--- a/doc/user/project/clusters/eks_and_gitlab/img/environment.png
+++ b/doc/user/project/clusters/img/environment.png
Binary files differ
diff --git a/doc/user/project/clusters/img/kubernetes_pod_logs_v12_4.png b/doc/user/project/clusters/img/kubernetes_pod_logs_v12_4.png
deleted file mode 100644
index 73c2ecd182a..00000000000
--- a/doc/user/project/clusters/img/kubernetes_pod_logs_v12_4.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/clusters/img/kubernetes_pod_logs_v12_5.png b/doc/user/project/clusters/img/kubernetes_pod_logs_v12_5.png
new file mode 100644
index 00000000000..e54637e7218
--- /dev/null
+++ b/doc/user/project/clusters/img/kubernetes_pod_logs_v12_5.png
Binary files differ
diff --git a/doc/user/project/clusters/eks_and_gitlab/img/pipeline.png b/doc/user/project/clusters/img/pipeline.png
index 0eb00d0faa7..0eb00d0faa7 100644
--- a/doc/user/project/clusters/eks_and_gitlab/img/pipeline.png
+++ b/doc/user/project/clusters/img/pipeline.png
Binary files differ
diff --git a/doc/user/project/clusters/eks_and_gitlab/img/rbac.png b/doc/user/project/clusters/img/rbac.png
index 517e4f7ca44..517e4f7ca44 100644
--- a/doc/user/project/clusters/eks_and_gitlab/img/rbac.png
+++ b/doc/user/project/clusters/img/rbac.png
Binary files differ
diff --git a/doc/user/project/clusters/img/sidebar_menu_pod_logs_v12_5.png b/doc/user/project/clusters/img/sidebar_menu_pod_logs_v12_5.png
new file mode 100644
index 00000000000..f113b0353f2
--- /dev/null
+++ b/doc/user/project/clusters/img/sidebar_menu_pod_logs_v12_5.png
Binary files differ
diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md
index 9ecb785d6fe..c5c2c2c07e7 100644
--- a/doc/user/project/clusters/index.md
+++ b/doc/user/project/clusters/index.md
@@ -28,12 +28,11 @@ Using the GitLab project Kubernetes integration, you can:
- Use [Deploy Boards](#deploy-boards-premium). **(PREMIUM)**
- Use [Canary Deployments](#canary-deployments-premium). **(PREMIUM)**
- View [Pod logs](#pod-logs-ultimate). **(ULTIMATE)**
-
-You can also:
-
-- Connect and deploy to an [Amazon EKS cluster](eks_and_gitlab/index.html).
- Run serverless workloads on [Kubernetes with Knative](serverless/index.md).
+See [Adding and removing Kubernetes clusters](add_remove_clusters.md) for details on how to
+set up integrations.
+
### Deploy Boards **(PREMIUM)**
GitLab's Deploy Boards offer a consolidated view of the current health and
@@ -98,236 +97,10 @@ pods are annotated with:
`$CI_ENVIRONMENT_SLUG` and `$CI_PROJECT_PATH_SLUG` are the values of
the CI variables.
-## Adding and removing clusters
-
-There are two options when adding a new cluster to your project:
-
-- Associate your account with Google Kubernetes Engine (GKE) to
- [create new clusters](#add-new-gke-cluster) from within GitLab.
-- Provide credentials to an
- [existing Kubernetes cluster](#add-existing-kubernetes-cluster).
-
-### Add new GKE cluster
-
-TIP: **Tip:**
-Every new Google Cloud Platform (GCP) account receives [$300 in credit upon sign up](https://console.cloud.google.com/freetrial),
-and in partnership with Google, GitLab is able to offer an additional $200 for new GCP accounts to get started with GitLab's
-Google Kubernetes Engine Integration. All you have to do is [follow this link](https://cloud.google.com/partners/partnercredit/?PCN=a0n60000006Vpz4AAC) and apply for credit.
-
-NOTE: **Note:**
-The [Google authentication integration](../../../integration/google.md) must
-be enabled in GitLab at the instance level. If that's not the case, ask your
-GitLab administrator to enable it. On GitLab.com, this is enabled.
-
-#### Requirements
-
-Before creating your first cluster on Google Kubernetes Engine with GitLab's
-integration, make sure the following requirements are met:
-
-- A [billing account](https://cloud.google.com/billing/docs/how-to/manage-billing-account)
- is set up and you have permissions to access it.
-- The Kubernetes Engine API and related service are enabled. It should work immediately but may take up to 10 minutes after you create a project. For more information see the
- ["Before you begin" section of the Kubernetes Engine docs](https://cloud.google.com/kubernetes-engine/docs/quickstart#before-you-begin).
-
-#### Creating the cluster
-
-If all of the above requirements are met, you can proceed to create and add a
-new Kubernetes cluster to your project:
-
-1. Navigate to your project's **Operations > Kubernetes** page.
-
- NOTE: **Note:**
- You need Maintainer [permissions](../../permissions.md) and above to access the Kubernetes page.
-
-1. Click **Add Kubernetes cluster**.
-1. Click **Create with Google Kubernetes Engine**.
-1. Connect your Google account if you haven't done already by clicking the
- **Sign in with Google** button.
-1. From there on, choose your cluster's settings:
- - **Kubernetes cluster name** - The name you wish to give the cluster.
- - **Environment scope** - The [associated environment](#setting-the-environment-scope-premium) to this cluster.
- - **Google Cloud Platform project** - Choose the project you created in your GCP
- console that will host the Kubernetes cluster. Learn more about
- [Google Cloud Platform projects](https://cloud.google.com/resource-manager/docs/creating-managing-projects).
- - **Zone** - Choose the [region zone](https://cloud.google.com/compute/docs/regions-zones/)
- under which the cluster will be created.
- - **Number of nodes** - Enter the number of nodes you wish the cluster to have.
- - **Machine type** - The [machine type](https://cloud.google.com/compute/docs/machine-types)
- of the Virtual Machine instance that the cluster will be based on.
- - **Enable Cloud Run on GKE (beta)** - Check this if you want to use Cloud Run on GKE for this cluster. See the [Cloud Run on GKE section](#cloud-run-on-gke) for more information.
- - **GitLab-managed cluster** - Leave this checked if you want GitLab to manage namespaces and service accounts for this cluster. See the [Managed clusters section](#gitlab-managed-clusters) for more information.
-1. Finally, click the **Create Kubernetes cluster** button.
-
-After a couple of minutes, your cluster will be ready to go. You can now proceed
-to install some [pre-defined applications](#installing-applications).
-
-NOTE: **Note:**
-GitLab requires basic authentication enabled and a client certificate issued for
-the cluster in order to setup an [initial service
-account](#access-controls). Starting from [GitLab
-11.10](https://gitlab.com/gitlab-org/gitlab-foss/issues/58208), the cluster
-creation process will explicitly request that basic authentication and
-client certificate is enabled.
-
-NOTE: **Note:**
-Starting from [GitLab 12.1](https://gitlab.com/gitlab-org/gitlab-foss/issues/55902), all GKE clusters created by GitLab are RBAC enabled. Take a look at the [RBAC section](#rbac-cluster-resources) for more information.
-
-### Add existing Kubernetes cluster
-
-NOTE: **Note:**
-Kubernetes integration is not supported for arm64 clusters. See the issue [Helm Tiller fails to install on arm64 cluster](https://gitlab.com/gitlab-org/gitlab-foss/issues/64044) for details.
-
-To add an existing Kubernetes cluster to your project:
-
-1. Navigate to your project's **Operations > Kubernetes** page.
-
- NOTE: **Note:**
- You need Maintainer [permissions](../../permissions.md) and above to access the Kubernetes page.
-
-1. Click **Add Kubernetes cluster**.
-1. Click **Add an existing Kubernetes cluster** and fill in the details:
- - **Kubernetes cluster name** (required) - The name you wish to give the cluster.
- - **Environment scope** (required) - The
- [associated environment](#setting-the-environment-scope-premium) to this cluster.
- - **API URL** (required) -
- It's the URL that GitLab uses to access the Kubernetes API. Kubernetes
- exposes several APIs, we want the "base" URL that is common to all of them,
- e.g., `https://kubernetes.example.com` rather than `https://kubernetes.example.com/api/v1`.
-
- Get the API URL by running this command:
-
- ```sh
- kubectl cluster-info | grep 'Kubernetes master' | awk '/http/ {print $NF}'
- ```
-
- - **CA certificate** (required) - A valid Kubernetes certificate is needed to authenticate to the cluster. We will use the certificate created by default.
- - List the secrets with `kubectl get secrets`, and one should named similar to
- `default-token-xxxxx`. Copy that token name for use below.
- - Get the certificate by running this command:
-
- ```sh
- kubectl get secret <secret name> -o jsonpath="{['data']['ca\.crt']}" | base64 --decode
- ```
-
- - **Token** -
- GitLab authenticates against Kubernetes using service tokens, which are
- scoped to a particular `namespace`.
- **The token used should belong to a service account with
- [`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles)
- privileges.** To create this service account:
-
- 1. Create a file called `gitlab-admin-service-account.yaml` with contents:
-
- ```yaml
- apiVersion: v1
- kind: ServiceAccount
- metadata:
- name: gitlab-admin
- namespace: kube-system
- ---
- apiVersion: rbac.authorization.k8s.io/v1beta1
- kind: ClusterRoleBinding
- metadata:
- name: gitlab-admin
- roleRef:
- apiGroup: rbac.authorization.k8s.io
- kind: ClusterRole
- name: cluster-admin
- subjects:
- - kind: ServiceAccount
- name: gitlab-admin
- namespace: kube-system
- ```
-
- 1. Apply the service account and cluster role binding to your cluster:
-
- ```bash
- kubectl apply -f gitlab-admin-service-account.yaml
- ```
-
- Output:
-
- ```bash
- serviceaccount "gitlab-admin" created
- clusterrolebinding "gitlab-admin" created
- ```
-
- 1. Retrieve the token for the `gitlab-admin` service account:
-
- ```bash
- kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep gitlab-admin | awk '{print $1}')
- ```
-
- Copy the `<authentication_token>` value from the output:
-
- ```yaml
- Name: gitlab-admin-token-b5zv4
- Namespace: kube-system
- Labels: <none>
- Annotations: kubernetes.io/service-account.name=gitlab-admin
- kubernetes.io/service-account.uid=bcfe66ac-39be-11e8-97e8-026dce96b6e8
-
- Type: kubernetes.io/service-account-token
-
- Data
- ====
- ca.crt: 1025 bytes
- namespace: 11 bytes
- token: <authentication_token>
- ```
-
- NOTE: **Note:**
- For GKE clusters, you will need the
- `container.clusterRoleBindings.create` permission to create a cluster
- role binding. You can follow the [Google Cloud
- documentation](https://cloud.google.com/iam/docs/granting-changing-revoking-access)
- to grant access.
-
- - **GitLab-managed cluster** - Leave this checked if you want GitLab to manage namespaces and service accounts for this cluster. See the [Managed clusters section](#gitlab-managed-clusters) for more information.
-
- - **Project namespace** (optional) - You don't have to fill it in; by leaving
- it blank, GitLab will create one for you. Also:
- - Each project should have a unique namespace.
- - The project namespace is not necessarily the namespace of the secret, if
- you're using a secret with broader permissions, like the secret from `default`.
- - You should **not** use `default` as the project namespace.
- - If you or someone created a secret specifically for the project, usually
- with limited permissions, the secret's namespace and project namespace may
- be the same.
-
-1. Finally, click the **Create Kubernetes cluster** button.
-
-After a couple of minutes, your cluster will be ready to go. You can now proceed
-to install some [pre-defined applications](#installing-applications).
-
-### Enabling or disabling integration
-
-After you have successfully added your cluster information, you can enable the
-Kubernetes cluster integration:
-
-1. Click the **Enabled/Disabled** switch
-1. Hit **Save** for the changes to take effect
-
-To disable the Kubernetes cluster integration, follow the same procedure.
-
-### Removing integration
-
-NOTE: **Note:**
-You need Maintainer [permissions](../../permissions.md) and above to remove a Kubernetes cluster integration.
-
-NOTE: **Note:**
-When you remove a cluster, you only remove its relation to GitLab, not the
-cluster itself. To remove the cluster, you can do so by visiting the GKE
-dashboard or using `kubectl`.
-
-To remove the Kubernetes cluster integration from your project, simply click the
-**Remove integration** button. You will then be able to follow the procedure
-and add a Kubernetes cluster again.
-
## Cluster configuration
-This section covers important considerations for configuring Kubernetes
-clusters with GitLab.
+After [adding a Kubernetes cluster](add_remove_clusters.md) to GitLab, read this section that covers
+important considerations for configuring Kubernetes clusters with GitLab.
### Security implications
@@ -340,15 +113,6 @@ functionalities needed to successfully build and deploy a containerized
application. Bear in mind that the same credentials are used for all the
applications running on the cluster.
-### Cloud Run on GKE
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/16566) in GitLab 12.4.
-
-You can choose to use Cloud Run on GKE in place of installing Knative and Istio
-separately after the cluster has been created. This means that Cloud Run
-(Knative), Istio, and HTTP Load Balancing will be enabled on the cluster at
-create time and cannot be [installed or uninstalled](../../clusters/applications.md) separately.
-
### GitLab-managed clusters
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/22011) in GitLab 11.5.
@@ -356,7 +120,7 @@ create time and cannot be [installed or uninstalled](../../clusters/applications
You can choose to allow GitLab to manage your cluster for you. If your cluster is
managed by GitLab, resources for your projects will be automatically created. See the
-[Access controls](#access-controls) section for details on which resources will
+[Access controls](add_remove_clusters.md#access-controls) section for details on which resources will
be created.
If you choose to manage your own cluster, project-specific resources will not be created
@@ -386,97 +150,6 @@ you can either:
- Create an `A` record that points to the Ingress IP address with your domain provider.
- Enter a wildcard DNS address using a service such as nip.io or xip.io. For example, `192.168.1.1.xip.io`.
-### Access controls
-
-When creating a cluster in GitLab, you will be asked if you would like to create either:
-
-- An [Attribute-based access control (ABAC)](https://kubernetes.io/docs/reference/access-authn-authz/abac/) cluster.
-- A [Role-based access control (RBAC)](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) cluster.
-
-NOTE: **Note:**
-[RBAC](#rbac-cluster-resources) is recommended and the GitLab default.
-
-GitLab creates the necessary service accounts and privileges to install and run
-[GitLab managed applications](#installing-applications). When GitLab creates the cluster,
-a `gitlab` service account with `cluster-admin` privileges is created in the `default` namespace
-to manage the newly created cluster.
-
- NOTE: **Note:**
- Restricted service account for deployment was [introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/51716) in GitLab 11.5.
-
-When you install Helm into your cluster, the `tiller` service account
-is created with `cluster-admin` privileges in the `gitlab-managed-apps`
-namespace. This service account will be added to the installed Helm Tiller and will
-be used by Helm to install and run [GitLab managed applications](#installing-applications).
-Helm will also create additional service accounts and other resources for each
-installed application. Consult the documentation of the Helm charts for each application
-for details.
-
-If you are [adding an existing Kubernetes cluster](#add-existing-kubernetes-cluster),
-ensure the token of the account has administrator privileges for the cluster.
-
-The resources created by GitLab differ depending on the type of cluster.
-
-#### ABAC cluster resources
-
-GitLab creates the following resources for ABAC clusters.
-
-| Name | Type | Details | Created when |
-|:----------------------|:---------------------|:-------------------------------------|:---------------------------|
-| `gitlab` | `ServiceAccount` | `default` namespace | Creating a new GKE Cluster |
-| `gitlab-token` | `Secret` | Token for `gitlab` ServiceAccount | Creating a new GKE Cluster |
-| `tiller` | `ServiceAccount` | `gitlab-managed-apps` namespace | Installing Helm Tiller |
-| `tiller-admin` | `ClusterRoleBinding` | `cluster-admin` roleRef | Installing Helm Tiller |
-| Environment namespace | `Namespace` | Contains all environment-specific resources | Deploying to a cluster |
-| Environment namespace | `ServiceAccount` | Uses namespace of environment | Deploying to a cluster |
-| Environment namespace | `Secret` | Token for environment ServiceAccount | Deploying to a cluster |
-
-#### RBAC cluster resources
-
-GitLab creates the following resources for RBAC clusters.
-
-| Name | Type | Details | Created when |
-|:----------------------|:---------------------|:-----------------------------------------------------------------------------------------------------------|:---------------------------|
-| `gitlab` | `ServiceAccount` | `default` namespace | Creating a new GKE Cluster |
-| `gitlab-admin` | `ClusterRoleBinding` | [`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) roleRef | Creating a new GKE Cluster |
-| `gitlab-token` | `Secret` | Token for `gitlab` ServiceAccount | Creating a new GKE Cluster |
-| `tiller` | `ServiceAccount` | `gitlab-managed-apps` namespace | Installing Helm Tiller |
-| `tiller-admin` | `ClusterRoleBinding` | `cluster-admin` roleRef | Installing Helm Tiller |
-| Environment namespace | `Namespace` | Contains all environment-specific resources | Deploying to a cluster |
-| Environment namespace | `ServiceAccount` | Uses namespace of environment | Deploying to a cluster |
-| Environment namespace | `Secret` | Token for environment ServiceAccount | Deploying to a cluster |
-| Environment namespace | `RoleBinding` | [`edit`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) roleRef | Deploying to a cluster |
-
-NOTE: **Note:**
-Environment-specific resources are only created if your cluster is [managed by GitLab](#gitlab-managed-clusters).
-
-NOTE: **Note:**
-If your cluster was created before GitLab 12.2, it will use a single namespace for all project environments.
-
-#### Security of GitLab Runners
-
-GitLab Runners have the [privileged mode](https://docs.gitlab.com/runner/executors/docker.html#the-privileged-mode)
-enabled by default, which allows them to execute special commands and running
-Docker in Docker. This functionality is needed to run some of the
-[Auto DevOps](../../../topics/autodevops/index.md)
-jobs. This implies the containers are running in privileged mode and you should,
-therefore, be aware of some important details.
-
-The privileged flag gives all capabilities to the running container, which in
-turn can do almost everything that the host can do. Be aware of the
-inherent security risk associated with performing `docker run` operations on
-arbitrary images as they effectively have root access.
-
-If you don't want to use GitLab Runner in privileged mode, either:
-
-- Use shared Runners on GitLab.com. They don't have this security issue.
-- Set up your own Runners using configuration described at
- [Shared Runners](../../gitlab_com/index.md#shared-runners). This involves:
- 1. Making sure that you don't have it installed via
- [the applications](#installing-applications).
- 1. Installing a Runner
- [using `docker+machine`](https://docs.gitlab.com/runner/executors/docker_machine.html).
-
### Setting the environment scope **(PREMIUM)**
When adding more than one Kubernetes cluster to your project, you need to differentiate
@@ -545,93 +218,12 @@ differentiate the new cluster with the rest.
## Installing applications
-GitLab can install and manage some applications in your project-level
-cluster. For more information on installing, upgrading, uninstalling,
-and troubleshooting applications for your project cluster, see
+GitLab can install and manage some applications like Helm, GitLab Runner, Ingress,
+Prometheus, etc., in your project-level cluster. For more information on
+installing, upgrading, uninstalling, and troubleshooting applications for
+your project cluster, see
[GitLab Managed Apps](../../clusters/applications.md).
-### Getting the external endpoint
-
-NOTE: **Note:**
-With the following procedure, a load balancer must be installed in your cluster
-to obtain the endpoint. You can use either
-[Ingress](#installing-applications), or Knative's own load balancer
-([Istio](https://istio.io)) if using [Knative](#installing-applications).
-
-In order to publish your web application, you first need to find the endpoint which will be either an IP
-address or a hostname associated with your load balancer.
-
-#### Automatically determining the external endpoint
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/17052) in GitLab 10.6.
-
-After you install [Ingress or Knative](#installing-applications), GitLab attempts to determine the external endpoint
-and it should be available within a few minutes. If the endpoint doesn't appear
-and your cluster runs on Google Kubernetes Engine:
-
-1. Check your [Kubernetes cluster on Google Kubernetes Engine](https://console.cloud.google.com/kubernetes) to ensure there are no errors on its nodes.
-1. Ensure you have enough [Quotas](https://console.cloud.google.com/iam-admin/quotas) on Google Kubernetes Engine. For more information, see [Resource Quotas](https://cloud.google.com/compute/quotas).
-1. Check [Google Cloud's Status](https://status.cloud.google.com/) to ensure they are not having any disruptions.
-
-If GitLab is still unable to determine the endpoint of your Ingress or Knative application, you can
-manually determine it by following the steps below.
-
-#### Manually determining the external endpoint
-
-If the cluster is on GKE, click the **Google Kubernetes Engine** link in the
-**Advanced settings**, or go directly to the
-[Google Kubernetes Engine dashboard](https://console.cloud.google.com/kubernetes/)
-and select the proper project and cluster. Then click **Connect** and execute
-the `gcloud` command in a local terminal or using the **Cloud Shell**.
-
-If the cluster is not on GKE, follow the specific instructions for your
-Kubernetes provider to configure `kubectl` with the right credentials.
-The output of the following examples will show the external endpoint of your
-cluster. This information can then be used to set up DNS entries and forwarding
-rules that allow external access to your deployed applications.
-
-If you installed the Ingress [via the **Applications**](#installing-applications),
-run the following command:
-
-```bash
-kubectl get service --namespace=gitlab-managed-apps ingress-nginx-ingress-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
-```
-
-Some Kubernetes clusters return a hostname instead, like [Amazon EKS](https://aws.amazon.com/eks/). For these platforms, run:
-
-```bash
-kubectl get service --namespace=gitlab-managed-apps ingress-nginx-ingress-controller -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'
-```
-
-For Istio/Knative, the command will be different:
-
-```bash
-kubectl get svc --namespace=istio-system knative-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip} '
-```
-
-Otherwise, you can list the IP addresses of all load balancers:
-
-```bash
-kubectl get svc --all-namespaces -o jsonpath='{range.items[?(@.status.loadBalancer.ingress)]}{.status.loadBalancer.ingress[*].ip} '
-```
-
-#### Using a static IP
-
-By default, an ephemeral external IP address is associated to the cluster's load
-balancer. If you associate the ephemeral IP with your DNS and the IP changes,
-your apps will not be able to be reached, and you'd have to change the DNS
-record again. In order to avoid that, you should change it into a static
-reserved IP.
-
-Read how to [promote an ephemeral external IP address in GKE](https://cloud.google.com/compute/docs/ip-addresses/reserve-static-external-ip-address#promote_ephemeral_ip).
-
-#### Pointing your DNS at the external endpoint
-
-Once you've set up the external endpoint, you should associate it with a [wildcard DNS
-record](https://en.wikipedia.org/wiki/Wildcard_DNS_record) such as `*.example.com.`
-in order to be able to reach your apps. If your external endpoint is an IP address,
-use an A record. If your external endpoint is a hostname, use a CNAME record.
-
## Deploying to a Kubernetes cluster
A Kubernetes cluster can be the destination for a deployment job. If
@@ -654,8 +246,8 @@ GitLab CI/CD build environment.
| Variable | Description |
| -------- | ----------- |
| `KUBE_URL` | Equal to the API URL. |
-| `KUBE_TOKEN` | The Kubernetes token of the [environment service account](#access-controls). |
-| `KUBE_NAMESPACE` | The Kubernetes namespace is auto-generated if not specified. The default value is `<project_name>-<project_id>-<environment>`. You can overwrite it to use different one if needed, otherwise the `KUBE_NAMESPACE` variable will receive the default value. |
+| `KUBE_TOKEN` | The Kubernetes token of the [environment service account](add_remove_clusters.md#access-controls). |
+| `KUBE_NAMESPACE` | The namespace associated with the project's deployment service account. In the format `<project_name>-<project_id>-<environment>`. For GitLab-managed clusters, a matching namespace is automatically created by GitLab in the cluster. |
| `KUBE_CA_PEM_FILE` | Path to a file containing PEM data. Only present if a custom CA bundle was specified. |
| `KUBE_CA_PEM` | (**deprecated**) Raw PEM data. Only if a custom CA bundle was specified. |
| `KUBECONFIG` | Path to a file containing `kubeconfig` for this deployment. CA bundle would be embedded if specified. This config also embeds the same token defined in `KUBE_TOKEN` so you likely will only need this variable. This variable name is also automatically picked up by `kubectl` so you won't actually need to reference it explicitly if using `kubectl`. |
@@ -668,6 +260,16 @@ service account of the cluster integration.
NOTE: **Note:**
If your cluster was created before GitLab 12.2, default `KUBE_NAMESPACE` will be set to `<project_name>-<project_id>`.
+When deploying a custom namespace:
+
+- The custom namespace must exist in your cluster.
+- The project's deployment service account must have permission to deploy to the namespace.
+- `KUBECONFIG` must be updated to use the custom namespace instead of the GitLab-provided default (this is [not automatic](https://gitlab.com/gitlab-org/gitlab/issues/31519)).
+- If deploying with Auto DevOps, you must *also* override `KUBE_NAMESPACE` with the custom namespace.
+
+CAUTION: **Caution:**
+GitLab does not save custom namespaces in the database. So while deployments work with custom namespaces, GitLab's integration for already-deployed environments will not pick up the customized values. For example, [Deploy Boards](../deploy_boards.md) will not work as intended for those deployments. For more information, see the [related issue](https://gitlab.com/gitlab-org/gitlab/issues/27630).
+
### Troubleshooting
Before the deployment jobs starts, GitLab creates the following specifically for
diff --git a/doc/user/project/clusters/kubernetes_pod_logs.md b/doc/user/project/clusters/kubernetes_pod_logs.md
index 4036eaf0bfb..797ddf784cc 100644
--- a/doc/user/project/clusters/kubernetes_pod_logs.md
+++ b/doc/user/project/clusters/kubernetes_pod_logs.md
@@ -11,7 +11,31 @@ Everything you need to build, test, deploy, and run your app at scale.
## Overview
-[Kubernetes](https://kubernetes.io) pod logs can be viewed directly within GitLab. Logs can be displayed by clicking on a specific pod from [Deploy Boards](../deploy_boards.md):
+[Kubernetes](https://kubernetes.io) pod logs can be viewed directly within GitLab.
+
+![Pod logs](img/kubernetes_pod_logs_v12_5.png)
+
+## Requirements
+
+[Deploying to a Kubernetes environment](../deploy_boards.md#enabling-deploy-boards) is required in order to be able to use Pod Logs.
+
+## Usage
+
+To access pod logs, you must have the right [permissions](../../permissions.md#project-members-permissions).
+
+You can access them in two ways.
+
+### From the project sidebar
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/22011) in GitLab 12.5.
+
+Go to **Operations > Pod logs** on the sidebar menu.
+
+![Sidebar menu](img/sidebar_menu_pod_logs_v12_5.png)
+
+### From Deploy Boards
+
+Logs can be displayed by clicking on a specific pod from [Deploy Boards](../deploy_boards.md):
1. Go to **Operations > Environments** and find the environment which contains the desired pod, like `production`.
1. On the **Environments** page, you should see the status of the environment's pods with [Deploy Boards](../deploy_boards.md).
@@ -23,9 +47,3 @@ Everything you need to build, test, deploy, and run your app at scale.
- [From GitLab 12.4](https://gitlab.com/gitlab-org/gitlab/issues/5769), environments.
Support for pods with multiple containers is coming [in a future release](https://gitlab.com/gitlab-org/gitlab/issues/6502).
-
- ![Deploy Boards pod list](img/kubernetes_pod_logs_v12_4.png)
-
-## Requirements
-
-[Enabling Deploy Boards](../deploy_boards.md#enabling-deploy-boards) is required in order to be able to use Pod Logs.
diff --git a/doc/user/project/clusters/runbooks/index.md b/doc/user/project/clusters/runbooks/index.md
index 7b17ec68234..bffae4c5069 100644
--- a/doc/user/project/clusters/runbooks/index.md
+++ b/doc/user/project/clusters/runbooks/index.md
@@ -35,7 +35,7 @@ for an overview of how this is accomplished in GitLab!**
To create an executable runbook, you will need:
1. **Kubernetes** - A Kubernetes cluster is required to deploy the rest of the applications.
- The simplest way to get started is to add a cluster using [GitLab's GKE integration](../index.md#add-new-gke-cluster).
+ The simplest way to get started is to add a cluster using one of [GitLab's integrations](../add_remove_clusters.md#add-new-cluster).
1. **Helm Tiller** - Helm is a package manager for Kubernetes and is required to install
all the other applications. It is installed in its own pod inside the cluster which
can run the Helm CLI in a safe environment.
@@ -60,7 +60,7 @@ the components outlined above and the preloaded demo runbook.
### 1. Add a Kubernetes cluster
-Follow the steps outlined in [Add new GKE cluster](../index.md#add-new-gke-cluster)
+Follow the steps outlined in [Add new cluster](../add_remove_clusters.md#add-new-cluster)
to add a Kubernetes cluster to your project.
### 2. Install Helm Tiller, Ingress, and JupyterHub
diff --git a/doc/user/project/clusters/serverless/index.md b/doc/user/project/clusters/serverless/index.md
index 9a9857bd5da..ffd7b0c0f2a 100644
--- a/doc/user/project/clusters/serverless/index.md
+++ b/doc/user/project/clusters/serverless/index.md
@@ -13,14 +13,16 @@ GitLab supports several ways deploy Serverless applications in both Kubernetes E
Currently we support:
-- [Knative](#knative): Build Knative applications with Knative and gitlabktl on GKE
-- [AWS Lambda](aws.md): Create serverless applications via the Serverless Framework and GitLab CI
+- [Knative](#knative): Build Knative applications with Knative and gitlabktl on GKE.
+- [AWS Lambda](aws.md): Create serverless applications via the Serverless Framework and GitLab CI.
## Knative
Run serverless workloads on Kubernetes using [Knative](https://cloud.google.com/knative/).
-Knative extends Kubernetes to provide a set of middleware components that are useful to build modern, source-centric, container-based applications. Knative brings some significant benefits out of the box through its main components:
+Knative extends Kubernetes to provide a set of middleware components that are useful to build
+modern, source-centric, container-based applications. Knative brings some significant benefits out
+of the box through its main components:
- [Serving](https://github.com/knative/serving): Request-driven compute that can scale to zero.
- [Eventing](https://github.com/knative/eventing): Management and delivery of events.
@@ -39,7 +41,7 @@ To run Knative on GitLab, you will need:
- If you are planning on deploying a serverless application, clone the sample [Knative Ruby App](https://gitlab.com/knative-examples/knative-ruby-app) to get started.
1. **Kubernetes Cluster:** An RBAC-enabled Kubernetes cluster is required to deploy Knative.
- The simplest way to get started is to add a cluster using [GitLab's GKE integration](../index.md#add-new-gke-cluster).
+ The simplest way to get started is to add a cluster using [GitLab's GKE integration](../add_remove_clusters.md#gke-cluster).
The set of minimum recommended cluster specifications to run Knative is 3 nodes, 6 vCPUs, and 22.50 GB memory.
1. **Helm Tiller:** Helm is a package manager for Kubernetes and is required to install
Knative.
@@ -62,20 +64,22 @@ To run Knative on GitLab, you will need:
using our [runtimes](https://gitlab.com/gitlab-org/serverless/runtimes).
1. **Prometheus** (optional): Installing Prometheus allows you to monitor the scale and traffic of your serverless function/application.
See [Installing Applications](../index.md#installing-applications) for more information.
+1. **Logging** (optional): Configuring logging allows you to view and search request logs for your serverless function/application.
+ See [Configuring logging](#configuring-logging) for more information.
## Installing Knative via GitLab's Kubernetes integration
NOTE: **Note:**
The minimum recommended cluster size to run Knative is 3-nodes, 6 vCPUs, and 22.50 GB memory. **RBAC must be enabled.**
-1. [Add a Kubernetes cluster](../index.md) and [install Helm](../index.md#installing-applications).
+1. [Add a Kubernetes cluster](../add_remove_clusters.md) and [install Helm](../index.md#installing-applications).
1. Once Helm has been successfully installed, scroll down to the Knative app section. Enter the domain to be used with
your application/functions (e.g. `example.com`) and click **Install**.
![install-knative](img/install-knative.png)
1. After the Knative installation has finished, you can wait for the IP address or hostname to be displayed in the
- **Knative Endpoint** field or [retrieve the Istio Ingress Endpoint manually](../#manually-determining-the-external-endpoint).
+ **Knative Endpoint** field or [retrieve the Istio Ingress Endpoint manually](../../../clusters/applications.md#determining-the-external-endpoint-manually).
NOTE: **Note:**
Running `kubectl` commands on your cluster requires setting up access to the cluster first.
@@ -108,7 +112,7 @@ You must do the following:
1. Follow the steps to
[add an existing Kubernetes
- cluster](../index.md#add-existing-kubernetes-cluster).
+ cluster](../add_remove_clusters.md#add-existing-cluster).
1. Ensure GitLab can manage Knative:
- For a non-GitLab managed cluster, ensure that the service account for the token
@@ -164,13 +168,61 @@ You must do the following:
or [serverless applications](#deploying-serverless-applications) onto your
cluster.
-## Deploying functions
+## Configuring logging
-> Introduced in GitLab 11.6.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/33330) in GitLab 12.5.
+
+### Prerequisites
+
+- A GitLab-managed cluster.
+- `kubectl` installed and working.
+
+Running `kubectl` commands on your cluster requires setting up access to the
+cluster first. For clusters created on:
+
+- GKE, see [GKE Cluster Access](https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-access-for-kubectl)
+- Other platforms, see [Install and Set Up kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/).
+
+### Enable request log template
+
+Run the following command to enable request logs:
+
+```shell
+kubectl edit cm -n knative-serving config-observability
+```
+
+Copy the `logging.request-log-template` from the `data._example` field to the data field one level up in the hierarchy.
+
+### Enable request logs
+
+Run the following commands to install Elasticsearch, Kibana, and Filebeat into a `kube-logging` namespace and configure all nodes to forward logs using Filebeat:
-Using functions is useful for dealing with independent events without needing
-to maintain a complex unified infrastructure. This allows you to focus on a
-single task that can be executed/scaled automatically and independently.
+```shell
+kubectl apply -f https://gitlab.com/gitlab-org/serverless/configurations/knative/raw/v0.7.0/kube-logging-filebeat.yaml
+kubectl label nodes --all beta.kubernetes.io/filebeat-ready="true"
+```
+
+### Viewing request logs
+
+To view request logs:
+
+1. Run `kubectl proxy`.
+1. Navigate to Kibana UI.
+
+Or:
+
+1. Open the Kibana UI.
+1. Click on **Discover**, then select `filebeat-*` from the dropdown on the left.
+1. Enter `kubernetes.container.name:"queue-proxy" AND message:/httpRequest/` into the search box.
+
+## Supported runtimes
+
+Serverless functions for GitLab can be written in 6 supported languages:
+
+- NodeJS and Ruby, with GitLab-managed and OpenFaas runtimes.
+- C#, Go, PHP, and Python with OpenFaaS runtimes only.
+
+### GitLab managed runtimes
Currently the following [runtimes](https://gitlab.com/gitlab-org/serverless/runtimes) are offered:
@@ -180,6 +232,31 @@ Currently the following [runtimes](https://gitlab.com/gitlab-org/serverless/runt
`Dockerfile` presence is assumed when a runtime is not specified.
+### OpenFaaS runtimes
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/29253) in GitLab 12.5.
+
+[OpenFaaS classic runtimes](https://github.com/openfaas/templates#templates-in-store) can be used with GitLab serverless.
+Runtimes are specified using the pattern: `openfaas/classic/<template_name>`. The following
+example shows how to define a function in `serverless.yml` using an OpenFaaS runtime:
+
+```yaml
+hello:
+ source: ./hello
+ runtime: openfaas/classic/ruby
+ description: "Ruby function using OpenFaaS classic runtime"
+```
+
+`handler` is not needed for OpenFaaS functions. The location of the handler is defined
+by the conventions of the runtime.
+
+See the [`ruby-openfaas-function`](https://gitlab.com/knative-examples/ruby-openfaas-function)
+project for an example of a function using an OpenFaaS runtime.
+
+## Deploying functions
+
+> Introduced in GitLab 11.6.
+
You can find and import all the files referenced in this doc in the
**[functions example project](https://gitlab.com/knative-examples/functions)**.
@@ -311,10 +388,49 @@ The sample function can now be triggered from any HTTP client using a simple `PO
![function execution](img/function-execution.png)
+### Running functions locally
+
+Running a function locally is a good way to quickly verify behavior during development.
+
+Running functions locally requires:
+
+- Go 1.12 or newer installed.
+- Docker Engine installed and running.
+- `gitlabktl` installed using the Go package manager:
+
+ ```shell
+ GO111MODULE=on go get gitlab.com/gitlab-org/gitlabktl
+ ```
+
+To run a function locally:
+
+1. Navigate to the root of your GitLab serverless project.
+1. Build your function into a Docker image:
+
+ ```shell
+ gitlabktl serverless build
+ ```
+
+1. Run your function in Docker:
+
+ ```shell
+ docker run -itp 8080:8080 <your_function_name>
+ ```
+
+1. Invoke your function:
+
+ ```shell
+ curl http://localhost:8080
+ ```
+
## Deploying Serverless applications
> Introduced in GitLab 11.5.
+Serverless applications are the building block of serverless functions. They are useful in scenarios where an existing
+runtime does not meet the needs of an application, such as one written in a language that has no runtime available. Note
+though that serverless applications should be stateless!
+
NOTE: **Note:**
You can reference and import the sample [Knative Ruby App](https://gitlab.com/knative-examples/knative-ruby-app) to get started.
diff --git a/doc/user/project/img/code_owners_approval_new_protected_branch_v12_4.png b/doc/user/project/img/code_owners_approval_new_protected_branch_v12_4.png
index f813b60dcd9..f813b60dcd9 100755..100644
--- a/doc/user/project/img/code_owners_approval_new_protected_branch_v12_4.png
+++ b/doc/user/project/img/code_owners_approval_new_protected_branch_v12_4.png
Binary files differ
diff --git a/doc/user/project/img/code_owners_approval_protected_branch_v12_4.png b/doc/user/project/img/code_owners_approval_protected_branch_v12_4.png
index 59da6874d14..59da6874d14 100755..100644
--- a/doc/user/project/img/code_owners_approval_protected_branch_v12_4.png
+++ b/doc/user/project/img/code_owners_approval_protected_branch_v12_4.png
Binary files differ
diff --git a/doc/workflow/time_tracking/img/time_tracking_example_v12_2.png b/doc/user/project/img/time_tracking_example_v12_2.png
index 31d8c490ed1..31d8c490ed1 100644
--- a/doc/workflow/time_tracking/img/time_tracking_example_v12_2.png
+++ b/doc/user/project/img/time_tracking_example_v12_2.png
Binary files differ
diff --git a/doc/workflow/time_tracking/img/time_tracking_sidebar_v8_16.png b/doc/user/project/img/time_tracking_sidebar_v8_16.png
index 22124afed6f..22124afed6f 100644
--- a/doc/workflow/time_tracking/img/time_tracking_sidebar_v8_16.png
+++ b/doc/user/project/img/time_tracking_sidebar_v8_16.png
Binary files differ
diff --git a/doc/user/project/import/gitea.md b/doc/user/project/import/gitea.md
index f883e4474e2..94ab9d9195b 100644
--- a/doc/user/project/import/gitea.md
+++ b/doc/user/project/import/gitea.md
@@ -75,7 +75,5 @@ You also can:
![Gitea importer page](img/import_projects_from_gitea_importer_v12_3.png)
----
-
You can also choose a different name for the project and a different namespace,
if you have the privileges to do so.
diff --git a/doc/user/project/import/github.md b/doc/user/project/import/github.md
index 0aeca7f73ad..9b98c52c4b8 100644
--- a/doc/user/project/import/github.md
+++ b/doc/user/project/import/github.md
@@ -125,7 +125,7 @@ your GitHub repositories are listed.
## Mirroring and pipeline status sharing
-Depending your GitLab tier, [project mirroring](../../../workflow/repository_mirroring.md) can be set up to keep
+Depending your GitLab tier, [project mirroring](../repository/repository_mirroring.md) can be set up to keep
your imported project in sync with its GitHub copy.
Additionally, you can configure GitLab to send pipeline status updates back GitHub with the
diff --git a/doc/user/project/index.md b/doc/user/project/index.md
index 7ae288996da..c173d3d3e11 100644
--- a/doc/user/project/index.md
+++ b/doc/user/project/index.md
@@ -26,6 +26,7 @@ When you create a project in GitLab, you'll have access to a large number of
from messing with history or pushing code without review
- [Protected tags](protected_tags.md): Control over who has
permission to create tags, and prevent accidental update or deletion
+ - [Repository mirroring](repository/repository_mirroring.md)
- [Signing commits](gpg_signed_commits/index.md): use GPG to sign your commits
- [Deploy tokens](deploy_tokens/index.md): Manage project-based deploy tokens that allow permanent access to the repository and Container Registry.
- [Web IDE](web_ide/index.md)
@@ -44,7 +45,7 @@ When you create a project in GitLab, you'll have access to a large number of
- [Review Apps](../../ci/review_apps/index.md): Live preview the results
of the changes proposed in a merge request in a per-branch basis
- [Labels](labels.md): Organize issues and merge requests by labels
-- [Time Tracking](../../workflow/time_tracking.md): Track estimate time
+- [Time Tracking](time_tracking.md): Track estimate time
and time spent on
the conclusion of an issue or merge request
- [Milestones](milestones/index.md): Work towards a target date
diff --git a/doc/user/project/integrations/generic_alerts.md b/doc/user/project/integrations/generic_alerts.md
index ec43696fdee..62310dd9177 100644
--- a/doc/user/project/integrations/generic_alerts.md
+++ b/doc/user/project/integrations/generic_alerts.md
@@ -1,6 +1,6 @@
# Generic alerts integration **(ULTIMATE)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/13203) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.3.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/13203) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.4.
GitLab can accept alerts from any source via a generic webhook receiver.
When you set up the generic alerts integration, a unique endpoint will
@@ -16,7 +16,7 @@ authored by the GitLab Alert Bot.
To set up the generic alerts integration:
1. Navigate to **Settings > Integrations** in a project.
-1. Click on **Alert endpoint**.
+1. Click on **Alerts endpoint**.
1. Toggle the **Active** alert setting. The `URL` and `Authorization Key` for the webhook configuration can be found there.
## Customizing the payload
@@ -37,12 +37,12 @@ Example request:
```sh
curl --request POST \
--data '{"title": "Incident title"}' \
- --header "Authorization: Bearer <autorization_key>" \
+ --header "Authorization: Bearer <authorization_key>" \
--header "Content-Type: application/json" \
<url>
```
-The `<autorization_key>` and `<url>` values can be found when [setting up generic alerts](#setting-up-generic-alerts).
+The `<authorization_key>` and `<url>` values can be found when [setting up generic alerts](#setting-up-generic-alerts).
Example payload:
diff --git a/doc/user/project/integrations/gitlab_slack_application.md b/doc/user/project/integrations/gitlab_slack_application.md
index 50adb5993e5..c1e6f93de30 100644
--- a/doc/user/project/integrations/gitlab_slack_application.md
+++ b/doc/user/project/integrations/gitlab_slack_application.md
@@ -31,7 +31,7 @@ integration settings.
Keep in mind that you need to have the appropriate permissions for your Slack
team in order to be able to install a new application, read more in Slack's
-docs on [Adding an app to your team][slack-docs].
+docs on [Adding an app to your team](https://slack.com/help/articles/202035138).
To enable GitLab's service for your Slack team:
@@ -60,6 +60,5 @@ project, you would do:
/gitlab gitlab-org/gitlab issue show 1001
```
-[slack-docs]: https://get.slack.help/hc/en-us/articles/202035138-Adding-apps-to-your-team
[slash commands]: ../../../integration/slash_commands.md
[slack-manual]: slack_slash_commands.md
diff --git a/doc/user/project/integrations/img/embed_metrics_issue_template.png b/doc/user/project/integrations/img/embed_metrics_issue_template.png
new file mode 100644
index 00000000000..3c6a243e5c1
--- /dev/null
+++ b/doc/user/project/integrations/img/embed_metrics_issue_template.png
Binary files differ
diff --git a/doc/user/project/integrations/img/grafana_panel_v12_5.png b/doc/user/project/integrations/img/grafana_panel_v12_5.png
new file mode 100644
index 00000000000..18c17b910cd
--- /dev/null
+++ b/doc/user/project/integrations/img/grafana_panel_v12_5.png
Binary files differ
diff --git a/doc/user/project/integrations/img/grafana_sharing_dialog_v12_5.png b/doc/user/project/integrations/img/grafana_sharing_dialog_v12_5.png
new file mode 100644
index 00000000000..fae62dd50df
--- /dev/null
+++ b/doc/user/project/integrations/img/grafana_sharing_dialog_v12_5.png
Binary files differ
diff --git a/doc/user/project/integrations/img/heatmap_panel_type.png b/doc/user/project/integrations/img/heatmap_panel_type.png
new file mode 100644
index 00000000000..a2b3911ec68
--- /dev/null
+++ b/doc/user/project/integrations/img/heatmap_panel_type.png
Binary files differ
diff --git a/doc/user/project/integrations/img/http_proxy_access_v12_5.png b/doc/user/project/integrations/img/http_proxy_access_v12_5.png
new file mode 100644
index 00000000000..0036a916a12
--- /dev/null
+++ b/doc/user/project/integrations/img/http_proxy_access_v12_5.png
Binary files differ
diff --git a/doc/user/project/integrations/img/prometheus_dashboard_anomaly_panel_type.png b/doc/user/project/integrations/img/prometheus_dashboard_anomaly_panel_type.png
new file mode 100644
index 00000000000..5cba6fa9038
--- /dev/null
+++ b/doc/user/project/integrations/img/prometheus_dashboard_anomaly_panel_type.png
Binary files differ
diff --git a/doc/user/project/integrations/img/rendered_grafana_embed_v12_5.png b/doc/user/project/integrations/img/rendered_grafana_embed_v12_5.png
new file mode 100644
index 00000000000..6cabe4193bd
--- /dev/null
+++ b/doc/user/project/integrations/img/rendered_grafana_embed_v12_5.png
Binary files differ
diff --git a/doc/user/project/integrations/img/select_query_variables_v12_5.png b/doc/user/project/integrations/img/select_query_variables_v12_5.png
new file mode 100644
index 00000000000..23503577327
--- /dev/null
+++ b/doc/user/project/integrations/img/select_query_variables_v12_5.png
Binary files differ
diff --git a/doc/user/project/integrations/jira.md b/doc/user/project/integrations/jira.md
index 6d2a0563ec1..874a1092b73 100644
--- a/doc/user/project/integrations/jira.md
+++ b/doc/user/project/integrations/jira.md
@@ -59,7 +59,7 @@ When connecting to **Jira Cloud**, which supports authentication via API token,
> higher is required.
> - GitLab 8.14 introduced a new way to integrate with Jira which greatly simplified
> the configuration options you have to enter. If you are using an older version,
-> [follow this documentation][jira-repo-old-docs].
+> [follow this documentation](https://gitlab.com/gitlab-org/gitlab/blob/8-13-stable-ee/doc/project_services/jira.md).
> - In order to support Oracle's Access Manager, GitLab will send additional cookies
> to enable Basic Auth. The cookie being added to each request is `OBBasicAuth` with
> a value of `fromDialog`.
@@ -205,4 +205,3 @@ authenticate with the Jira site. You will need to log in to your Jira instance
and complete the CAPTCHA.
[services-templates]: services_templates.md
-[jira-repo-old-docs]: https://gitlab.com/gitlab-org/gitlab/blob/8-13-stable/doc/project_services/jira.md
diff --git a/doc/user/project/integrations/project_services.md b/doc/user/project/integrations/project_services.md
index e385ee53636..315039f82b3 100644
--- a/doc/user/project/integrations/project_services.md
+++ b/doc/user/project/integrations/project_services.md
@@ -58,7 +58,7 @@ Click on the service links to see further configuration instructions and details
## Push hooks limit
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/31009) in GitLab 12.4.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/17874) in GitLab 12.4.
If a single push includes changes to more than three branches or tags, services
supported by `push_hooks` and `tag_push_hooks` events won't be executed.
diff --git a/doc/user/project/integrations/prometheus.md b/doc/user/project/integrations/prometheus.md
index d7666d00e76..d3d4afefb59 100644
--- a/doc/user/project/integrations/prometheus.md
+++ b/doc/user/project/integrations/prometheus.md
@@ -117,7 +117,7 @@ You can view the performance dashboard for an environment by [clicking on the mo
Custom metrics can be monitored by adding them on the monitoring dashboard page. Once saved, they will be displayed on the environment performance dashboard provided that either:
-- A [connected Kubernetes cluster](../clusters/index.md#adding-and-removing-clusters) with the environment scope of `*` is used and [Prometheus installed on the cluster](#enabling-prometheus-integration), or
+- A [connected Kubernetes cluster](../clusters/add_remove_clusters.md) with the environment scope of `*` is used and [Prometheus installed on the cluster](#enabling-prometheus-integration)
- Prometheus is [manually configured](#manual-configuration-of-prometheus).
![Add New Metric](img/prometheus_add_metric.png)
@@ -139,7 +139,7 @@ GitLab supports a limited set of [CI variables](../../../ci/variables/README.htm
- CI_ENVIRONMENT_SLUG
- KUBE_NAMESPACE
-To specify a variable in a query, enclose it in curly braces with a leading percent. For example: `%{ci_environment_slug}`.
+To specify a variable in a query, enclose it in quotation marks with curly braces with a leading percent. For example: `"%{ci_environment_slug}"`.
### Defining custom dashboards per project
@@ -211,11 +211,11 @@ The following tables outline the details of expected properties.
| Property | Type | Required | Description |
| ------ | ------ | ------ | ------- |
-| `type` | enum | no, defaults to `area-chart` | Specifies the chart type to use, can be `area-chart` or `line-chart` |
+| `type` | enum | no, defaults to `area-chart` | Specifies the chart type to use, can be: `area-chart`, `line-chart` or `anomaly-chart`. |
| `title` | string | yes | Heading for the panel. |
| `y_label` | string | no, but highly encouraged | Y-Axis label for the panel. |
| `weight` | number | no, defaults to order in file | Order to appear within the grouping. Lower number means higher priority, which will be higher on the page. Numbers do not need to be consecutive. |
-| `metrics` | array | yes | The metrics which should be displayed in the panel. |
+| `metrics` | array | yes | The metrics which should be displayed in the panel. Any number of metrics can be displayed when `type` is `area-chart` or `line-chart`, whereas only 3 can be displayed when `type` is `anomaly-chart`. |
**Metrics (`metrics`) properties:**
@@ -231,20 +231,20 @@ The following tables outline the details of expected properties.
The below panel types are supported in monitoring dashboards.
-##### Area
+##### Area or Line Chart
-To add an area panel type to a dashboard, look at the following sample dashboard file:
+To add an area chart panel type to a dashboard, look at the following sample dashboard file:
```yaml
dashboard: 'Dashboard Title'
panel_groups:
- group: 'Group Title'
panels:
- - type: area-chart
- title: "Chart Title"
+ - type: area-chart # or line-chart
+ title: 'Area Chart Title'
y_label: "Y-Axis"
metrics:
- - id: 10
+ - id: area_http_requests_total
query_range: 'http_requests_total'
label: "Metric of Ages"
unit: "count"
@@ -255,10 +255,52 @@ Note the following properties:
| Property | Type | Required | Description |
| ------ | ------ | ------ | ------ |
| type | string | no | Type of panel to be rendered. Optional for area panel types |
-| query_range | yes | required | For area panel types, you must use a [range query](https://prometheus.io/docs/prometheus/latest/querying/api/#range-queries) |
+| query_range | string | required | For area panel types, you must use a [range query](https://prometheus.io/docs/prometheus/latest/querying/api/#range-queries) |
![area panel type](img/prometheus_dashboard_area_panel_type.png)
+##### Anomaly chart
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/16530) in GitLab 12.5.
+
+To add an anomaly chart panel type to a dashboard, add add a panel with *exactly* 3 metrics.
+
+The first metric represents the current state, and the second and third metrics represent the upper and lower limit respectively:
+
+```yaml
+dashboard: 'Dashboard Title'
+panel_groups:
+ - group: 'Group Title'
+ panels:
+ - type: anomaly-chart
+ title: "Chart Title"
+ y_label: "Y-Axis"
+ metrics:
+ - id: anomaly_requests_normal
+ query_range: 'http_requests_total'
+ label: "# of Requests"
+ unit: "count"
+ metrics:
+ - id: anomaly_requests_upper_limit
+ query_range: 10000
+ label: "Max # of requests"
+ unit: "count"
+ metrics:
+ - id: anomaly_requests_lower_limit
+ query_range: 2000
+ label: "Min # of requests"
+ unit: "count"
+```
+
+Note the following properties:
+
+| Property | Type | Required | Description |
+| ------ | ------ | ------ | ------ |
+| type | string | required | Must be `anomaly-chart` for anomaly panel types |
+| query_range | yes | required | For anomaly panel types, you must use a [range query](https://prometheus.io/docs/prometheus/latest/querying/api/#range-queries) in every metric. |
+
+![anomaly panel type](img/prometheus_dashboard_anomaly_panel_type.png)
+
##### Single Stat
To add a single stat panel type to a dashboard, look at the following sample dashboard file:
@@ -286,6 +328,42 @@ Note the following properties:
![single stat panel type](img/prometheus_dashboard_single_stat_panel_type.png)
+##### Heatmaps
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/30581) in GitLab 12.5.
+
+To add a heatmap panel type to a dashboard, look at the following sample dashboard file:
+
+```yaml
+dashboard: 'Dashboard Title'
+panel_groups:
+ - group: 'Group Title'
+ panels:
+ - title: "Heatmap"
+ type: "heatmap"
+ metrics:
+ - id: 10
+ query: 'sum(rate(nginx_upstream_responses_total{upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"}[60m])) by (status_code)'
+ unit: req/sec
+ label: "Status code"
+```
+
+Note the following properties:
+
+| Property | Type | Required | Description |
+| ------ | ------ | ------ | ------ |
+| type | string | yes | Type of panel to be rendered. For heatmap panel types, set to `heatmap` |
+| query_range | yes | yes | For area panel types, you must use a [range query](https://prometheus.io/docs/prometheus/latest/querying/api/#range-queries) |
+
+![heatmap panel type](img/heatmap_panel_type.png)
+
+### View and edit the source file of a custom dashboard
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/34779) in GitLab 12.5.
+
+When viewing a custom dashboard of a project, you can view the original
+`.yml` file by clicking on **Edit dashboard** button.
+
### Downloading data as CSV
Data from Prometheus charts on the metrics dashboard can be downloaded as CSV.
@@ -332,9 +410,12 @@ receivers:
...
```
+In order for GitLab to associate your alerts with an [environment](../../../ci/environments.md), you need to configure a `gitlab_environment_name` label on the alerts you set up in Prometheus. The value of this should match the name of your Environment in GitLab.
+
### Taking action on incidents **(ULTIMATE)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/4925) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.11.
+>- [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/4925) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.11.
+>- [From GitLab Ultimate 12.5](https://gitlab.com/gitlab-org/gitlab/issues/13401), when GitLab receives a recovery alert, it will automatically close the associated issue.
Alerts can be used to trigger actions, like open an issue automatically (enabled by default since `12.1`). To configure the actions:
@@ -355,6 +436,8 @@ Once enabled, an issue will be opened automatically when an alert is triggered w
- Optional list of attached annotations extracted from `annotations/*`
- Alert [GFM](../../markdown.md): GitLab Flavored Markdown from `annotations/gitlab_incident_markdown`
+When GitLab receives a **Recovery Alert**, it will automatically close the associated issue. This action will be recorded as a system message on the issue indicated that it was closed automatically by the GitLab Alert bot.
+
To further customize the issue, you can add labels, mentions, or any other supported [quick action](../quick_actions.md) in the selected issue template, which will apply to all incidents. To limit quick actions or other information to only specific types of alerts, use the `annotations/gitlab_incident_markdown` field.
Since [version 12.2](https://gitlab.com/gitlab-org/gitlab-foss/issues/63373), GitLab will tag each incident issue with the `incident` label automatically. If the label does not yet exist, it will be created automatically as well.
@@ -389,6 +472,8 @@ Prometheus server.
## Embedding metric charts within GitLab Flavored Markdown
+### Embedding GitLab-managed Kubernetes metrics
+
> [Introduced][ce-29691] in GitLab 12.2.
It is possible to display metrics charts within [GitLab Flavored Markdown](../../markdown.md#gitlab-flavored-markdown-gfm).
@@ -414,9 +499,19 @@ The following requirements must be met for the metric to unfurl:
![Embedded Metrics](img/embed_metrics.png)
-### Embedding live Grafana charts
+### Embedding metrics in issue templates
+
+It is also possible to embed either the default dashboard metrics or individual metrics in issue templates. For charts to render side-by-side, links to the entire metrics dashboard or individual metrics should be separated by either a comma or a space.
+
+![Embedded Metrics in issue templates](img/embed_metrics_issue_template.png)
+
+### Embedding Grafana charts
-It is also possible to embed live [Grafana](https://docs.gitlab.com/omnibus/settings/grafana.html) charts within issues, as a [Direct Linked Rendered Image](https://grafana.com/docs/reference/sharing/#direct-link-rendered-image).
+Grafana metrics can be embedded in [GitLab Flavored Markdown](../../markdown.md).
+
+#### Embedding charts via Grafana Rendered Images
+
+It is possible to embed live [Grafana](https://docs.gitlab.com/omnibus/settings/grafana.html) charts in issues, as a [direct linked rendered image](https://grafana.com/docs/reference/sharing/#direct-link-rendered-image).
The sharing dialog within Grafana provides the link, as highlighted below.
@@ -435,6 +530,41 @@ This will render like so:
<img src="https://dashboards.gitlab.com/render/d-solo/RZmbBr7mk/gitlab-triage?orgId=1&refresh=30s&var-env=gprd&var-environment=gprd&var-prometheus=prometheus-01-inf-gprd&var-prometheus_app=prometheus-app-01-inf-gprd&var-backend=All&var-type=All&var-stage=main&panelId=1247&width=1000&height=300"/>
+#### Embedding charts via integration with Grafana HTTP API
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/31376) in GitLab 12.5.
+
+Each project can support integration with one Grafana instance. This configuration allows a user to copy a link to a panel in Grafana, then paste it into a GitLab markdown field. The chart will be rendered in the GitLab chart format.
+
+Prerequisites for embedding from a Grafana instance:
+
+1. The datasource must be a Prometheus instance.
+1. The datasource must be proxyable, so the HTTP Access setting should be set to `Server`.
+
+![HTTP Proxy Access](img/http_proxy_access_v12_5.png)
+
+##### Setting up the Grafana integration
+
+1. [Generate an Admin-level API Token in Grafana.](https://grafana.com/docs/http_api/auth/#create-api-token)
+1. In your GitLab project, navigate to **Settings > Operations > Grafana Authentication**.
+1. To enable the integration, check the "Active" checkbox.
+1. For "Grafana URL", enter the base URL of the Grafana instance.
+1. For "API Token", enter the Admin API Token you just generated.
+1. Click **Save Changes**.
+
+##### Generating a link to a chart
+
+1. In Grafana, navigate to the dashboard you wish to embed a panel from.
+ ![Grafana Metric Panel](img/grafana_panel_v12_5.png)
+1. In the upper-left corner of the page, select a specific value for each variable required for the queries in the chart.
+ ![Select Query Variables](img/select_query_variables_v12_5.png)
+1. In Grafana, click on a panel's title, then click **Share** to open the panel's sharing dialog to the **Link** tab.
+1. If your Prometheus queries use Grafana's custom template variables, ensure that "Template variables" and "Current time range" options are toggled to **On**. Of Grafana global template variables, only `$__interval`, `$__from`, and `$__to` are currently supported.
+ ![Grafana Sharing Dialog](img/grafana_sharing_dialog_v12_5.png)
+1. Click **Copy** to copy the URL to the clipboard.
+1. In GitLab, paste the URL into a markdown field and save. The chart will take a few moments to render.
+ ![GitLab Rendered Grafana Panel](img/rendered_grafana_embed_v12_5.png)
+
## Troubleshooting
If the "No data found" screen continues to appear, it could be due to:
diff --git a/doc/user/project/integrations/prometheus_library/nginx_ingress.md b/doc/user/project/integrations/prometheus_library/nginx_ingress.md
index d630956c109..93f6dbb0302 100644
--- a/doc/user/project/integrations/prometheus_library/nginx_ingress.md
+++ b/doc/user/project/integrations/prometheus_library/nginx_ingress.md
@@ -30,7 +30,7 @@ For other deployments, there is [some configuration](#manually-setting-up-nginx-
### About managed NGINX Ingress deployments
-NGINX Ingress is deployed into the `gitlab-managed-apps` namespace, using the [official Helm chart](https://github.com/helm/charts/tree/master/stable/nginx-ingress). NGINX Ingress will be [externally reachable via the Load Balancer's Endpoint](../../clusters/index.md#getting-the-external-endpoint).
+NGINX Ingress is deployed into the `gitlab-managed-apps` namespace, using the [official Helm chart](https://github.com/helm/charts/tree/master/stable/nginx-ingress). NGINX Ingress will be [externally reachable via the Load Balancer's Endpoint](../../../clusters/applications.md#ingress).
NGINX is configured for Prometheus monitoring, by setting:
diff --git a/doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md b/doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md
index 83eac44666c..a1dcb105196 100644
--- a/doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md
+++ b/doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md
@@ -30,7 +30,7 @@ For other deployments, there is [some configuration](#manually-setting-up-nginx-
### About managed NGINX Ingress deployments
-NGINX Ingress is deployed into the `gitlab-managed-apps` namespace, using the [official Helm chart](https://github.com/helm/charts/tree/master/stable/nginx-ingress). NGINX Ingress will be [externally reachable via the Load Balancer's Endpoint](../../clusters/index.md#getting-the-external-endpoint).
+NGINX Ingress is deployed into the `gitlab-managed-apps` namespace, using the [official Helm chart](https://github.com/helm/charts/tree/master/stable/nginx-ingress). NGINX Ingress will be [externally reachable via the Load Balancer's Endpoint](../../../clusters/applications.md#ingress).
NGINX is configured for Prometheus monitoring, by setting:
diff --git a/doc/user/project/issue_board.md b/doc/user/project/issue_board.md
index 103d50a94e8..403972941b2 100644
--- a/doc/user/project/issue_board.md
+++ b/doc/user/project/issue_board.md
@@ -287,7 +287,7 @@ Different issue board features are available in different [GitLab tiers](https:/
| Tier | Number of Project Issue Boards | Number of Group Issue Boards | Configurable Issue Boards | Assignee Lists |
|----------|--------------------------------|------------------------------|---------------------------|----------------|
-| Core / Free | 1 | 1 | No | No |
+| Core / Free | Multiple | 1 | No | No |
| Starter / Bronze | Multiple | 1 | Yes | No |
| Premium / Silver | Multiple | Multiple | Yes | Yes |
| Ultimate / Gold | Multiple | Multiple | Yes | Yes |
diff --git a/doc/user/project/issues/associate_zoom_meeting.md b/doc/user/project/issues/associate_zoom_meeting.md
new file mode 100644
index 00000000000..24775204c9f
--- /dev/null
+++ b/doc/user/project/issues/associate_zoom_meeting.md
@@ -0,0 +1,42 @@
+# Associate a Zoom meeting with an issue
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/16609) in GitLab 12.4.
+
+In order to communicate synchronously for incidents management,
+GitLab allows to associate a Zoom meeting with an issue.
+Once you start a Zoom call for a fire-fight, you need a way to
+associate the conference call with an issue, so that your team
+members can join swiftly without requesting a link.
+
+## Adding a zoom meeting to an issue
+
+To associate a zoom meeting with an issue, you can use GitLab's
+[quick actions](../quick_actions.md#quick-actions-for-issues-merge-requests-and-epics).
+
+In an issue, leave a comment using the `/zoom` quick action followed by a valid Zoom link:
+
+```sh
+/zoom https://zoom.us/j/123456789
+```
+
+If the Zoom meeting URL is valid and you have at least [Reporter permissions](../../permissions.md),
+a system alert will notify you that the addition of the meeting URL was successful.
+The issue's description will be automatically edited to include the Zoom link, and a button will
+appear right under the issue's title.
+
+![Link Zoom Call in Issue](img/zoom-quickaction-button.png)
+
+You are only allowed to attach a single Zoom meeting to an issue. If you attempt
+to add a second Zoom meeting using the `/zoom` quick action, it won't work, you
+need to [remove it](#removing-an-existing-zoom-meeting-from-an-issue) first.
+
+## Removing an existing Zoom meeting from an issue
+
+Similarly to adding a zoom meeting, you can remove it with a quick action:
+
+```sh
+/remove_zoom
+```
+
+If you have at least [Reporter permissions](../../permissions.md),
+a system alert will notify you that the meeting URL was successfully removed.
diff --git a/doc/user/project/issues/csv_export.md b/doc/user/project/issues/csv_export.md
index fb7fdde7b94..b97bcd47f61 100644
--- a/doc/user/project/issues/csv_export.md
+++ b/doc/user/project/issues/csv_export.md
@@ -67,8 +67,8 @@ Data will be encoded with a comma as the column delimiter, with `"` used to quot
| Milestone | Title of the issue milestone |
| Weight | Issue weight |
| Labels | Title of any labels joined with a `,` |
-| Time Estimate | [Time estimate](../../../workflow/time_tracking.md#estimates) in seconds |
-| Time Spent | [Time spent](../../../workflow/time_tracking.md#time-spent) in seconds |
+| Time Estimate | [Time estimate](../time_tracking.md#estimates) in seconds |
+| Time Spent | [Time spent](../time_tracking.md#time-spent) in seconds |
## Limitations
diff --git a/doc/user/project/issues/design_management.md b/doc/user/project/issues/design_management.md
index 169da7049a6..594f73dbfbe 100644
--- a/doc/user/project/issues/design_management.md
+++ b/doc/user/project/issues/design_management.md
@@ -22,24 +22,26 @@ For an overview, see the video [Design Management (GitLab 12.2)](https://www.you
## Requirements
Design Management requires
-[Large File Storage (LFS)](../../../workflow/lfs/manage_large_binaries_with_git_lfs.md)
+[Large File Storage (LFS)](../../../administration/lfs/manage_large_binaries_with_git_lfs.md)
to be enabled:
- For GitLab.com, LFS is already enabled.
- For self-managed instances, a GitLab administrator must have
- [enabled LFS globally](../../../workflow/lfs/lfs_administration.md).
+ [enabled LFS globally](../../../administration/lfs/lfs_administration.md).
- For both GitLab.com and self-managed instances: LFS must be enabled for the project itself.
If enabled globally, LFS will be enabled by default to all projects. To enable LFS on the
project level, navigate to your project's **Settings > General**, expand **Visibility, project features, permissions**
and enable **Git Large File Storage**.
+Design Management requires that projects are using
+[hashed storage](../../../administration/repository_storage_types.html#hashed-storage)
+(the default storage type since v10.0).
+
## Limitations
- Files uploaded must have a file extension of either `png`, `jpg`, `jpeg`, `gif`, `bmp`, `tiff` or `ico`.
The [`svg` extension is not yet supported](https://gitlab.com/gitlab-org/gitlab/issues/12771).
- Design uploads are limited to 10 files at a time.
-- Design Management is
- [not yet supported in the project export](https://gitlab.com/gitlab-org/gitlab/issues/11090).
- Design Management data
[isn't deleted when a project is destroyed](https://gitlab.com/gitlab-org/gitlab/issues/13429) yet.
- Design Management data [won't be moved](https://gitlab.com/gitlab-org/gitlab/issues/13426)
@@ -112,12 +114,16 @@ viewed by browsing previous versions.
## Adding annotations to designs
-When a design image is displayed, you can add annotations to it by clicking on
-the image. A badge is added to the image and a form is displayed to start a new
-discussion. For example:
+When a design is uploaded, you can add annotations by clicking on
+the image on the exact location you'd like to add the note to.
+A badge is added to the image identifying the annotation, from
+which you can start a new discussion:
![Starting a new discussion on design](img/adding_note_to_design_1.png)
-When submitted, the form saves a badge linked to the discussion on the image. Different discussions have different badge numbers. For example:
+Different discussions have different badge numbers:
![Discussions on design annotations](img/adding_note_to_design_2.png)
+
+From GitLab 12.5 on, new annotations will be outputted to the issue activity,
+so that everyone involved can participate in the discussion.
diff --git a/doc/user/project/issues/due_dates.md b/doc/user/project/issues/due_dates.md
index 240859651e2..b19d5dc1650 100644
--- a/doc/user/project/issues/due_dates.md
+++ b/doc/user/project/issues/due_dates.md
@@ -33,7 +33,7 @@ the icon and the date colored red. You can sort issues by those that are
![Issues with due dates in the issues index page](img/due_dates_issues_index_page.png)
-Due dates also appear in your [todos list](../../../workflow/todos.md).
+Due dates also appear in your [todos list](../../todos.md).
![Issues with due dates in the todos](img/due_dates_todos.png)
diff --git a/doc/workflow/issue_weight/issue.png b/doc/user/project/issues/img/issue_weight.png
index 3800b5940b8..3800b5940b8 100644
--- a/doc/workflow/issue_weight/issue.png
+++ b/doc/user/project/issues/img/issue_weight.png
Binary files differ
diff --git a/doc/user/project/issues/img/select_all_designs_v12_4.png b/doc/user/project/issues/img/select_all_designs_v12_4.png
deleted file mode 100644
index b08b04c1214..00000000000
--- a/doc/user/project/issues/img/select_all_designs_v12_4.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/issues/img/zoom-quickaction-button.png b/doc/user/project/issues/img/zoom-quickaction-button.png
index d6d691b2267..c95a56b43e8 100644
--- a/doc/user/project/issues/img/zoom-quickaction-button.png
+++ b/doc/user/project/issues/img/zoom-quickaction-button.png
Binary files differ
diff --git a/doc/user/project/issues/issue_data_and_actions.md b/doc/user/project/issues/issue_data_and_actions.md
index 01f4eb5b912..92da4235afa 100644
--- a/doc/user/project/issues/issue_data_and_actions.md
+++ b/doc/user/project/issues/issue_data_and_actions.md
@@ -41,7 +41,7 @@ after it is closed.
#### 2. To Do
-You can add issues to and remove issues from your [GitLab To-Do List](../../../workflow/todos.md).
+You can add issues to and remove issues from your [GitLab To-Do List](../../todos.md).
The button to do this has a different label depending on whether the issue is already on your To-Do List or not. If the issue is:
@@ -83,9 +83,9 @@ Select a [milestone](../milestones/index.md) to attribute that issue to.
#### 6. Time Tracking
-Use [GitLab Quick Actions](../quick_actions.md) to [track estimates and time spent on issues](../../../workflow/time_tracking.md).
-You can add an [estimate of the time it will take](../../../workflow/time_tracking.md#estimates)
-to resolve the issue, and also add [the time spent](../../../workflow/time_tracking.md#time-spent)
+Use [GitLab Quick Actions](../quick_actions.md) to [track estimates and time spent on issues](../time_tracking.md).
+You can add an [estimate of the time it will take](../time_tracking.md#estimates)
+to resolve the issue, and also add [the time spent](../time_tracking.md#time-spent)
on the resolution of the issue.
#### 7. Due date
@@ -109,7 +109,7 @@ from which you can select **Create new label**.
#### 9. Weight **(STARTER)**
-[Assign a weight](../../../workflow/issue_weight.md) to an issue.
+[Assign a weight](issue_weight.md) to an issue.
Larger values are used to indicate more effort is required to complete the issue. Only
positive values or zero are allowed.
@@ -131,7 +131,7 @@ or were mentioned in the description or threads.
#### 13. Notifications
-Click on the icon to enable/disable [notifications](../../../workflow/notifications.md#issue--epics--merge-request-events)
+Click on the icon to enable/disable [notifications](../../profile/notifications.md#issue--epics--merge-request-events)
for the issue. This will automatically enable if you participate in the issue in any way.
- **Enable**: If you are not a participant in the discussion on that issue, but
@@ -162,7 +162,7 @@ allowing many formatting options.
You can mention a user or a group present in your GitLab instance with `@username` or
`@groupname` and they will be notified via todos and email, unless they have disabled
all notifications in their profile settings. This is controlled in the
-[notification settings](../../../workflow/notifications.md).
+[notification settings](../../profile/notifications.md).
Mentions for yourself (the current logged in user), will be highlighted in a different
color, allowing you to easily see which comments involve you, helping you focus on
@@ -257,4 +257,4 @@ You can attach and remove Zoom meetings to issues using the `/zoom` and `/remove
Attaching a [Zoom](https://zoom.us) call an issue
results in a **Join Zoom meeting** button at the top of the issue, just under the header.
-![Link Zoom Call in Issue](img/zoom-quickaction-button.png)
+Read more how to [add or remove a zoom meeting](associate_zoom_meeting.md).
diff --git a/doc/user/project/issues/issue_weight.md b/doc/user/project/issues/issue_weight.md
new file mode 100644
index 00000000000..4b8d2318e9b
--- /dev/null
+++ b/doc/user/project/issues/issue_weight.md
@@ -0,0 +1,25 @@
+---
+disqus_identifier: 'https://docs.gitlab.com/ee/workflow/issue_weight.html'
+---
+
+# Issue weight **(STARTER)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/76) in [GitLab Starter](https://about.gitlab.com/pricing/) 8.3.
+
+When you have a lot of issues, it can be hard to get an overview.
+By adding a weight to each issue, you can get a better idea of how much time,
+value or complexity a given issue has or will cost.
+
+You can set the weight of an issue during its creation, by simply changing the
+value in the dropdown menu. You can set it to a non-negative integer
+value from 0, 1, 2, and so on. (The database stores a 4-byte value, so the
+upper bound is essentially limitless).
+You can remove weight from an issue
+as well.
+
+This value will appear on the right sidebar of an individual issue, as well as
+in the issues page next to a distinctive balance scale icon.
+
+As an added bonus, you can see the total sum of all issues on the milestone page.
+
+![issue page](img/issue_weight.png)
diff --git a/doc/user/project/labels.md b/doc/user/project/labels.md
index cfd6d4eaf4b..d8356abdd1c 100644
--- a/doc/user/project/labels.md
+++ b/doc/user/project/labels.md
@@ -210,8 +210,8 @@ The following can be filtered by labels:
## Subscribing to labels
From the project label list page and the group label list page, you can subscribe
-to [notifications](../../workflow/notifications.md) of a given label, to alert you
-that the label has been assigned to an epic, issue, and merge request.
+to [notifications](../profile/notifications.md) of a given label, to alert you
+that the label has been assigned to an epic, issue, or merge request.
![Labels subscriptions](img/labels_subscriptions_v12_1.png)
diff --git a/doc/user/project/merge_requests/code_quality.md b/doc/user/project/merge_requests/code_quality.md
index 92681e741de..69bdfe10e3f 100644
--- a/doc/user/project/merge_requests/code_quality.md
+++ b/doc/user/project/merge_requests/code_quality.md
@@ -66,6 +66,18 @@ will scan your source code for code quality issues. The report will be saved as
that you can later download and analyze. Due to implementation limitations we always
take the latest Code Quality artifact available.
+By default, report artifacts are not downloadable. If you need them downloadable on the
+job details page, you can add `gl-code-quality-report.json` to the artifact paths like so:
+
+```yaml
+include:
+ - template: Code-Quality.gitlab-ci.yml
+
+code_quality:
+ artifacts:
+ paths: [gl-code-quality-report.json]
+```
+
The included `code_quality` job is running in the `test` stage, so it needs to be included in your CI config, like so:
```yaml
@@ -91,7 +103,7 @@ old job definitions are still maintained they have been deprecated and may be re
in the next major release, GitLab 12.0. You are advised to update your current `.gitlab-ci.yml`
configuration to reflect that change.
-For GitLab 11.5 and earlier, the job should look like:
+For GitLab 11.5 and later, the job should look like:
```yaml
code_quality:
diff --git a/doc/user/project/merge_requests/creating_merge_requests.md b/doc/user/project/merge_requests/creating_merge_requests.md
new file mode 100644
index 00000000000..084ebf32a92
--- /dev/null
+++ b/doc/user/project/merge_requests/creating_merge_requests.md
@@ -0,0 +1,156 @@
+---
+type: index, reference
+---
+
+# Creating merge requests
+
+Merge requests are the primary method of making changes to files in a GitLab project.
+Changes are proposed by creating and submitting a merge request, which is then
+[reviewed, and accepted (or rejected)](reviewing_and_managing_merge_requests.md),
+all within GitLab.
+
+## Creating new merge requests
+
+You can start creating a new merge request by clicking the **New merge request** button
+on the **Merge Requests** page in a project. Then you must choose the source project and
+branch that contain your changes, and the target project and branch where you want to merge
+the changes into. Click on **Compare branches and continue** to go to the next step
+and start filling in the merge request details.
+
+When viewing the commits on a branch other than master in **Repository > Commits**, you
+can click on the **Create merge request** button, and a new merge request will be started
+using the current branch as the source, and `master` in the current project as the target.
+
+If you have recently pushed changes to GitLab, the **Create merge request** button will
+also appear in the top right of the:
+
+- **Project** page.
+- **Repository > Files** page.
+- **Merge Requests** page.
+
+In this case, the merge request will use the most recent branch you pushed changes
+to as the source branch, and `master` in the current project as the target.
+
+## Workflow for new merge requests
+
+On the **New Merge Request** page, you can start by filling in the title and description
+for the merge request. If there are are already commits on the branch, the title will
+be pre-filled with the first line of the first commit message, and the description will
+be pre-filled with any additional lines in the commit message. The title is the only
+field that is mandatory in all cases.
+
+From here, you can also:
+
+- Set the merge request as a [work in progress](work_in_progress_merge_requests.md).
+- Select the [assignee](#assignee), or [assignees](#multiple-assignees-starter). **(STARTER)**
+- Select a [milestone](../milestones/index.md).
+- Select [labels](../labels.md).
+- Add any [merge request dependencies](merge_request_dependencies.md). **(PREMIUM)**
+- Select [approval options](merge_request_approvals.md). **(STARTER)**
+- Verify the source and target branches are correct.
+- Enable the [delete source branch when merge request is accepted](#deleting-the-source-branch) option.
+- Enable the [squash commits when merge request is accepted](squash_and_merge.md) option.
+- If the merge request is from a fork, enable [Allow collaboration on merge requests across forks](allow_collaboration.md).
+
+Many of these can be set when pushing changes from the command line, with
+[Git push options](../push_options.md).
+
+### Merge requests to close issues
+
+If the merge request is being created to resolve an issue, you can add a note in the
+description which will set it to [automatically close the issue](../issues/managing_issues.md#closing-issues-automatically)
+when merged.
+
+If the issue is [confidential](../issues/confidential_issues.md), you may want to
+use a different workflow for [merge requests for confidential issues](../issues/confidential_issues.md#merge-requests-for-confidential-issues),
+to prevent confidential information from being exposed.
+
+## Assignee
+
+Choose an assignee to designate someone as the person responsible for the first
+[review of the merge request](reviewing_and_managing_merge_requests.md). Open the
+drop down box to search for the user you wish to assign, and the merge request will be
+added to their [assigned merge request list](../../search/index.md#issues-and-merge-requests).
+
+### Multiple assignees **(STARTER)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/2004) in [GitLab Starter 11.11](https://about.gitlab.com/pricing/).
+
+Multiple people often review merge requests at the same time. GitLab allows you to
+have multiple assignees for merge requests to indicate everyone that is reviewing or
+accountable for it.
+
+![multiple assignees for merge requests sidebar](img/multiple_assignees_for_merge_requests_sidebar.png)
+
+To assign multiple assignees to a merge request:
+
+1. From a merge request, expand the right sidebar and locate the **Assignees** section.
+1. Click on **Edit** and from the dropdown menu, select as many users as you want
+ to assign the merge request to.
+
+Similarly, assignees are removed by deselecting them from the same dropdown menu.
+
+It's also possible to manage multiple assignees:
+
+- When creating a merge request.
+- Using [quick actions](../quick_actions.md#quick-actions-for-issues-merge-requests-and-epics).
+
+## Deleting the source branch
+
+When creating a merge request, select the "Delete source branch when merge
+request accepted" option and the source branch will be deleted when the merge
+request is merged. To make this option enabled by default for all new merge
+requests, enable it in the [project's settings](../settings/index.md#merge-request-settings).
+
+This option is also visible in an existing merge request next to the merge
+request button and can be selected/deselected before merging. It's only visible
+to users with [Maintainer permissions](../../permissions.md) in the source project.
+
+If the user viewing the merge request does not have the correct permissions to
+delete the source branch and the source branch is set for deletion, the merge
+request widget will show the "Deletes source branch" text.
+
+![Delete source branch status](img/remove_source_branch_status.png)
+
+## Create new merge requests by email
+
+_This feature needs [incoming email](../../../administration/incoming_email.md)
+to be configured by a GitLab administrator to be available for CE/EE users, and
+it's available on GitLab.com._
+
+You can create a new merge request by sending an email to a user-specific email
+address. The address can be obtained on the merge requests page by clicking on
+a **Email a new merge request to this project** button. The subject will be
+used as the source branch name for the new merge request and the target branch
+will be the default branch for the project. The message body (if not empty)
+will be used as the merge request description. You need
+["Reply by email"](../../../administration/reply_by_email.md) enabled to use
+this feature. If it's not enabled to your instance, you may ask your GitLab
+administrator to do so.
+
+This is a private email address, generated just for you. **Keep it to yourself**
+as anyone who gets ahold of it can create issues or merge requests as if they were you.
+You can add this address to your contact list for easy access.
+
+![Create new merge requests by email](img/create_from_email.png)
+
+_In GitLab 11.7, we updated the format of the generated email address.
+However the older format is still supported, allowing existing aliases
+or contacts to continue working._
+
+### Adding patches when creating a merge request via e-mail
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/22723) in GitLab 11.5.
+
+You can add commits to the merge request being created by adding
+patches as attachments to the email. All attachments with a filename
+ending in `.patch` will be considered patches and they will be processed
+ordered by name.
+
+The combined size of the patches can be 2MB.
+
+If the source branch from the subject does not exist, it will be
+created from the repository's HEAD or the specified target branch to
+apply the patches. The target branch can be specified using the
+[`/target_branch` quick action](../quick_actions.md). If the source
+branch already exists, the patches will be applied on top of it.
diff --git a/doc/user/project/merge_requests/img/approvals_premium_project_edit_v12_3.png b/doc/user/project/merge_requests/img/approvals_premium_project_edit_v12_3.png
deleted file mode 100644
index bbb131e86e9..00000000000
--- a/doc/user/project/merge_requests/img/approvals_premium_project_edit_v12_3.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/merge_requests/img/approvals_premium_project_edit_v12_5.png b/doc/user/project/merge_requests/img/approvals_premium_project_edit_v12_5.png
new file mode 100644
index 00000000000..24c8c8f8c11
--- /dev/null
+++ b/doc/user/project/merge_requests/img/approvals_premium_project_edit_v12_5.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/mr_approvals_by_code_owners_v12_4.png b/doc/user/project/merge_requests/img/mr_approvals_by_code_owners_v12_4.png
index c704129685f..c704129685f 100755..100644
--- a/doc/user/project/merge_requests/img/mr_approvals_by_code_owners_v12_4.png
+++ b/doc/user/project/merge_requests/img/mr_approvals_by_code_owners_v12_4.png
Binary files differ
diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md
index 2ab7c3fb15b..1ca8c882ac7 100644
--- a/doc/user/project/merge_requests/index.md
+++ b/doc/user/project/merge_requests/index.md
@@ -1,5 +1,5 @@
---
-type: index, reference, concepts
+type: index, reference
---
# Merge requests
@@ -9,45 +9,9 @@ to source code that exist as commits on a given Git branch.
![Merge request view](img/merge_request.png)
-## Overview
-
-A Merge Request (**MR**) is the basis of GitLab as a code collaboration
-and version control platform.
-It is as simple as the name implies: a _request_ to _merge_ one branch into another.
-
-With GitLab merge requests, you can:
-
-- Compare the changes between two [branches](https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell#_git_branching)
-- [Review and discuss](../../discussions/index.md#threads) the proposed modifications inline
-- Live preview the changes when [Review Apps](../../../ci/review_apps/index.md) is configured for your project
-- Build, test, and deploy your code in a per-branch basis with built-in [GitLab CI/CD](../../../ci/README.md)
-- Prevent the merge request from being merged before it's ready with [WIP MRs](#work-in-progress-merge-requests)
-- View the deployment process through [Pipeline Graphs](../../../ci/pipelines.md#visualizing-pipelines)
-- [Automatically close the issue(s)](../../project/issues/managing_issues.md#closing-issues-automatically) that originated the implementation proposed in the merge request
-- Assign it to any registered user, and change the assignee how many times you need
-- Assign a [milestone](../../project/milestones/index.md) and track the development of a broader implementation
-- Organize your issues and merge requests consistently throughout the project with [labels](../../project/labels.md)
-- Add a time estimation and the time spent with that merge request with [Time Tracking](../../../workflow/time_tracking.md#time-tracking)
-- [Resolve merge conflicts from the UI](#resolve-conflicts)
-- Enable [fast-forward merge requests](#fast-forward-merge-requests)
-- Enable [semi-linear history merge requests](#semi-linear-history-merge-requests) as another security layer to guarantee the pipeline is passing in the target branch
-- [Create new merge requests by email](#create-new-merge-requests-by-email)
-- [Allow collaboration](allow_collaboration.md) so members of the target project can push directly to the fork
-- [Squash and merge](squash_and_merge.md) for a cleaner commit history
-
-With **[GitLab Enterprise Edition][ee]**, you can also:
-
-- Prepare a full review and submit it once it's ready with [Merge Request Reviews](../../discussions/index.md#merge-request-reviews-premium) **(PREMIUM)**
-- View the deployment process across projects with [Multi-Project Pipelines](../../../ci/multi_project_pipelines.md) **(PREMIUM)**
-- Request [approvals](merge_request_approvals.md) from your managers **(STARTER)**
-- Analyze the impact of your changes with [Code Quality reports](code_quality.md) **(STARTER)**
-- Manage the licenses of your dependencies with [License Compliance](../../application_security/license_compliance/index.md) **(ULTIMATE)**
-- Analyze your source code for vulnerabilities with [Static Application Security Testing](../../application_security/sast/index.md) **(ULTIMATE)**
-- Analyze your running web applications for vulnerabilities with [Dynamic Application Security Testing](../../application_security/dast/index.md) **(ULTIMATE)**
-- Analyze your dependencies for vulnerabilities with [Dependency Scanning](../../application_security/dependency_scanning/index.md) **(ULTIMATE)**
-- Analyze your Docker images for vulnerabilities with [Container Scanning](../../application_security/container_scanning/index.md) **(ULTIMATE)**
-- Determine the performance impact of changes with [Browser Performance Testing](#browser-performance-testing-premium) **(PREMIUM)**
-- Specify merge order dependencies with [Merge Request Dependencies](#merge-request-dependencies-premium) **(PREMIUM)**
+A Merge Request (**MR**) is the basis of GitLab as a code collaboration and version
+control platform. It is as simple as the name implies: a _request_ to _merge_ one
+branch into another.
## Use cases
@@ -58,8 +22,11 @@ A. Consider you are a software developer working in a team:
1. You work on the implementation optimizing code with [Code Quality reports](code_quality.md) **(STARTER)**
1. You verify your changes with [JUnit test reports](../../../ci/junit_test_reports.md) in GitLab CI/CD
1. You avoid using dependencies whose license is not compatible with your project with [License Compliance reports](../../application_security/license_compliance/index.md) **(ULTIMATE)**
-1. You request the [approval](#merge-request-approvals-starter) from your manager
-1. Your manager pushes a commit with their final review, [approves the merge request](merge_request_approvals.md), and set it to [merge when pipeline succeeds](#merge-when-pipeline-succeeds) (Merge Request Approvals are available in GitLab Starter)
+1. You request the [approval](merge_request_approvals.md) from your manager **(STARTER)**
+1. Your manager:
+ 1. Pushes a commit with their final review
+ 1. [Approves the merge request](merge_request_approvals.md) **(STARTER)**
+ 1. Sets it to [merge when pipeline succeeds](merge_when_pipeline_succeeds.md)
1. Your changes get deployed to production with [manual actions](../../../ci/yaml/README.md#whenmanual) for GitLab CI/CD
1. Your implementations were successfully shipped to your customer
@@ -71,547 +38,112 @@ B. Consider you're a web developer writing a webpage for your company's website:
1. You request your web designers for their implementation
1. You request the [approval](merge_request_approvals.md) from your manager **(STARTER)**
1. Once approved, your merge request is [squashed and merged](squash_and_merge.md), and [deployed to staging with GitLab Pages](https://about.gitlab.com/blog/2016/08/26/ci-deployment-and-environments/)
-1. Your production team [cherry picks](#cherry-pick-changes) the merge commit into production
-
-## Merge requests per project
-
-View all the merge requests within a project by navigating to **Project > Merge Requests**.
-
-When you access your project's merge requests, GitLab will present them in a list,
-and you can use the tabs available to quickly filter by open and closed. You can also [search and filter the results](../../search/index.md#issues-and-merge-requests-per-project).
-
-![Project merge requests list view](img/project_merge_requests_list_view.png)
-
-## Merge requests per group
-
-View merge requests in all projects in the group, including all projects of all descendant subgroups of the group. Navigate to **Group > Merge Requests** to view these merge requests. This view also has the open and closed merge requests tabs.
-
-You can [search and filter the results](../../search/index.md#issues-and-merge-requests-per-group) from here.
-
-![Group Issues list view](img/group_merge_requests_list_view.png)
-
-## Deleting the source branch
-
-When creating a merge request, select the "Delete source branch when merge
-request accepted" option and the source branch will be deleted when the merge
-request is merged.
-
-This option is also visible in an existing merge request next to the merge
-request button and can be selected/deselected before merging. It's only visible
-to users with [Maintainer permissions](../../permissions.md) in the source project.
-
-If the user viewing the merge request does not have the correct permissions to
-delete the source branch and the source branch is set for deletion, the merge
-request widget will show the "Deletes source branch" text.
-
-![Delete source branch status](img/remove_source_branch_status.png)
-
-## Allow collaboration on merge requests across forks
-
-When a user opens a merge request from a fork, they are given the option to allow
-upstream maintainers to collaborate with them on the source branch. This allows
-the maintainers of the upstream project to make small fixes or rebase branches
-before merging, reducing the back and forth of accepting community contributions.
-
-[Learn more about allowing upstream members to push to forks.](allow_collaboration.md)
+1. Your production team [cherry picks](cherry_pick_changes.md) the merge commit into production
+
+## Creating merge requests
+
+While making changes to files in the `master` branch of a repository is possible, it is not
+the common workflow. In most cases, a user will make changes in a [branch](https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell#_git_branching),
+then [create a merge request](creating_merge_requests.md) to request that the changes
+be merged into another branch (often the `master` branch).
+
+It is then [reviewed](#reviewing-and-managing-merge-requests), possibly updated after
+discussions and suggestions, and finally approved and merged into the target branch.
+Creating and reviewing merge requests is one of the most fundamental parts of working
+with GitLab.
+
+When [creating merge requests](creating_merge_requests.md), there are a number of features
+to be aware of:
+
+| Feature | Description |
+|-----------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| [Adding patches when creating a merge request via e-mail](creating_merge_requests.md#adding-patches-when-creating-a-merge-request-via-e-mail) | Add commits to a merge request created by e-mail, by adding patches as e-mail attachments. |
+| [Allow collaboration on merge requests across forks](allow_collaboration.md) | Allows the maintainers of an upstream project to collaborate on a fork, to make fixes or rebase branches before merging, reducing the back and forth of accepting community contributions. |
+| [Assignee](creating_merge_requests.md#assignee) | Add an assignee to indicate who is reviewing or accountable for it. |
+| [Automatic issue closing](../../project/issues/managing_issues.md#closing-issues-automatically) | Set a merge request to close defined issues automatically as soon as it is merged. |
+| [Create new merge requests by email](creating_merge_requests.md#create-new-merge-requests-by-email) | Create new merge requests by sending an email to a user-specific email address. |
+| [Deleting the source branch](creating_merge_requests.md#deleting-the-source-branch) | Select the "Delete source branch when merge request accepted" option and the source branch will be deleted when the merge request is merged. |
+| [Git push options](../push_options.md) | Use Git push options to create or update merge requests when pushing changes to GitLab with Git, without needing to use the GitLab interface. |
+| [Labels](../../project/labels.md) | Organize your issues and merge requests consistently throughout the project. |
+| [Merge request approvals](merge_request_approvals.md) **(STARTER)** | Set the number of necessary approvals and predefine a list of approvers that will need to approve every merge request in a project. |
+| [Merge Request dependencies](merge_request_dependencies.md) **(PREMIUM)** | Specify that a merge request depends on other merge requests, enforcing a desired order of merging. |
+| [Merge Requests for Confidential Issues](../issues/confidential_issues.md#merge-requests-for-confidential-issues) | Create merge requests to resolve confidential issues for preventing leakage or early release of sensitive data through regular merge requests. |
+| [Milestones](../../project/milestones/index.md) | Track merge requests to achieve a broader goal in a certain period of time. |
+| [Multiple assignees](creating_merge_requests.md#multiple-assignees-starter) **(STARTER)** | Have multiple assignees for merge requests to indicate everyone that is reviewing or accountable for it. |
+| [Squash and merge](squash_and_merge.md) | Squash all changes present in a merge request into a single commit when merging, to allow for a neater commit history. |
+| [Work In Progress merge requests](work_in_progress_merge_requests.md) | Prevent the merge request from being merged before it's ready |
+
+## Reviewing and managing merge requests
+
+Once a merge request has been [created](#creating-merge-requests) and submitted, there
+are many powerful features that you can use during the review process to make sure only
+the changes you want are merged into the repository.
+
+For managers and administrators, it is also important to be able to view and manage
+all the merge requests in a group or project. When [reviewing or managing merge requests](reviewing_and_managing_merge_requests.md),
+there are a number of features to be aware of:
+
+| Feature | Description |
+|-------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------|
+| [Bulk editing merge requests](../../project/bulk_editing.md) | Update the attributes of multiple merge requests simultaneously. |
+| [Cherry-pick changes](cherry_pick_changes.md) | Cherry-pick any commit in the UI by simply clicking the **Cherry-pick** button in a merged merge requests or a commit. |
+| [Commenting on any file line in merge requests](reviewing_and_managing_merge_requests.md#commenting-on-any-file-line-in-merge-requests) | Make comments directly on the exact line of a file you want to talk about. |
+| [Discuss changes in threads in merge requests reviews](../../discussions/index.md) | Keep track of the progress during a code review by making and resolving comments. |
+| [Fast-forward merge requests](fast_forward_merge.md) | For a linear Git history and a way to accept merge requests without creating merge commits |
+| [Find the merge request that introduced a change](versions.md) | When viewing the commit details page, GitLab will link to the merge request(s) containing that commit. |
+| [Ignore whitespace changes in Merge Request diff view](reviewing_and_managing_merge_requests.md#ignore-whitespace-changes-in-Merge-Request-diff-view) | Hide whitespace changes from the diff view for a to focus on more important changes. |
+| [Incrementally expand merge request diffs](reviewing_and_managing_merge_requests.md#incrementally-expand-merge-request-diffs) | View the content directly above or below a change, to better understand the context of that change. |
+| [Live preview with Review Apps](reviewing_and_managing_merge_requests.md#live-preview-with-review-apps) | Live preview the changes when Review Apps are configured for your project |
+| [Merge request diff file navigation](reviewing_and_managing_merge_requests.md#merge-request-diff-file-navigation) | Quickly jump to any changed file within the diff view. |
+| [Merge requests versions](versions.md) | Select and compare the different versions of merge request diffs |
+| [Merge when pipeline succeeds](merge_when_pipeline_succeeds.md) | Set a merge request that looks ready to merge to merge automatically when CI pipeline succeeds. |
+| [Perform a Review](../../discussions/index.md#merge-request-reviews-premium) **(PREMIUM)** | Start a review in order to create multiple comments on a diff and publish them once you're ready. |
+| [Pipeline status in merge requests](reviewing_and_managing_merge_requests.md#pipeline-status-in-merge-requests) | If using [GitLab CI/CD](../../../ci/README.md), see pre and post-merge pipelines information, and which deployments are in progress. |
+| [Post-merge pipeline status](reviewing_and_managing_merge_requests.md#post-merge-pipeline-status) | When a merge request is merged, see the post-merge pipeline status of the branch the merge request was merged into. |
+| [Resolve conflicts](resolve_conflicts.md) | GitLab can provide the option to resolve certain merge request conflicts in the GitLab UI. |
+| [Revert changes](revert_changes.md) | Revert changes from any commit from within a merge request. |
+| [Semi-linear history merge requests](reviewing_and_managing_merge_requests.md#semi-linear-history-merge-requests) | Enable semi-linear history merge requests as another security layer to guarantee the pipeline is passing in the target branch |
+| [Suggest changes](../../discussions/index.md#suggest-changes) | Add suggestions to change the content of merge requests directly into merge request threads, and easily apply them to the codebase directly from the UI. |
+| [Time Tracking](../time_tracking.md#time-tracking) | Add a time estimation and the time spent with that merge request. |
+| [View changes between file versions](reviewing_and_managing_merge_requests.md#view-changes-between-file-versions) | View what will be changed when a merge request is merged. |
+| [View group merge requests](reviewing_and_managing_merge_requests.md#view-merge-requests-for-all-projects-in-a-group) | List and view the merge requests within a group. |
+| [View project merge requests](reviewing_and_managing_merge_requests.md#view-project-merge-requests) | List and view the merge requests within a project. |
+
+## Testing and reports in merge requests
+
+GitLab has the ability to test the changes included in a merge request, and can display
+or link to useful information directly in the merge request page:
+
+| Feature | Description |
+|--------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| [Browser Performance Testing](browser_performance_testing.md) **(PREMIUM)** | Quickly determine the performance impact of pending code changes. |
+| [Code Quality](code_quality.md) **(STARTER)** | Analyze your source code quality using the [Code Climate](https://codeclimate.com/) analyzer and show the Code Climate report right in the merge request widget area. |
+| [Display arbitrary job artifacts](../../../ci/yaml/README.md#artifactsexpose_as) | Configure CI pipelines with the `artifacts:expose_as` parameter to directly link to selected [artifacts](../pipelines/job_artifacts.md) in merge requests. |
+| [GitLab CI/CD](../../../ci/README.md) | Build, test, and deploy your code in a per-branch basis with built-in CI/CD. |
+| [JUnit test reports](../../../ci/junit_test_reports.md) | Configure your CI jobs to use JUnit test reports, and let GitLab display a report on the merge request so that it’s easier and faster to identify the failure without having to check the entire job log. |
+| [Metrics Reports](../../../ci/metrics_reports.md) **(PREMIUM)** | Display the Metrics Report on the merge request so that it's fast and easy to identify changes to important metrics. |
+| [Multi-Project pipelines](../../../ci/multi_project_pipelines.md) **(PREMIUM)** | When you set up GitLab CI/CD across multiple projects, you can visualize the entire pipeline, including all cross-project interdependencies. |
+| [Pipelines for merge requests](../../../ci/merge_request_pipelines/index.md) | Customize a specific pipeline structure for merge requests in order to speed the cycle up by running only important jobs. |
+| [Pipeline Graphs](../../../ci/pipelines.md#visualizing-pipelines) | View the status of pipelines within the merge request, including the deployment process. |
+
+### Security Reports **(ULTIMATE)**
+
+In addition to the reports listed above, GitLab can do many types of [Security reports](../../application_security/index.md),
+generated by scanning and reporting any vulnerabilities found in your project:
+
+| Feature | Description |
+|-----------------------------------------------------------------------------------------|------------------------------------------------------------------|
+| [Container Scanning](../../application_security/container_scanning/index.md) | Analyze your Docker images for known vulnerabilities. |
+| [Dynamic Application Security Testing (DAST)](../../application_security/dast/index.md) | Analyze your running web applications for known vulnerabilities. |
+| [Dependency Scanning](../../application_security/dependency_scanning/index.md) | Analyze your dependencies for known vulnerabilities. |
+| [License Compliance](../../application_security/license_compliance/index.md) | Manage the licenses of your dependencies. |
+| [Static Application Security Testing (SAST)](../../application_security/sast/index.md) | Analyze your source code for known vulnerabilities. |
## Authorization for merge requests
There are two main ways to have a merge request flow with GitLab:
-1. Working with [protected branches][] in a single repository
+1. Working with [protected branches](../protected_branches.md) in a single repository
1. Working with forks of an authoritative project
[Learn more about the authorization for merge requests.](authorization_for_merge_requests.md)
-
-## Cherry-pick changes
-
-Cherry-pick any commit in the UI by simply clicking the **Cherry-pick** button
-in a merged merge requests or a commit.
-
-[Learn more about cherry-picking changes.](cherry_pick_changes.md)
-
-## Semi-linear history merge requests
-
-A merge commit is created for every merge, but the branch is only merged if
-a fast-forward merge is possible. This ensures that if the merge request build
-succeeded, the target branch build will also succeed after merging.
-
-Navigate to a project's settings, select the **Merge commit with semi-linear
-history** option under **Merge Requests: Merge method** and save your changes.
-
-## Fast-forward merge requests
-
-If you prefer a linear Git history and a way to accept merge requests without
-creating merge commits, you can configure this on a per-project basis.
-
-[Read more about fast-forward merge requests.](fast_forward_merge.md)
-
-## Merge when pipeline succeeds
-
-When reviewing a merge request that looks ready to merge but still has one or
-more CI jobs running, you can set it to be merged automatically when CI
-pipeline succeeds. This way, you don't have to wait for the pipeline to finish
-and remember to merge the request manually.
-
-[Learn more about merging when pipeline succeeds.](merge_when_pipeline_succeeds.md)
-
-## Resolve threads in merge requests reviews
-
-Keep track of the progress during a code review with resolving comments.
-Resolving comments prevents you from forgetting to address feedback and lets
-you hide threads that are no longer relevant.
-
-[Read more about resolving threads in merge requests reviews.](../../discussions/index.md)
-
-## View changes between file versions
-
-The **Changes** tab of a merge request shows the changes to files between branches or
-commits. This view of changes to a file is also known as a **diff**. By default, the diff view
-compares the file in the merge request branch and the file in the target branch.
-
-The diff view includes the following:
-
-- The file's name and path.
-- The number of lines added and deleted.
-- Buttons for the following options:
- - Toggle comments for this file; useful for inline reviews.
- - Edit the file in the merge request's branch.
- - Show full file, in case you want to look at the changes in context with the rest of the file.
- - View file at the current commit.
- - Preview the changes with [Review Apps](../../../ci/review_apps/index.md).
-- The changed lines, with the specific changes highlighted.
-
-![Example screenshot of a source code diff](img/merge_request_diff_v12_2.png)
-
-## Commenting on any file line in merge requests
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/13950) in GitLab 11.5.
-
-GitLab provides a way of leaving comments in any part of the file being changed
-in a Merge Request. To do so, click the **...** button in the gutter of the Merge Request diff UI to expand the diff lines and leave a comment, just as you would for a changed line.
-
-![Comment on any diff file line](img/comment-on-any-diff-line.png)
-
-## Perform a Review **(PREMIUM)**
-
-Start a review in order to create multiple comments on a diff and publish them once you're ready.
-Starting a review allows you to get all your thoughts in order and ensure you haven't missed anything
-before submitting all your comments.
-
-[Learn more about Merge Request Reviews](../../discussions/index.md#merge-request-reviews-premium)
-
-## Squash and merge
-
-GitLab allows you to squash all changes present in a merge request into a single
-commit when merging, to allow for a neater commit history.
-
-[Learn more about squash and merge.](squash_and_merge.md)
-
-## Suggest changes
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/18008) in GitLab 11.6.
-
-As a reviewer, you can add suggestions to change the content in
-merge request threads, and users with appropriate [permission](../../permissions.md)
-can easily apply them to the codebase directly from the UI. Read
-through the documentation on [Suggest changes](../../discussions/index.md#suggest-changes)
-to learn more.
-
-## Multiple assignees **(STARTER)**
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/2004)
-in [GitLab Starter 11.11](https://about.gitlab.com/pricing/).
-
-Multiple people often review merge requests at the same time. GitLab allows you to have multiple assignees for merge requests to indicate everyone that is reviewing or accountable for it.
-
-![multiple assignees for merge requests sidebar](img/multiple_assignees_for_merge_requests_sidebar.png)
-
-To assign multiple assignees to a merge request:
-
-1. From a merge request, expand the right sidebar and locate the **Assignees** section.
-1. Click on **Edit** and from the dropdown menu, select as many users as you want
- to assign the merge request to.
-
-Similarly, assignees are removed by deselecting them from the same dropdown menu.
-
-It's also possible to manage multiple assignees:
-
-- When creating a merge request.
-- Using [quick actions](../quick_actions.md#quick-actions-for-issues-merge-requests-and-epics).
-
-## Resolve conflicts
-
-When a merge request has conflicts, GitLab may provide the option to resolve
-those conflicts in the GitLab UI.
-
-[Learn more about resolving merge conflicts in the UI.](resolve_conflicts.md)
-
-## Create new merge requests by email
-
-_This feature needs [incoming email](../../../administration/incoming_email.md)
-to be configured by a GitLab administrator to be available for CE/EE users, and
-it's available on GitLab.com._
-
-You can create a new merge request by sending an email to a user-specific email
-address. The address can be obtained on the merge requests page by clicking on
-a **Email a new merge request to this project** button. The subject will be
-used as the source branch name for the new merge request and the target branch
-will be the default branch for the project. The message body (if not empty)
-will be used as the merge request description. You need
-["Reply by email"](../../../administration/reply_by_email.md) enabled to use
-this feature. If it's not enabled to your instance, you may ask your GitLab
-administrator to do so.
-
-This is a private email address, generated just for you. **Keep it to yourself**
-as anyone who gets ahold of it can create issues or merge requests as if they were you.
-You can add this address to your contact list for easy access.
-
-![Create new merge requests by email](img/create_from_email.png)
-
-_In GitLab 11.7, we updated the format of the generated email address.
-However the older format is still supported, allowing existing aliases
-or contacts to continue working._
-
-### Adding patches when creating a merge request via e-mail
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/22723) in GitLab 11.5.
-
-You can add commits to the merge request being created by adding
-patches as attachments to the email. All attachments with a filename
-ending in `.patch` will be considered patches and they will be processed
-ordered by name.
-
-The combined size of the patches can be 2MB.
-
-If the source branch from the subject does not exist, it will be
-created from the repository's HEAD or the specified target branch to
-apply the patches. The target branch can be specified using the
-[`/target_branch` quick action](../quick_actions.md). If the source
-branch already exists, the patches will be applied on top of it.
-
-## Use Git push options with merge requests
-
-Use [Git push options](../push_options.md) to create or update merge requests when
-pushing changes to GitLab with Git, without needing to use the GitLab interface.
-
-## Find the merge request that introduced a change
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/2383) in GitLab 10.5.
-
-When viewing the commit details page, GitLab will link to the merge request (or
-merge requests, if it's in more than one) containing that commit.
-
-This only applies to commits that are in the most recent version of a merge
-request - if a commit was in a merge request, then rebased out of that merge
-request, they will not be linked.
-
-[Read more about merge request versions](versions.md)
-
-## Revert changes
-
-GitLab implements Git's powerful feature to revert any commit with introducing
-a **Revert** button in merge requests and commit details.
-
-[Learn more about reverting changes in the UI](revert_changes.md)
-
-## Merge requests versions
-
-Every time you push to a branch that is tied to a merge request, a new version
-of merge request diff is created. When you visit a merge request that contains
-more than one pushes, you can select and compare the versions of those merge
-request diffs.
-
-[Read more about merge request versions](versions.md)
-
-## Work In Progress merge requests
-
-To prevent merge requests from accidentally being accepted before they're
-completely ready, GitLab blocks the "Accept" button for merge requests that
-have been marked as a **Work In Progress**.
-
-[Learn more about setting a merge request as "Work In Progress".](work_in_progress_merge_requests.md)
-
-## Merge Requests for Confidential Issues
-
-Create [merge requests to resolve confidential issues](../issues/confidential_issues.md#merge-requests-for-confidential-issues)
-for preventing leakage or early release of sensitive data through regular merge requests.
-
-## Merge request approvals **(STARTER)**
-
-> Included in [GitLab Starter](https://about.gitlab.com/product/).
-
-If you want to make sure every merge request is approved by one or more people,
-you can enforce this workflow by using merge request approvals. Merge request
-approvals allow you to set the number of necessary approvals and predefine a
-list of approvers that will need to approve every merge request in a project.
-
-[Read more about merge request approvals.](merge_request_approvals.md)
-
-## Code Quality **(STARTER)**
-
-> Introduced in [GitLab Starter](https://about.gitlab.com/product/) 9.3.
-
-If you are using [GitLab CI][ci], you can analyze your source code quality using
-the [Code Climate][cc] analyzer [Docker image][cd]. Going a step further, GitLab
-can show the Code Climate report right in the merge request widget area.
-
-[Read more about Code Quality reports.](code_quality.md)
-
-## Metrics Reports **(PREMIUM)**
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/9788) in [GitLab Premium](https://about.gitlab.com/product/) 11.10.
-Requires GitLab Runner 11.10 and above.
-
-If you are using [GitLab CI][ci], you can configure your job to output custom
-metrics and GitLab will display the Metrics Report on the merge request so
-that it's fast and easy to identify changes to important metrics.
-
-[Read more about Metrics Report](../../../ci/metrics_reports.md).
-
-## Browser Performance Testing **(PREMIUM)**
-
-> Introduced in [GitLab Premium](https://about.gitlab.com/product/) 10.3.
-
-If your application offers a web interface and you are using [GitLab CI/CD][ci], you can quickly determine the performance impact of pending code changes. GitLab uses [Sitespeed.io][sitespeed], a free and open source tool for measuring the performance of web sites, to analyze the performance of specific pages.
-
-GitLab runs the [Sitespeed.io container][sitespeed-container] and displays the difference in overall performance scores between the source and target branches.
-
-[Read more about Browser Performance Testing.](browser_performance_testing.md)
-
-## Merge Request Dependencies **(PREMIUM)**
-
-> Introduced in [GitLab Premium](https://about.gitlab.com/product/) 12.2.
-
-A single logical change may be split across several merge requests, across
-several projects. When this happens, the order in which MRs are merged is
-important.
-
-GitLab allows you to specify that a merge request depends on other MRs. With
-this relationship in place, the merge request cannot be merged until all of its
-dependencies have also been merged, helping to maintain the consistency of a
-single logical change.
-
-[Read more about merge request dependencies.](merge_request_dependencies.md)
-
-## Security reports **(ULTIMATE)**
-
-GitLab can scan and report any vulnerabilities found in your project.
-
-[Read more about security reports.](../../application_security/index.md)
-
-## JUnit test reports
-
-Configure your CI jobs to use JUnit test reports, and let GitLab display a report
-on the merge request so that it’s easier and faster to identify the failure
-without having to check the entire job log.
-
-[Read more about JUnit test reports](../../../ci/junit_test_reports.md).
-
-## Merge request diff file navigation
-
-When reviewing changes in the **Changes** tab the diff can be navigated using
-the file tree or file list. As you scroll through large diffs with many
-changes, you can quickly jump to any changed file using the file tree or file
-list.
-
-![Merge request diff file navigation](img/merge_request_diff_file_navigation.png)
-
-### Incrementally expand merge request diffs
-
-By default, the diff shows only the parts of a file which are changed.
-To view more unchanged lines above or below a change click on the
-**Expand up** or **Expand down** icons. You can also click on **Show all lines**
-to expand the entire file.
-
-![Incrementally expand merge request diffs](img/incrementally_expand_merge_request_diffs_v12_2.png)
-
-## Ignore whitespace changes in Merge Request diff view
-
-If you click the **Hide whitespace changes** button, you can see the diff
-without whitespace changes (if there are any). This is also working when on a
-specific commit page.
-
-![MR diff](img/merge_request_diff.png)
-
->**Tip:**
-You can append `?w=1` while on the diffs page of a merge request to ignore any
-whitespace changes.
-
-## Live preview with Review Apps
-
-If you configured [Review Apps](https://about.gitlab.com/product/review-apps/) for your project,
-you can preview the changes submitted to a feature-branch through a merge request
-in a per-branch basis. No need to checkout the branch, install and preview locally;
-all your changes will be available to preview by anyone with the Review Apps link.
-
-With GitLab's [Route Maps](../../../ci/review_apps/index.md#route-maps) set, the
-merge request widget takes you directly to the pages changed, making it easier and
-faster to preview proposed modifications.
-
-[Read more about Review Apps](../../../ci/review_apps/index.md).
-
-## Pipelines for merge requests
-
-When a developer updates a merge request, a pipeline should quickly report back
-its result to the developer, but often pipelines take long time to complete
-because general branch pipelines contain unnecessary jobs from the merge request standpoint.
-You can customize a specific pipeline structure for merge requests in order to
-speed the cycle up by running only important jobs.
-
-Learn more about [pipelines for merge requests](../../../ci/merge_request_pipelines/index.md).
-
-## Pipeline status in merge requests
-
-If you've set up [GitLab CI/CD](../../../ci/README.md) in your project,
-you will be able to see:
-
-- Both pre and post-merge pipelines and the environment information if any.
-- Which deployments are in progress.
-
-If there's an [environment](../../../ci/environments.md) and the application is
-successfully deployed to it, the deployed environment and the link to the
-Review App will be shown as well.
-
-### Post-merge pipeline status
-
-When a merge request is merged, you can see the post-merge pipeline status of
-the branch the merge request was merged into. For example, when a merge request
-is merged into the master branch and then triggers a deployment to the staging
-environment.
-
-Deployments that are ongoing will be shown, as well as the deploying/deployed state
-for environments. If it's the first time the branch is deployed, the link
-will return a `404` error until done. During the deployment, the stop button will
-be disabled. If the pipeline fails to deploy, the deployment info will be hidden.
-
-![Merge request pipeline](img/merge_request_pipeline.png)
-
-For more information, [read about pipelines](../../../ci/pipelines.md).
-
-## Bulk editing merge requests
-
-Find out about [bulk editing merge requests](../../project/bulk_editing.md).
-
-## Troubleshooting
-
-Sometimes things don't go as expected in a merge request, here are some
-troubleshooting steps.
-
-### Merge request cannot retrieve the pipeline status
-
-This can occur if Sidekiq doesn't pick up the changes fast enough.
-
-#### Sidekiq
-
-Sidekiq didn't process the CI state change fast enough. Please wait a few
-seconds and the status will update automatically.
-
-#### Bug
-
-Merge Request pipeline statuses can't be retrieved when the following occurs:
-
-1. A Merge Request is created
-1. The Merge Request is closed
-1. Changes are made in the project
-1. The Merge Request is reopened
-
-To enable the pipeline status to be properly retrieved, close and reopen the
-Merge Request again.
-
-## Tips
-
-Here are some tips that will help you be more efficient with merge requests in
-the command line.
-
-> **Note:**
-This section might move in its own document in the future.
-
-### Checkout merge requests locally
-
-A merge request contains all the history from a repository, plus the additional
-commits added to the branch associated with the merge request. Here's a few
-tricks to checkout a merge request locally.
-
-Please note that you can checkout a merge request locally even if the source
-project is a fork (even a private fork) of the target project.
-
-#### Checkout locally by adding a Git alias
-
-Add the following alias to your `~/.gitconfig`:
-
-```
-[alias]
- mr = !sh -c 'git fetch $1 merge-requests/$2/head:mr-$1-$2 && git checkout mr-$1-$2' -
-```
-
-Now you can check out a particular merge request from any repository and any
-remote. For example, to check out the merge request with ID 5 as shown in GitLab
-from the `origin` remote, do:
-
-```
-git mr origin 5
-```
-
-This will fetch the merge request into a local `mr-origin-5` branch and check
-it out.
-
-#### Checkout locally by modifying `.git/config` for a given repository
-
-Locate the section for your GitLab remote in the `.git/config` file. It looks
-like this:
-
-```
-[remote "origin"]
- url = https://gitlab.com/gitlab-org/gitlab-foss.git
- fetch = +refs/heads/*:refs/remotes/origin/*
-```
-
-You can open the file with:
-
-```
-git config -e
-```
-
-Now add the following line to the above section:
-
-```
-fetch = +refs/merge-requests/*/head:refs/remotes/origin/merge-requests/*
-```
-
-In the end, it should look like this:
-
-```
-[remote "origin"]
- url = https://gitlab.com/gitlab-org/gitlab-foss.git
- fetch = +refs/heads/*:refs/remotes/origin/*
- fetch = +refs/merge-requests/*/head:refs/remotes/origin/merge-requests/*
-```
-
-Now you can fetch all the merge requests:
-
-```
-git fetch origin
-
-...
-From https://gitlab.com/gitlab-org/gitlab-foss.git
- * [new ref] refs/merge-requests/1/head -> origin/merge-requests/1
- * [new ref] refs/merge-requests/2/head -> origin/merge-requests/2
-...
-```
-
-And to check out a particular merge request:
-
-```
-git checkout origin/merge-requests/1
-```
-
-All the above can be done with the [`git-mr`](https://gitlab.com/glensc/git-mr) script.
-
-[protected branches]: ../protected_branches.md
-[ci]: ../../../ci/README.md
-[cc]: https://codeclimate.com/
-[cd]: https://hub.docker.com/r/codeclimate/codeclimate/
-[sitespeed]: https://www.sitespeed.io
-[sitespeed-container]: https://hub.docker.com/r/sitespeedio/sitespeed.io/
-[ee]: https://about.gitlab.com/pricing/ "GitLab Enterprise Edition"
diff --git a/doc/user/project/merge_requests/merge_request_approvals.md b/doc/user/project/merge_requests/merge_request_approvals.md
index 2aa92ba2316..76c348eb93e 100644
--- a/doc/user/project/merge_requests/merge_request_approvals.md
+++ b/doc/user/project/merge_requests/merge_request_approvals.md
@@ -75,9 +75,9 @@ request approval rules:
1. Click **Add approvers** to create a new approval rule.
1. Just like in [GitLab Starter](#editing-approvals), select the approval members and approvals required.
1. Give the approval rule a name that describes the set of approvers selected.
-1. Click **Add approvers** to submit the new rule.
+1. Click **Add approval rule** to submit the new rule.
- ![Approvals premium project edit](img/approvals_premium_project_edit_v12_3.png)
+ ![Approvals premium project edit](img/approvals_premium_project_edit_v12_5.png)
## Multiple approval rules **(PREMIUM)**
@@ -219,8 +219,6 @@ and the project level approvers are changed after a merge request is created,
the merge request retains the previous approvers.
However, the approvers can be changed by [editing the merge request](#overriding-the-merge-request-approvals-default-settings).
----
-
The default approval settings can now be overridden when creating a
[merge request](index.md) or by editing it after it's been created:
diff --git a/doc/user/project/merge_requests/merge_when_pipeline_succeeds.md b/doc/user/project/merge_requests/merge_when_pipeline_succeeds.md
index dab2184448a..6630179ea47 100644
--- a/doc/user/project/merge_requests/merge_when_pipeline_succeeds.md
+++ b/doc/user/project/merge_requests/merge_when_pipeline_succeeds.md
@@ -85,3 +85,8 @@ questions that you know someone might ask.
Each scenario can be a third-level heading, e.g. `### Getting error message X`.
If you have none to add when creating a doc, leave this section in place
but commented out to help encourage others to add to it in the future. -->
+
+## Use it from the command line
+
+You can use [Push Options](../push_options.md) to trigger this feature when
+pushing.
diff --git a/doc/user/project/merge_requests/reviewing_and_managing_merge_requests.md b/doc/user/project/merge_requests/reviewing_and_managing_merge_requests.md
new file mode 100644
index 00000000000..f693b0b1e72
--- /dev/null
+++ b/doc/user/project/merge_requests/reviewing_and_managing_merge_requests.md
@@ -0,0 +1,251 @@
+---
+type: index, reference
+---
+
+# Reviewing and managing merge requests
+
+Merge requests are the primary method of making changes to files in a GitLab project.
+Changes are proposed by [creating and submitting a merge request](creating_merge_requests.md),
+which is then reviewed, and accepted (or rejected).
+
+## View project merge requests
+
+View all the merge requests within a project by navigating to **Project > Merge Requests**.
+
+When you access your project's merge requests, GitLab will present them in a list,
+and you can use the tabs available to quickly filter by open and closed. You can also [search and filter the results](../../search/index.md#issues-and-merge-requests-per-project).
+
+![Project merge requests list view](img/project_merge_requests_list_view.png)
+
+## View merge requests for all projects in a group
+
+View merge requests in all projects in the group, including all projects of all descendant subgroups of the group. Navigate to **Group > Merge Requests** to view these merge requests. This view also has the open and closed merge requests tabs.
+
+You can [search and filter the results](../../search/index.md#issues-and-merge-requests-per-group) from here.
+
+![Group Issues list view](img/group_merge_requests_list_view.png)
+
+## Semi-linear history merge requests
+
+A merge commit is created for every merge, but the branch is only merged if
+a fast-forward merge is possible. This ensures that if the merge request build
+succeeded, the target branch build will also succeed after merging.
+
+Navigate to a project's settings, select the **Merge commit with semi-linear history**
+option under **Merge Requests: Merge method** and save your changes.
+
+## View changes between file versions
+
+The **Changes** tab, below the main merge request details and next to the discussion tab,
+shows the changes to files between branches or commits. This view of changes to a
+file is also known as a **diff**. By default, the diff view compares the file in the
+merge request branch and the file in the target branch.
+
+The diff view includes the following:
+
+- The file's name and path.
+- The number of lines added and deleted.
+- Buttons for the following options:
+ - Toggle comments for this file; useful for inline reviews.
+ - Edit the file in the merge request's branch.
+ - Show full file, in case you want to look at the changes in context with the rest of the file.
+ - View file at the current commit.
+ - Preview the changes with [Review Apps](../../../ci/review_apps/index.md).
+- The changed lines, with the specific changes highlighted.
+
+![Example screenshot of a source code diff](img/merge_request_diff_v12_2.png)
+
+### Merge request diff file navigation
+
+When reviewing changes in the **Changes** tab the diff can be navigated using
+the file tree or file list. As you scroll through large diffs with many
+changes, you can quickly jump to any changed file using the file tree or file
+list.
+
+![Merge request diff file navigation](img/merge_request_diff_file_navigation.png)
+
+### Incrementally expand merge request diffs
+
+By default, the diff shows only the parts of a file which are changed.
+To view more unchanged lines above or below a change click on the
+**Expand up** or **Expand down** icons. You can also click on **Show all lines**
+to expand the entire file.
+
+![Incrementally expand merge request diffs](img/incrementally_expand_merge_request_diffs_v12_2.png)
+
+### Ignore whitespace changes in Merge Request diff view
+
+If you click the **Hide whitespace changes** button, you can see the diff
+without whitespace changes (if there are any). This is also working when on a
+specific commit page.
+
+![MR diff](img/merge_request_diff.png)
+
+>**Tip:**
+You can append `?w=1` while on the diffs page of a merge request to ignore any
+whitespace changes.
+
+## Commenting on any file line in merge requests
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/13950) in GitLab 11.5.
+
+GitLab provides a way of leaving comments in any part of the file being changed
+in a Merge Request. To do so, click the **...** button in the gutter of the Merge Request diff UI to expand the diff lines and leave a comment, just as you would for a changed line.
+
+![Comment on any diff file line](img/comment-on-any-diff-line.png)
+
+## Live preview with Review Apps
+
+If you configured [Review Apps](https://about.gitlab.com/product/review-apps/) for your project,
+you can preview the changes submitted to a feature-branch through a merge request
+in a per-branch basis. No need to checkout the branch, install and preview locally;
+all your changes will be available to preview by anyone with the Review Apps link.
+
+With GitLab's [Route Maps](../../../ci/review_apps/index.md#route-maps) set, the
+merge request widget takes you directly to the pages changed, making it easier and
+faster to preview proposed modifications.
+
+[Read more about Review Apps](../../../ci/review_apps/index.md).
+
+## Pipeline status in merge requests
+
+If you've set up [GitLab CI/CD](../../../ci/README.md) in your project,
+you will be able to see:
+
+- Both pre and post-merge pipelines and the environment information if any.
+- Which deployments are in progress.
+
+If there's an [environment](../../../ci/environments.md) and the application is
+successfully deployed to it, the deployed environment and the link to the
+Review App will be shown as well.
+
+### Post-merge pipeline status
+
+When a merge request is merged, you can see the post-merge pipeline status of
+the branch the merge request was merged into. For example, when a merge request
+is merged into the master branch and then triggers a deployment to the staging
+environment.
+
+Deployments that are ongoing will be shown, as well as the deploying/deployed state
+for environments. If it's the first time the branch is deployed, the link
+will return a `404` error until done. During the deployment, the stop button will
+be disabled. If the pipeline fails to deploy, the deployment info will be hidden.
+
+![Merge request pipeline](img/merge_request_pipeline.png)
+
+For more information, [read about pipelines](../../../ci/pipelines.md).
+
+## Troubleshooting
+
+Sometimes things don't go as expected in a merge request, here are some
+troubleshooting steps.
+
+### Merge request cannot retrieve the pipeline status
+
+This can occur if Sidekiq doesn't pick up the changes fast enough.
+
+#### Sidekiq
+
+Sidekiq didn't process the CI state change fast enough. Please wait a few
+seconds and the status will update automatically.
+
+#### Bug
+
+Merge Request pipeline statuses can't be retrieved when the following occurs:
+
+1. A Merge Request is created
+1. The Merge Request is closed
+1. Changes are made in the project
+1. The Merge Request is reopened
+
+To enable the pipeline status to be properly retrieved, close and reopen the
+Merge Request again.
+
+## Tips
+
+Here are some tips that will help you be more efficient with merge requests in
+the command line.
+
+> **Note:**
+This section might move in its own document in the future.
+
+### Checkout merge requests locally
+
+A merge request contains all the history from a repository, plus the additional
+commits added to the branch associated with the merge request. Here's a few
+tricks to checkout a merge request locally.
+
+Please note that you can checkout a merge request locally even if the source
+project is a fork (even a private fork) of the target project.
+
+#### Checkout locally by adding a Git alias
+
+Add the following alias to your `~/.gitconfig`:
+
+```
+[alias]
+ mr = !sh -c 'git fetch $1 merge-requests/$2/head:mr-$1-$2 && git checkout mr-$1-$2' -
+```
+
+Now you can check out a particular merge request from any repository and any
+remote. For example, to check out the merge request with ID 5 as shown in GitLab
+from the `origin` remote, do:
+
+```
+git mr origin 5
+```
+
+This will fetch the merge request into a local `mr-origin-5` branch and check
+it out.
+
+#### Checkout locally by modifying `.git/config` for a given repository
+
+Locate the section for your GitLab remote in the `.git/config` file. It looks
+like this:
+
+```
+[remote "origin"]
+ url = https://gitlab.com/gitlab-org/gitlab-foss.git
+ fetch = +refs/heads/*:refs/remotes/origin/*
+```
+
+You can open the file with:
+
+```
+git config -e
+```
+
+Now add the following line to the above section:
+
+```
+fetch = +refs/merge-requests/*/head:refs/remotes/origin/merge-requests/*
+```
+
+In the end, it should look like this:
+
+```
+[remote "origin"]
+ url = https://gitlab.com/gitlab-org/gitlab-foss.git
+ fetch = +refs/heads/*:refs/remotes/origin/*
+ fetch = +refs/merge-requests/*/head:refs/remotes/origin/merge-requests/*
+```
+
+Now you can fetch all the merge requests:
+
+```
+git fetch origin
+
+...
+From https://gitlab.com/gitlab-org/gitlab-foss.git
+ * [new ref] refs/merge-requests/1/head -> origin/merge-requests/1
+ * [new ref] refs/merge-requests/2/head -> origin/merge-requests/2
+...
+```
+
+And to check out a particular merge request:
+
+```
+git checkout origin/merge-requests/1
+```
+
+All the above can be done with the [`git-mr`](https://gitlab.com/glensc/git-mr) script.
diff --git a/doc/user/project/merge_requests/versions.md b/doc/user/project/merge_requests/versions.md
index fbe216c3aed..ffd0efb365a 100644
--- a/doc/user/project/merge_requests/versions.md
+++ b/doc/user/project/merge_requests/versions.md
@@ -35,6 +35,17 @@ changes appears as a system note.
![Merge request versions system note](img/versions_system_note.png)
+## Find the merge request that introduced a change
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/2383) in GitLab 10.5.
+
+When viewing the commit details page, GitLab will link to the merge request (or
+merge requests, if it's in more than one) containing that commit.
+
+This only applies to commits that are in the most recent version of a merge
+request - if a commit was in a merge request, then rebased out of that merge
+request, they will not be linked.
+
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
diff --git a/doc/user/project/milestones/index.md b/doc/user/project/milestones/index.md
index 105854ccd33..21a4e3d8ead 100644
--- a/doc/user/project/milestones/index.md
+++ b/doc/user/project/milestones/index.md
@@ -12,23 +12,21 @@ Milestones allow you to organize issues and merge requests into a cohesive group
## Milestones as Agile sprints
-Milestones can be used as Agile sprints.
-Set the milestone start date and due date to represent
-the start and end of your Agile sprint.
-Set the milestone title to the name of your Agile sprint,
-such as `November 2018 sprint`.
-Add an issue to your Agile sprint by associating
-the milestone to the issue.
+Milestones can be used as Agile sprints so that you can track all issues and merge requests related to a particular sprint. To do so:
+
+1. Set the milestone start date and due date to represent the start and end of your Agile sprint.
+1. Set the milestone title to the name of your Agile sprint, such as `November 2018 sprint`.
+1. Add an issue to your Agile sprint by associating the desired milestone from the issue's right-hand sidebar.
## Milestones as releases
-Milestones can be used as releases.
-Set the milestone due date to represent the release date of your release.
-(And leave the milestone start date blank.)
-Set the milestone title to the version of your release,
-such as `Version 9.4`.
-Add an issue to your release by associating
-the milestone to the issue.
+Similarily, milestones can be used as releases. To do so:
+
+1. Set the milestone due date to represent the release date of your release and leave the milestone start date blank.
+1. Set the milestone title to the version of your release, such as `Version 9.4`.
+1. Add an issue to your release by associating the desired milestone from the issue's right-hand sidebar.
+
+Additionally, you can integrate milestones with GitLab's [Releases feature](../releases/index.md#releases-associated-with-milestones).
## Project milestones and group milestones
@@ -103,30 +101,18 @@ When filtering by milestone, in addition to choosing a specific project mileston
## Milestone view
-Not all features in the project milestone view are available in the group milestone view. This table summarizes the differences:
-
-| Feature | Project milestone view | Group milestone view |
-|--------------------------------------|:----------------------:|:--------------------:|
-| Title an description | ✓ | ✓ |
-| Issues assigned to milestone | ✓ | |
-| Merge requests assigned to milestone | ✓ | |
-| Participants and labels used | ✓ | |
-| Percentage complete | ✓ | ✓ |
-| Start date and due date | ✓ | ✓ |
-| Total issue time spent | ✓ | ✓ |
-| Total issue weight | ✓ | |
-| Burndown chart **[STARTER}** | ✓ | ✓ |
-
The milestone view shows the title and description.
-### Project milestone features
-
-These features are only available for project milestones and not group milestones.
+There are also tabs below these that show the following:
-- Issues assigned to the milestone are displayed in three columns: Unstarted issues, ongoing issues, and completed issues.
-- Merge requests assigned to the milestone are displayed in four columns: Work in progress merge requests, waiting for merge, rejected, and closed.
-- Participants and labels that are used in issues and merge requests that have the milestone assigned are displayed.
-- [Burndown chart](#project-burndown-charts-starter).
+- Issues
+ Shows all issues assigned to the milestone. These are displayed in three columns: Unstarted issues, ongoing issues, and completed issues.
+- Merge requests
+ Shows all merge requests assigned to the milestone. These are displayed in four columns: Work in progress merge requests, waiting for merge, rejected, and closed.
+- Participants
+ Shows all assignees of issues assigned to the milestone.
+- Labels
+ Shows all labels that are used in issues assigned to the milestone.
### Project Burndown Charts **(STARTER)**
@@ -144,9 +130,8 @@ The milestone sidebar on the milestone view shows the following:
- Percentage complete, which is calculated as number of closed issues divided by total number of issues.
- The start date and due date.
-- The total time spent on all issues that have the milestone assigned.
-
-For project milestones only, the milestone sidebar shows the total issue weight of all issues that have the milestone assigned.
+- The total time spent on all issues assigned to the milestone.
+- The total issue weight of all issues assigned to the milestone.
![Project milestone page](img/milestones_project_milestone_page.png)
diff --git a/doc/user/project/operations/error_tracking.md b/doc/user/project/operations/error_tracking.md
index 1b319c5641c..04eda026bc3 100644
--- a/doc/user/project/operations/error_tracking.md
+++ b/doc/user/project/operations/error_tracking.md
@@ -6,7 +6,7 @@ Error tracking allows developers to easily discover and view the errors that the
## Sentry error tracking
-[Sentry](https://sentry.io/) is an open source error tracking system. GitLab allows administrators to connect Sentry to GitLab, to allow users to view a list of Sentry errors in GitLab itself.
+[Sentry](https://sentry.io/) is an open source error tracking system. GitLab allows administrators to connect Sentry to GitLab, to allow users to view a list of Sentry errors in GitLab.
### Deploying Sentry
@@ -20,6 +20,7 @@ You will need at least Maintainer [permissions](../../permissions.md) to enable
GitLab provides an easy way to connect Sentry to your project:
1. Sign up to Sentry.io or [deploy your own](#deploying-sentry) Sentry instance.
+1. [Create](https://docs.sentry.io/guides/integrate-frontend/create-new-project/) a new Sentry project. For each GitLab project that you want to integrate, we recommend that you create a new Sentry project.
1. [Find or generate](https://docs.sentry.io/api/auth/) a Sentry auth token for your Sentry project.
Make sure to give the token at least the following scopes: `event:read` and `project:read`.
1. Navigate to your project’s **Settings > Operations**.
@@ -31,11 +32,27 @@ GitLab provides an easy way to connect Sentry to your project:
1. Click **Save changes** for the changes to take effect.
1. You can now visit **Operations > Error Tracking** in your project's sidebar to [view a list](#error-tracking-list) of Sentry errors.
+### Enabling Gitlab issues links
+
+You may also want to enable Sentry's GitLab integration by following the steps in the [Sentry documentation](https://docs.sentry.io/workflow/integrations/global-integrations/#gitlab)
+
## Error Tracking List
NOTE: **Note:**
You will need at least Reporter [permissions](../../permissions.md) to view the Error Tracking list.
The Error Tracking list may be found at **Operations > Error Tracking** in your project's sidebar.
+Errors can be filtered by title.
![Error Tracking list](img/error_tracking_list.png)
+
+## Error Details
+
+From error list, users can navigate to the error details page by clicking the title of any error.
+
+This page has:
+
+- A link to Sentry issue.
+- A full stack trace along with other details.
+
+![Error Details](img/error_details_v12_5.png)
diff --git a/doc/user/project/operations/feature_flags.md b/doc/user/project/operations/feature_flags.md
index 08df92959c3..c05f8fa8bc4 100644
--- a/doc/user/project/operations/feature_flags.md
+++ b/doc/user/project/operations/feature_flags.md
@@ -81,7 +81,14 @@ NOTE: **NOTE**
We'd highly recommend you to use the [Environment](../../../ci/environments.md)
feature in order to quickly assess which flag is enabled per environment.
-## Rollout strategy
+## Feature Flag strategies
+
+GitLab Feature Flag adopts [Unleash](https://unleash.github.io)
+as the feature flag engine. In unleash, there is a concept of rulesets for granular feature flag controls,
+called [strategies](https://unleash.github.io/docs/activation_strategy).
+Supported strategies for GitLab Feature Flags are described below.
+
+### Rollout strategy
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/8240) in GitLab 12.2.
@@ -91,13 +98,13 @@ The status of an environment spec ultimately determines whether or not a feature
For instance, a feature will always be disabled for every user if the matching environment spec has a disabled status, regardless of the chosen rollout strategy.
However, a feature will be enabled for 50% of logged-in users if the matching environment spec has an enabled status along with a **Percent rollout (logged in users)** strategy set to 50%.
-### All users
+#### All users
Enables the feature for all users. It is implemented using the Unleash
[`default`](https://unleash.github.io/docs/activation_strategy#default)
activation strategy.
-### Percent rollout (logged in users)
+#### Percent rollout (logged in users)
Enables the feature for a percentage of authenticated users. It is
implemented using the Unleash
@@ -112,7 +119,7 @@ CAUTION: **Caution:**
If this strategy is selected, then the Unleash client **must** be given a user
ID for the feature to be enabled. See the [Ruby example](#ruby-application-example) below.
-## Target users
+### Target users strategy
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/8240) in GitLab 12.2.
@@ -134,7 +141,7 @@ In order to use Feature Flags, you need to first
[get the access credentials](#configuring-feature-flags) from GitLab and then
prepare your application and hook it with a [client library](#client-libraries).
-### Configuring Feature Flags
+## Configuring Feature Flags
To get the access credentials that your application will need to talk to GitLab:
@@ -153,7 +160,7 @@ if **Instance ID** will be single token or multiple tokens, assigned to the
**Environment**. Also, **Application name** could describe the version of
application instead of the running environment.
-### Client libraries
+## Client libraries
GitLab currently implements a single backend that is compatible with
[Unleash](https://github.com/Unleash/unleash#client-implementations) clients.
@@ -178,7 +185,7 @@ Community contributed clients:
- [Unofficial .Net Core Unleash client](https://github.com/onybo/unleash-client-core)
- [Unleash client for Python 3](https://github.com/aes/unleash-client-python)
-### Golang application example
+## Golang application example
Here's an example of how to integrate the feature flags in a Golang application:
@@ -219,7 +226,7 @@ func main() {
}
```
-### Ruby application example
+## Ruby application example
Here's an example of how to integrate the feature flags in a Ruby application.
@@ -249,3 +256,11 @@ else
puts "hello, world!"
end
```
+
+## Feature Flags API
+
+You can create, update, read, and delete Feature Flags via API
+to control them in an automated flow:
+
+- [Feature Flags API](../../../api/feature_flags.md)
+- [Feature Flag Specs API](../../../api/feature_flag_specs.md)
diff --git a/doc/user/project/operations/img/error_details_v12_5.png b/doc/user/project/operations/img/error_details_v12_5.png
new file mode 100644
index 00000000000..5e3e6300640
--- /dev/null
+++ b/doc/user/project/operations/img/error_details_v12_5.png
Binary files differ
diff --git a/doc/user/project/operations/img/error_tracking_list.png b/doc/user/project/operations/img/error_tracking_list.png
index 194c7b440a4..79b464e021e 100644
--- a/doc/user/project/operations/img/error_tracking_list.png
+++ b/doc/user/project/operations/img/error_tracking_list.png
Binary files differ
diff --git a/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md b/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md
index 326a2d302d2..2f16606c5a8 100644
--- a/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md
+++ b/doc/user/project/pages/custom_domains_ssl_tls_certification/index.md
@@ -169,6 +169,22 @@ from the GitLab project.
in place: your domain will be periodically reverified, and may be
disabled if the record is removed.
+##### Troubleshooting Pages domain verification
+
+To manually verify that you have properly configured the domain verification
+`TXT` DNS entry, you can run the following command in your terminal:
+
+```
+dig _gitlab-pages-verification-code.<YOUR-PAGES-DOMAIN> TXT
+```
+
+Expect the output:
+
+```
+;; ANSWER SECTION:
+_gitlab-pages-verification-code.<YOUR-PAGES-DOMAIN>. 300 IN TXT "gitlab-pages-verification-code=<YOUR-VERIFICATION-CODE>"
+```
+
### Adding more domain aliases
You can add more than one alias (custom domains and subdomains) to the same project.
diff --git a/doc/user/project/pages/custom_domains_ssl_tls_certification/lets_encrypt_integration.md b/doc/user/project/pages/custom_domains_ssl_tls_certification/lets_encrypt_integration.md
index c9b504dc6ee..1d64e843e46 100644
--- a/doc/user/project/pages/custom_domains_ssl_tls_certification/lets_encrypt_integration.md
+++ b/doc/user/project/pages/custom_domains_ssl_tls_certification/lets_encrypt_integration.md
@@ -5,7 +5,8 @@ description: "Automatic Let's Encrypt SSL certificates for GitLab Pages."
# GitLab Pages integration with Let's Encrypt
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/28996) in GitLab 12.1.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/28996) in GitLab 12.1. For versions earlier than GitLab 12.1, see the [manual Let's Encrypt instructions](../lets_encrypt_for_gitlab_pages.md).
+This feature is in **beta** and may still have bugs. See all the related issues linked from this [issue's description](https://gitlab.com/gitlab-org/gitlab-foss/issues/28996) for more information.
The GitLab Pages integration with Let's Encrypt (LE) allows you
to use LE certificates for your Pages website with custom domains
@@ -16,19 +17,11 @@ GitLab does it for you, out-of-the-box.
open source Certificate Authority.
CAUTION: **Caution:**
-This feature is in **beta** and might present bugs and UX issues
-such as [#64870](https://gitlab.com/gitlab-org/gitlab-foss/issues/64870).
-See all the related issues linked from this [issue's description](https://gitlab.com/gitlab-org/gitlab-foss/issues/28996)
-for more information.
-
-CAUTION: **Caution:**
-This feature covers only certificates for **custom domains**,
-not the wildcard certificate required to run [Pages daemon](../../../../administration/pages/index.md) **(CORE ONLY)**.
-Wildcard certificate generation is tracked in [this issue](https://gitlab.com/gitlab-org/omnibus-gitlab/issues/3342).
+This feature covers only certificates for **custom domains**, not the wildcard certificate required to run [Pages daemon](../../../../administration/pages/index.md) **(CORE ONLY)**. Wildcard certificate generation is tracked in [this issue](https://gitlab.com/gitlab-org/omnibus-gitlab/issues/3342).
## Requirements
-Before you can enable automatic provisioning of a SSL certificate for your domain, make sure you have:
+Before you can enable automatic provisioning of an SSL certificate for your domain, make sure you have:
- Created a [project](../getting_started_part_two.md) in GitLab
containing your website's source code.
@@ -36,7 +29,7 @@ Before you can enable automatic provisioning of a SSL certificate for your domai
pointing it to your Pages website.
- [Added your domain to your Pages project](index.md#1-add-a-custom-domain-to-pages)
and verified your ownership.
-- Have your website up and running, accessible through your custom domain.
+- Verified your website is up and running, accessible through your custom domain.
NOTE: **Note:**
GitLab's Let's Encrypt integration is enabled and available on GitLab.com.
@@ -45,7 +38,7 @@ For **self-managed** GitLab instances, make sure your administrator has
## Enabling Let's Encrypt integration for your custom domain
-Once you've met the requirements, to enable Let's Encrypt integration:
+Once you've met the requirements, enable Let's Encrypt integration:
1. Navigate to your project's **Settings > Pages**.
1. Find your domain and click **Details**.
diff --git a/doc/user/project/pages/getting_started/fork_sample_project.md b/doc/user/project/pages/getting_started/fork_sample_project.md
new file mode 100644
index 00000000000..ac1a29ca2a0
--- /dev/null
+++ b/doc/user/project/pages/getting_started/fork_sample_project.md
@@ -0,0 +1,61 @@
+---
+type: reference, howto
+---
+
+# New Pages website from a forked sample
+
+To get started with GitLab Pages from a sample website, the easiest
+way to do it is by using one of the [bundled templates](pages_bundled_template.md).
+If you don't find one that suits your needs, you can opt by
+forking (copying) a [sample project from the most popular Static Site Generators](https://gitlab.com/pages).
+
+<table class="borderless-table center fixed-table middle width-80">
+ <tr>
+ <td style="width: 30%"><img src="../img/icons/fork.png" alt="Fork" class="image-noshadow half-width"></td>
+ <td style="width: 10%">
+ <strong>
+ <i class="fa fa-angle-double-right" aria-hidden="true"></i>
+ </strong>
+ </td>
+ <td style="width: 30%"><img src="../img/icons/terminal.png" alt="Deploy" class="image-noshadow half-width"></td>
+ <td style="width: 10%">
+ <strong>
+ <i class="fa fa-angle-double-right" aria-hidden="true"></i>
+ </strong>
+ </td>
+ <td style="width: 30%"><img src="../img/icons/click.png" alt="Visit" class="image-noshadow half-width"></td>
+ </tr>
+ <tr>
+ <td><em>Fork an example project</em></td>
+ <td></td>
+ <td><em>Deploy your website</em></td>
+ <td></td>
+ <td><em>Visit your website's URL</em></td>
+ </tr>
+</table>
+
+**<i class="fa fa-youtube-play youtube" aria-hidden="true"></i> Watch a [video tutorial](https://www.youtube.com/watch?v=TWqh9MtT4Bg) with all the steps below.**
+
+1. [Fork](../../../../gitlab-basics/fork-project.md) a sample project from the [GitLab Pages examples](https://gitlab.com/pages) group.
+1. From the left sidebar, navigate to your project's **CI/CD > Pipelines**
+ and click **Run pipeline** to trigger GitLab CI/CD to build and deploy your
+ site to the server.
+1. Once the pipeline has finished successfully, find the link to visit your
+ website from your project's **Settings > Pages**. It can take aproximatelly
+ 30 minutes to be deployed.
+
+You can also take some **optional** further steps:
+
+- _Remove the fork relationship._ The fork relationship is necessary to contribute back to the project you originally forked from. If you don't have any intentions to do so, you can remove it. To do so, navigate to your project's **Settings**, expand **Advanced settings**, and scroll down to **Remove fork relationship**:
+
+ ![remove fork relationship](../img/remove_fork_relationship.png)
+
+- _Make it a user or group website._ To turn a **project website** forked
+ from the Pages group into a **user/group** website, you'll need to:
+ - Rename it to `namespace.gitlab.io`: go to your project's
+ **Settings > General** and expand **Advanced**. Scroll down to
+ **Rename repository** and change the path to `namespace.gitlab.io`.
+ - Adjust your SSG's [base URL](../getting_started_part_one.md#urls-and-baseurls) from `"project-name"` to
+ `""`. This setting will be at a different place for each SSG, as each of them
+ have their own structure and file tree. Most likely, it will be in the SSG's
+ config file.
diff --git a/doc/user/project/pages/getting_started/new_or_existing_website.md b/doc/user/project/pages/getting_started/new_or_existing_website.md
new file mode 100644
index 00000000000..62b5fa33117
--- /dev/null
+++ b/doc/user/project/pages/getting_started/new_or_existing_website.md
@@ -0,0 +1,45 @@
+---
+type: reference, howto
+---
+
+# Start a new Pages website from scratch or deploy an existing website
+
+If you already have a website and want to deploy it with GitLab Pages,
+or, if you want to start a new site from scratch, you'll need to:
+
+- Create a new project in GitLab to hold your site content.
+- Set up GitLab CI/CD to deploy your website to Pages.
+
+To do so, follow the steps below.
+
+1. From your **Project**'s **[Dashboard](https://gitlab.com/dashboard/projects)**,
+ click **New project**, and name it according to the
+ [Pages domain names](../getting_started_part_one.md#gitlab-pages-default-domain-names).
+1. Clone it to your local computer, add your website
+ files to your project, add, commit and push to GitLab.
+ Alternativelly, you can run `git init` in your local directory,
+ add the remote URL:
+ `git remote add origin git@gitlab.com:namespace/project-name.git`,
+ then add, commit, and push to GitLab.
+1. From the your **Project**'s page, click **Set up CI/CD**:
+
+ ![setup GitLab CI/CD](../img/setup_ci.png)
+
+1. Choose one of the templates from the dropbox menu.
+ Pick up the template corresponding to the SSG you're using (or plain HTML).
+
+ ![gitlab-ci templates](../img/choose_ci_template.png)
+
+ Note that, if you don't find a corresponding template, you can look into
+ [GitLab Pages group of sample projects](https://gitlab.com/pages),
+ you may find one among them that suits your needs, from which you
+ can copy `.gitlab-ci.yml`'s content and adjust for your case.
+ If you don't find it there either, [learn how to write a `.gitlab-ci.yml`
+ file for GitLab Pages](../getting_started_part_four.md).
+
+Once you have both site files and `.gitlab-ci.yml` in your project's
+root, GitLab CI/CD will build your site and deploy it with Pages.
+Once the first build passes, you access your site by
+navigating to your **Project**'s **Settings** > **Pages**,
+where you'll find its default URL. It can take approximately 30 min to be
+deployed.
diff --git a/doc/user/project/pages/getting_started/pages_bundled_template.md b/doc/user/project/pages/getting_started/pages_bundled_template.md
new file mode 100644
index 00000000000..802abeb3cc2
--- /dev/null
+++ b/doc/user/project/pages/getting_started/pages_bundled_template.md
@@ -0,0 +1,29 @@
+---
+type: reference, howto
+---
+
+# New Pages website from a bundled template
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/47857)
+in GitLab 11.8.
+
+The simplest way to create a GitLab Pages site is to use one of the most
+popular templates, which come already bundled with GitLab and are ready to go.
+
+1. From the top navigation, click the **+** button and select **New project**.
+1. Select **Create from Template**.
+1. Choose one of the templates starting with **Pages**:
+
+ ![Project templates for Pages](../img/pages_project_templates_v11_8.png)
+
+1. From the left sidebar, navigate to your project's **CI/CD > Pipelines**
+ and click **Run pipeline** to trigger GitLab CI/CD to build and deploy your
+ site to the server.
+1. After the pipeline has finished successfully, wait approximately 30 minutes
+ for your website to be visible. After waiting 30 minutes, find the link to
+ visit your website from your project's **Settings > Pages**. If the link
+ leads to a 404 page, wait a few minutes and try again.
+
+Your website is then visible on your domain and you can modify your files
+as you wish. For every modification pushed to your repository, GitLab CI/CD
+will run a new pipeline to immediately publish your changes to the server.
diff --git a/doc/user/project/pages/getting_started_part_one.md b/doc/user/project/pages/getting_started_part_one.md
index 0b1cae9ab4c..b876e547ba5 100644
--- a/doc/user/project/pages/getting_started_part_one.md
+++ b/doc/user/project/pages/getting_started_part_one.md
@@ -3,25 +3,12 @@ last_updated: 2018-06-04
type: concepts, reference
---
-# Static sites and GitLab Pages domains
+# GitLab Pages domain names, URLs, and baseurls
On this document, learn how to name your project for GitLab Pages
according to your intended website's URL.
-## Static sites
-
-GitLab Pages only supports static websites, meaning,
-your output files must be HTML, CSS, and JavaScript only.
-
-To create your static site, you can either hardcode in HTML,
-CSS, and JS, or use a [Static Site Generator (SSG)](https://www.staticgen.com/)
-to simplify your code and build the static site for you,
-which is highly recommendable and much faster than hardcoding.
-
-See the [further reading](#further-reading) section below for
-references on static site concepts.
-
-## GitLab Pages domain names
+## GitLab Pages default domain names
>**Note:**
If you use your own GitLab instance to deploy your
@@ -93,11 +80,35 @@ To understand Pages domains clearly, read the examples below.
- On your GitLab instance, replace `gitlab.io` above with your
Pages server domain. Ask your sysadmin for this information.
-_Read on about [Projects for GitLab Pages and URL structure](getting_started_part_two.md)._
+## URLs and baseurls
+
+Every Static Site Generator (SSG) default configuration expects
+to find your website under a (sub)domain (`example.com`), not
+in a subdirectory of that domain (`example.com/subdir`). Therefore,
+whenever you publish a project website (`namespace.gitlab.io/project-name`),
+you'll have to look for this configuration (base URL) on your SSG's
+documentation and set it up to reflect this pattern.
+
+For example, for a Jekyll site, the `baseurl` is defined in the Jekyll
+configuration file, `_config.yml`. If your website URL is
+`https://john.gitlab.io/blog/`, you need to add this line to `_config.yml`:
+
+```yaml
+baseurl: "/blog"
+```
+
+On the contrary, if you deploy your website after forking one of
+our [default examples](https://gitlab.com/pages), the baseurl will
+already be configured this way, as all examples there are project
+websites. If you decide to make yours a user or group website, you'll
+have to remove this configuration from your project. For the Jekyll
+example we've just mentioned, you'd have to change Jekyll's `_config.yml` to:
+
+```yaml
+baseurl: ""
+```
-### Further reading
+## Custom domains
-- Read through this technical overview on [Static versus Dynamic Websites](https://about.gitlab.com/blog/2016/06/03/ssg-overview-gitlab-pages-part-1-dynamic-x-static/)
-- Understand [how modern Static Site Generators work](https://about.gitlab.com/blog/2016/06/10/ssg-overview-gitlab-pages-part-2/) and what you can add to your static site
-- You can use [any SSG with GitLab Pages](https://about.gitlab.com/blog/2016/06/17/ssg-overview-gitlab-pages-part-3-examples-ci/)
-- Fork an [example project](https://gitlab.com/pages) to build your website based upon
+GitLab Pages supports custom domains and subdomains, served under HTTP or HTTPS.
+See [GitLab Pages custom domains and SSL/TLS Certificates](custom_domains_ssl_tls_certification/index.md) for more information.
diff --git a/doc/user/project/pages/getting_started_part_two.md b/doc/user/project/pages/getting_started_part_two.md
index ff752917087..70e84f5d486 100644
--- a/doc/user/project/pages/getting_started_part_two.md
+++ b/doc/user/project/pages/getting_started_part_two.md
@@ -1,172 +1,5 @@
---
-last_updated: 2019-06-04
-type: reference, howto
+redirect_to: 'index.md'
---
-# Projects for GitLab Pages and URL structure
-
-## What you need to get started
-
-To get started with GitLab Pages, you need:
-
-1. A project, thus a repository to hold your website's codebase.
-1. A configuration file (`.gitlab-ci.yml`) to deploy your site.
-1. A specific `job` called `pages` in the configuration file
- that will make GitLab aware that you are deploying a GitLab Pages website.
-1. A `public` directory with the static content of the website.
-
-Optional Features:
-
-1. A custom domain or subdomain.
-1. A DNS pointing your (sub)domain to your Pages site.
- 1. **Optional**: an SSL/TLS certificate so your custom
- domain is accessible under HTTPS.
-
-The optional settings, custom domain, DNS records, and SSL/TLS certificates, are described in [GitLab Pages custom domains and SSL/TLS Certificates](custom_domains_ssl_tls_certification/index.md)).
-
-## Project
-
-Your GitLab Pages project is a regular project created the
-same way you do for the other ones. To get started with GitLab Pages, you have three ways:
-
-- [Use one of the popular project templates bundled with GitLab](#use-one-of-the-popular-pages-templates-bundled-with-gitlab).
-- [Fork one of the templates from Page Examples](#fork-a-project-to-get-started-from).
-- [Create a new project from scratch](#create-a-project-from-scratch).
-
-### Use one of the popular Pages templates bundled with GitLab
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/47857)
-in GitLab 11.8.
-
-The simplest way to create a GitLab Pages site is to
-[use one of the most popular templates](index.md#getting-started),
-which come already bundled with GitLab and are ready to go.
-
-### Fork a project to get started from
-
-If you don't find an existing project template that suits you,
-we've created this [group](https://gitlab.com/pages) of default projects
-containing the most popular SSGs templates to get you started.
-
-<table class="borderless-table center fixed-table middle width-80">
- <tr>
- <td style="width: 30%"><img src="img/icons/fork.png" alt="Fork" class="image-noshadow half-width"></td>
- <td style="width: 10%">
- <strong>
- <i class="fa fa-angle-double-right" aria-hidden="true"></i>
- </strong>
- </td>
- <td style="width: 30%"><img src="img/icons/terminal.png" alt="Deploy" class="image-noshadow half-width"></td>
- <td style="width: 10%">
- <strong>
- <i class="fa fa-angle-double-right" aria-hidden="true"></i>
- </strong>
- </td>
- <td style="width: 30%"><img src="img/icons/click.png" alt="Visit" class="image-noshadow half-width"></td>
- </tr>
- <tr>
- <td><em>Fork an example project</em></td>
- <td></td>
- <td><em>Deploy your website</em></td>
- <td></td>
- <td><em>Visit your website's URL</em></td>
- </tr>
-</table>
-
-**<i class="fa fa-youtube-play youtube" aria-hidden="true"></i> Watch a [video tutorial](https://www.youtube.com/watch?v=TWqh9MtT4Bg) with all the steps below.**
-
-1. [Fork](../../../gitlab-basics/fork-project.md) a sample project from the [GitLab Pages examples](https://gitlab.com/pages) group.
-1. From the left sidebar, navigate to your project's **CI/CD > Pipelines**
- and click **Run pipeline** to trigger GitLab CI/CD to build and deploy your
- site to the server.
-1. Once the pipeline has finished successfully, find the link to visit your
- website from your project's **Settings > Pages**.
-
-You can also take some **optional** further steps:
-
-- _Remove the fork relationship._ The fork relationship is necessary to contribute back to the project you originally forked from. If you don't have any intentions to do so, you can remove it. To do so, navigate to your project's **Settings**, expand **Advanced settings**, and scroll down to **Remove fork relationship**:
-
- ![remove fork relationship](img/remove_fork_relationship.png)
-
-- _Make it a user or group website._ To turn a **project website** forked
- from the Pages group into a **user/group** website, you'll need to:
- - Rename it to `namespace.gitlab.io`: go to your project's
- **Settings > General** and expand **Advanced**. Scroll down to
- **Rename repository** and change the path to `namespace.gitlab.io`.
- - Adjust your SSG's [base URL](#urls-and-baseurls) from `"project-name"` to
- `""`. This setting will be at a different place for each SSG, as each of them
- have their own structure and file tree. Most likely, it will be in the SSG's
- config file.
-
-### Create a project from scratch
-
-1. From your **Project**'s **[Dashboard](https://gitlab.com/dashboard/projects)**,
- click **New project**, and name it according to the
- [Pages domain names](getting_started_part_one.md#gitlab-pages-domain-names).
-1. Clone it to your local computer, add your website
- files to your project, add, commit and push to GitLab.
-1. From the your **Project**'s page, click **Set up CI/CD**:
-
- ![setup GitLab CI/CD](img/setup_ci.png)
-
-1. Choose one of the templates from the dropbox menu.
- Pick up the template corresponding to the SSG you're using (or plain HTML).
-
- ![gitlab-ci templates](img/choose_ci_template.png)
-
-Once you have both site files and `.gitlab-ci.yml` in your project's
-root, GitLab CI/CD will build your site and deploy it with Pages.
-Once the first build passes, you see your site is live by
-navigating to your **Project**'s **Settings** > **Pages**,
-where you'll find its default URL.
-
-> **Notes:**
->
-> - GitLab Pages [supports any SSG](https://about.gitlab.com/blog/2016/06/17/ssg-overview-gitlab-pages-part-3-examples-ci/), but,
-> if you don't find yours among the templates, you'll need
-> to configure your own `.gitlab-ci.yml`. To do that, please
-> read through the article [Creating and Tweaking GitLab CI/CD for GitLab Pages](getting_started_part_four.md). New SSGs are very welcome among
-> the [example projects](https://gitlab.com/pages). If you set
-> up a new one, please
-> [contribute](https://gitlab.com/pages/pages.gitlab.io/blob/master/CONTRIBUTING.md)
-> to our examples.
->
-> - The second step _"Clone it to your local computer"_, can be done
-> differently, achieving the same results: instead of cloning the bare
-> repository to you local computer and moving your site files into it,
-> you can run `git init` in your local website directory, add the
-> remote URL: `git remote add origin git@gitlab.com:namespace/project-name.git`,
-> then add, commit, and push to GitLab.
-
-## URLs and Baseurls
-
-Every Static Site Generator (SSG) default configuration expects
-to find your website under a (sub)domain (`example.com`), not
-in a subdirectory of that domain (`example.com/subdir`). Therefore,
-whenever you publish a project website (`namespace.gitlab.io/project-name`),
-you'll have to look for this configuration (base URL) on your SSG's
-documentation and set it up to reflect this pattern.
-
-For example, for a Jekyll site, the `baseurl` is defined in the Jekyll
-configuration file, `_config.yml`. If your website URL is
-`https://john.gitlab.io/blog/`, you need to add this line to `_config.yml`:
-
-```yaml
-baseurl: "/blog"
-```
-
-On the contrary, if you deploy your website after forking one of
-our [default examples](https://gitlab.com/pages), the baseurl will
-already be configured this way, as all examples there are project
-websites. If you decide to make yours a user or group website, you'll
-have to remove this configuration from your project. For the Jekyll
-example we've just mentioned, you'd have to change Jekyll's `_config.yml` to:
-
-```yaml
-baseurl: ""
-```
-
-## Custom Domains
-
-GitLab Pages supports custom domains and subdomains, served under HTTP or HTTPS.
-See [GitLab Pages custom domains and SSL/TLS Certificates](custom_domains_ssl_tls_certification/index.md) for more information.
+This document was moved to [another location](index.md#getting-started).
diff --git a/doc/user/project/pages/img/new_project_for_pages_v12_5.png b/doc/user/project/pages/img/new_project_for_pages_v12_5.png
new file mode 100644
index 00000000000..8d2dc0bf9f5
--- /dev/null
+++ b/doc/user/project/pages/img/new_project_for_pages_v12_5.png
Binary files differ
diff --git a/doc/user/project/pages/img/pages_workflow_v12_5.png b/doc/user/project/pages/img/pages_workflow_v12_5.png
new file mode 100644
index 00000000000..ca5190fca79
--- /dev/null
+++ b/doc/user/project/pages/img/pages_workflow_v12_5.png
Binary files differ
diff --git a/doc/user/project/pages/index.md b/doc/user/project/pages/index.md
index 7d533c6f9d1..abd67c90dd6 100644
--- a/doc/user/project/pages/index.md
+++ b/doc/user/project/pages/index.md
@@ -19,38 +19,7 @@ You can use it either for personal or business websites, such as
portfolios, documentation, manifestos, and business presentations.
You can also attribute any license to your content.
-<table class="borderless-table center fixed-table">
- <tr>
- <td style="width: 22%"><img src="img/icons/cogs.png" alt="SSGs" class="image-noshadow half-width"></td>
- <td style="width: 4%">
- <strong>
- <i class="fa fa-angle-double-right" aria-hidden="true"></i>
- </strong>
- </td>
- <td style="width: 22%"><img src="img/icons/monitor.png" alt="Websites" class="image-noshadow half-width"></td>
- <td style="width: 4%">
- <strong>
- <i class="fa fa-angle-double-right" aria-hidden="true"></i>
- </strong>
- </td>
- <td style="width: 22%"><img src="img/icons/free.png" alt="Pages is free" class="image-noshadow half-width"></td>
- <td style="width: 4%">
- <strong>
- <i class="fa fa-angle-double-right" aria-hidden="true"></i>
- </strong>
- </td>
- <td style="width: 22%"><img src="img/icons/lock.png" alt="Secure your website" class="image-noshadow half-width"></td>
- </tr>
- <tr>
- <td><em>Use any static website generator or plain HTML</em></td>
- <td></td>
- <td><em>Create websites for your projects, groups, or user account</em></td>
- <td></td>
- <td><em>Host on GitLab.com for free, or on your own GitLab instance</em></td>
- <td></td>
- <td><em>Connect your custom domain(s) and TLS certificates</em></td>
- </tr>
-</table>
+<img src="img/pages_workflow_v12_5.png" alt="Pages websites workflow" class="image-noshadow">
Pages is available for free for all GitLab.com users as well as for self-managed
instances (GitLab Core, Starter, Premium, and Ultimate).
@@ -73,6 +42,7 @@ publish any website written directly in plain HTML, CSS, and JavaScript.</p>
To use GitLab Pages, first you need to create a project in GitLab to upload your website's
files to. These projects can be either public, internal, or private, at your own choice.
+
GitLab will always deploy your website from a very specific folder called `public` in your
repository. Note that when you create a new project in GitLab, a [repository](../repository/index.md)
becomes available automatically.
@@ -80,67 +50,50 @@ becomes available automatically.
To deploy your site, GitLab will use its built-in tool called [GitLab CI/CD](../../../ci/README.md),
to build your site and publish it to the GitLab Pages server. The sequence of
scripts that GitLab CI/CD runs to accomplish this task is created from a file named
-`.gitlab-ci.yml`, which you can [create and modify](getting_started_part_four.md) at will.
+`.gitlab-ci.yml`, which you can [create and modify](getting_started_part_four.md) at will. A specific `job` called `pages` in the configuration file will make GitLab aware that you are deploying a GitLab Pages website.
-You can either use GitLab's [default domain for GitLab Pages websites](getting_started_part_one.md#gitlab-pages-domain-names),
+You can either use GitLab's [default domain for GitLab Pages websites](getting_started_part_one.md#gitlab-pages-default-domain-names),
`*.gitlab.io`, or your own domain (`example.com`). In that case, you'll
need admin access to your domain's registrar (or control panel) to set it up with Pages.
-Optionally, when adding your own domain, you can add an SSL/TLS certificate to secure your
-site under the HTTPS protocol.
-
### Getting started
To get started with GitLab Pages, you can either:
-- [Create a project from scratch](getting_started_part_two.md#create-a-project-from-scratch).
-- [Copy an existing example project](getting_started_part_two.md#fork-a-project-to-get-started-from).
-- Use a bundled project template ready to go:
-
-1. From the top navigation, click the **+** button and select **New project**.
-1. Select **Create from Template**.
-1. Choose one of the templates starting with **Pages**:
-
- ![Project templates for Pages](img/pages_project_templates_v11_8.png)
+- [Use a bundled website template ready to go](getting_started/pages_bundled_template.md).
+- [Copy an existing sample](getting_started/fork_sample_project.md).
+- [Create a website from scratch or deploy an existing one](getting_started/new_or_existing_website.md).
-1. From the left sidebar, navigate to your project's **CI/CD > Pipelines**
- and click **Run pipeline** to trigger GitLab CI/CD to build and deploy your
- site to the server.
-1. After the pipeline has finished successfully, wait approximately 30 minutes
- for your website to be visible. After waiting 30 minutes, find the link to
- visit your website from your project's **Settings > Pages**. If the link
- leads to a 404 page, wait a few minutes and try again.
+<img src="img/new_project_for_pages_v12_5.png" alt="New projects for GitLab Pages" class="image-noshadow">
-Your website is then visible on your domain and you can modify your files
-as you wish. For every modification pushed to your repository, GitLab CI/CD
-will run a new pipeline to immediately publish your changes to the server.
+Optional features:
-_Advanced options:_
+- Use a [custom domain or subdomain](custom_domains_ssl_tls_certification/index.md#set-up-pages-with-a-custom-domain).
+- Add an [SSL/TLS certificate to secure your site under the HTTPS protocol](custom_domains_ssl_tls_certification/index.md#adding-an-ssltls-certificate-to-pages).
-- [Use a custom domain](custom_domains_ssl_tls_certification/index.md#set-up-pages-with-a-custom-domain)
-- Apply [SSL/TLS certification](custom_domains_ssl_tls_certification/index.md#adding-an-ssltls-certificate-to-pages) to your custom domain
+Note that, if you're using GitLab Pages default domain (`.gitlab.io`),
+your website will be automatically secure and available under
+HTTPS. If you're using your own custom domain, you can
+optionally secure it with SSL/TLS certificates.
## Availability
If you're using GitLab.com, your website will be publicly available to the internet.
+
+To restrict access to your website, enable [GitLab Pages Access Control](pages_access_control.md).
+
If you're using self-managed instances (Core, Starter, Premium, or Ultimate),
your websites will be published on your own server, according to the
[Pages admin settings](../../../administration/pages/index.md) chosen by your sysadmin,
who can opt for making them public or internal to your server.
-Note that, if you're using GitLab Pages default domain (`.gitlab.io`),
-your website will be automatically secure and available under
-HTTPS. If you're using your own custom domain, you can
-optionally secure it with SSL/TLS certificates.
-
## Explore GitLab Pages
To learn more about configuration options for GitLab Pages, read the following:
| Document | Description |
| --- | --- |
-| [Static websites and Pages domains](getting_started_part_one.md) | Understand what is a static website, and how GitLab Pages default domains work. |
-| [Projects and URL structure](getting_started_part_two.md) | Forking projects and creating new ones from scratch, understanding URLs structure and baseurls. |
+| [GitLab Pages domain names, URLs, and baseurls](getting_started_part_one.md) | Understand how GitLab Pages default domains work. |
| [GitLab CI/CD for GitLab Pages](getting_started_part_four.md) | Understand how to create your own `.gitlab-ci.yml` for your site. |
| [Exploring GitLab Pages](introduction.md) | Requirements, technical aspects, specific GitLab CI's configuration options, Access Control, custom 404 pages, limitations, FAQ. |
|---+---|
diff --git a/doc/user/project/pages/introduction.md b/doc/user/project/pages/introduction.md
index 86257e2aa03..01e1909f6d6 100644
--- a/doc/user/project/pages/introduction.md
+++ b/doc/user/project/pages/introduction.md
@@ -69,40 +69,7 @@ don't have to create and edit HTML files manually. For example, Jekyll has the
## GitLab Pages Access Control **(CORE)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/33422) in GitLab 11.5.
-
-You can enable Pages access control on your project, so that only
-[members of your project](../../permissions.md#project-members-permissions)
-(at least Guest) can access your website:
-
-1. Navigate to your project's **Settings > General > Permissions**.
-1. Toggle the **Pages** button to enable the access control.
-
- NOTE: **Note:**
- If you don't see the toggle button, that means that it's not enabled.
- Ask your administrator to [enable it](../../../administration/pages/index.md#access-control).
-
-1. The Pages access control dropdown allows you to set who can view pages hosted
- with GitLab Pages, depending on your project's visibility:
-
- - If your project is private:
- - **Only project members**: Only project members will be able to browse the website.
- - **Everyone**: Everyone, both logged into and logged out of GitLab, will be able to browse the website, no matter their project membership.
- - If your project is internal:
- - **Only project members**: Only project members will be able to browse the website.
- - **Everyone with access**: Everyone logged into GitLab will be able to browse the website, no matter their project membership.
- - **Everyone**: Everyone, both logged into and logged out of GitLab, will be able to browse the website, no matter their project membership.
- - If your project is public:
- - **Only project members**: Only project members will be able to browse the website.
- - **Everyone with access**: Everyone, both logged into and logged out of GitLab, will be able to browse the website, no matter their project membership.
-
-1. Click **Save changes**.
-
----
-
-The next time someone tries to access your website and the access control is
-enabled, they will be presented with a page to sign into GitLab and verify they
-can access the website.
+To restrict access to your website, enable [GitLab Pages Access Control](pages_access_control.md).
## Unpublishing your Pages
diff --git a/doc/user/project/pages/lets_encrypt_for_gitlab_pages.md b/doc/user/project/pages/lets_encrypt_for_gitlab_pages.md
index 1338c7e58f5..c9bd3e35a5f 100644
--- a/doc/user/project/pages/lets_encrypt_for_gitlab_pages.md
+++ b/doc/user/project/pages/lets_encrypt_for_gitlab_pages.md
@@ -21,8 +21,8 @@ open source Certificate Authority.
To follow along with this tutorial, we assume you already have:
-- Created a [project](getting_started_part_two.md) in GitLab which
- contains your website's source code.
+- [Created a project](index.md#getting-started) in GitLab
+ containing your website's source code.
- Acquired a domain (`example.com`) and added a [DNS entry](custom_domains_ssl_tls_certification/index.md#set-up-pages-with-a-custom-domain)
pointing it to your Pages website.
- [Added your domain to your Pages project](custom_domains_ssl_tls_certification/index.md#steps)
diff --git a/doc/user/project/pages/pages_access_control.md b/doc/user/project/pages/pages_access_control.md
new file mode 100644
index 00000000000..cd715c6e3b9
--- /dev/null
+++ b/doc/user/project/pages/pages_access_control.md
@@ -0,0 +1,48 @@
+---
+type: reference, howto
+---
+
+# GitLab Pages Access Control
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/33422) in GitLab 11.5.
+> - Available on GitLab.com in GitLab 12.4.
+
+You can enable Pages access control on your project, so that only
+[members of your project](../../permissions.md#project-members-permissions)
+(at least Guest) can access your website:
+
+1. Navigate to your project's **Settings > General > Permissions**.
+1. Toggle the **Pages** button to enable the access control.
+
+ NOTE: **Note:**
+ If you don't see the toggle button, that means that it's not enabled.
+ Ask your administrator to [enable it](../../../administration/pages/index.md#access-control).
+
+1. The Pages access control dropdown allows you to set who can view pages hosted
+ with GitLab Pages, depending on your project's visibility:
+
+ - If your project is private:
+ - **Only project members**: Only project members will be able to browse the website.
+ - **Everyone**: Everyone, both logged into and logged out of GitLab, will be able to browse the website, no matter their project membership.
+ - If your project is internal:
+ - **Only project members**: Only project members will be able to browse the website.
+ - **Everyone with access**: Everyone logged into GitLab will be able to browse the website, no matter their project membership.
+ - **Everyone**: Everyone, both logged into and logged out of GitLab, will be able to browse the website, no matter their project membership.
+ - If your project is public:
+ - **Only project members**: Only project members will be able to browse the website.
+ - **Everyone with access**: Everyone, both logged into and logged out of GitLab, will be able to browse the website, no matter their project membership.
+
+1. Click **Save changes**.
+
+The next time someone tries to access your website and the access control is
+enabled, they will be presented with a page to sign into GitLab and verify they
+can access the website.
+
+## Terminating a Pages session
+
+If you want to log out from your Pages website,
+you can do so by revoking application access token for GitLab Pages:
+
+1. Navigate to your profile's **Settings > Applications**.
+1. Find **Authorized applications** at the bottom of the page.
+1. Find **GitLab Pages** and press the **Revoke** button.
diff --git a/doc/user/project/protected_branches.md b/doc/user/project/protected_branches.md
index b7c9faeb1df..8ce575222b9 100644
--- a/doc/user/project/protected_branches.md
+++ b/doc/user/project/protected_branches.md
@@ -55,7 +55,7 @@ the actions that different roles can perform with the protected branch.
For example, you could set "Allowed to push" to "No one", and "Allowed to merge"
to "Developers + Maintainers", to require _everyone_ to submit a merge request for
changes going into the protected branch. This is compatible with workflows like
-the [GitLab workflow](../../workflow/gitlab_flow.md).
+the [GitLab workflow](../../topics/gitlab_flow.md).
However, there are workflows where that is not needed, and only protecting from
force pushes and branch removal is useful. For those workflows, you can allow
@@ -118,10 +118,11 @@ all matching branches:
When a protected branch or wildcard protected branches are set to
[**No one** is **Allowed to push**](#using-the-allowed-to-merge-and-allowed-to-push-settings),
-Developers (and users with higher [permission levels](../permissions.md)) are allowed
-to create a new protected branch, but only via the UI or through the API (to avoid
-creating protected branches accidentally from the command line or from a Git
-client application).
+Developers (and users with higher [permission levels](../permissions.md)) are
+allowed to create a new protected branch as long as they are
+[**Allowed to merge**](#using-the-allowed-to-merge-and-allowed-to-push-settings).
+This can only be done via the UI or through the API (to avoid creating protected
+branches accidentally from the command line or from a Git client application).
To create a new branch through the user interface:
diff --git a/doc/user/project/push_options.md b/doc/user/project/push_options.md
index 51c46dbd1d4..8952f845b96 100644
--- a/doc/user/project/push_options.md
+++ b/doc/user/project/push_options.md
@@ -75,3 +75,33 @@ merge request, and target a branch named `my-target-branch`:
```shell
git push -o merge_request.create -o merge_request.target=my-target-branch
```
+
+Additionally if you want the merge request to merge as soon as the pipeline succeeds you can do:
+
+```shell
+git push -o merge_request.create -o merge_request.target=my-target-branch -o merge_request.merge_when_pipeline_succeeds
+```
+
+## Useful Git aliases
+
+As shown above, Git push options can cause Git commands to grow very long. If
+you use the same push options frequently, it's useful to create [Git
+aliases](https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases). Git aliases
+are command line shortcuts for Git which can significantly simplify the use of
+long Git commands.
+
+### Merge when pipeline succeeds alias
+
+To set up a Git alias for the [merge when pipeline succeeds Git push
+option](#push-options-for-merge-requests):
+
+```shell
+git config --global alias.mwps "push -o merge_request.create -o merge_request.target=master -o merge_request.merge_when_pipeline_succeeds"
+```
+
+Then to quickly push a local branch that will target master and merge when the
+pipeline succeeds:
+
+```shell
+git mwps origin <local-branch-name>
+```
diff --git a/doc/user/project/releases/img/edit_release_page_v12_5.png b/doc/user/project/releases/img/edit_release_page_v12_5.png
new file mode 100644
index 00000000000..8b9c502a2ef
--- /dev/null
+++ b/doc/user/project/releases/img/edit_release_page_v12_5.png
Binary files differ
diff --git a/doc/user/project/releases/img/milestone_list_with_releases_v12_5.png b/doc/user/project/releases/img/milestone_list_with_releases_v12_5.png
new file mode 100644
index 00000000000..2e3ec08ba87
--- /dev/null
+++ b/doc/user/project/releases/img/milestone_list_with_releases_v12_5.png
Binary files differ
diff --git a/doc/user/project/releases/img/milestone_with_releases_v12_5.png b/doc/user/project/releases/img/milestone_with_releases_v12_5.png
new file mode 100644
index 00000000000..8719a58ce4e
--- /dev/null
+++ b/doc/user/project/releases/img/milestone_with_releases_v12_5.png
Binary files differ
diff --git a/doc/workflow/releases/new_tag.png b/doc/user/project/releases/img/new_tag_12_5.png
index 6137ad2ee56..6137ad2ee56 100644
--- a/doc/workflow/releases/new_tag.png
+++ b/doc/user/project/releases/img/new_tag_12_5.png
Binary files differ
diff --git a/doc/user/project/releases/img/release_edit_button_v12_5.png b/doc/user/project/releases/img/release_edit_button_v12_5.png
new file mode 100644
index 00000000000..f60b0ecb1be
--- /dev/null
+++ b/doc/user/project/releases/img/release_edit_button_v12_5.png
Binary files differ
diff --git a/doc/user/project/releases/img/release_with_milestone_v12_5.png b/doc/user/project/releases/img/release_with_milestone_v12_5.png
new file mode 100644
index 00000000000..2a7a2ee9754
--- /dev/null
+++ b/doc/user/project/releases/img/release_with_milestone_v12_5.png
Binary files differ
diff --git a/doc/workflow/releases/tags.png b/doc/user/project/releases/img/tags_12_5.png
index 4c032f96125..4c032f96125 100644
--- a/doc/workflow/releases/tags.png
+++ b/doc/user/project/releases/img/tags_12_5.png
Binary files differ
diff --git a/doc/user/project/releases/index.md b/doc/user/project/releases/index.md
index ceb077ab8af..8372aefc94c 100644
--- a/doc/user/project/releases/index.md
+++ b/doc/user/project/releases/index.md
@@ -58,6 +58,31 @@ links from your GitLab instance.
NOTE: **NOTE**
You can manipulate links of each release entry with [Release Links API](../../../api/releases/links.md)
+#### Releases associated with milestones
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/29020) in GitLab 12.5.
+
+Releases can optionally be associated with one or more
+[project milestones](../milestones/index.md#project-milestones-and-group-milestones)
+by including a `milestones` array in your requests to the
+[Releases API](../../../api/releases/index.md#create-a-release).
+
+Releases display this association with the **Milestone** indicator near
+the top of the Release block on the **Project overview > Releases** page.
+
+![A Release with one associated milestone](img/release_with_milestone_v12_5.png)
+
+Below is an example of milestones with no Releases, one Release, and two
+Releases, respectively.
+
+![Milestones with and without Release associations](img/milestone_list_with_releases_v12_5.png)
+
+This relationship is also visible in the **Releases** section of the sidebar
+when viewing a specific milestone. Below is an example of a milestone
+associated with a large number of Releases.
+
+![Milestone with lots of associated Releases](img/milestone_with_releases_v12_5.png)
+
## Releases list
Navigate to **Project > Releases** in order to see the list of releases for a given
@@ -65,6 +90,27 @@ project.
![Releases list](img/releases.png)
+## Editing a release
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/26016) in GitLab 12.5.
+
+To edit the details of a release, navigate to **Project overview > Releases** and click
+the edit button (pencil icon) in the top-right corner of the release you want to modify.
+
+![A release with an edit button](img/release_edit_button_v12_5.png)
+
+This will bring you to the **Edit Release** page, from which you can
+change some of the release's details.
+
+![Edit release page](img/edit_release_page_v12_5.png)
+
+Currently, it is only possible to edit the release title and notes.
+To change other release information, such as its tag, associated
+milestones, or release date, use the
+[Releases API](../../../api/releases/index.md#update-a-release). Editing this
+information through the **Edit Release** page is planned for a future version
+of GitLab.
+
## Notification for Releases
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/26001) in GitLab 12.4.
@@ -77,6 +123,91 @@ following modal window will be then displayed, from which you can select **New r
![Custom notification - New release](img/custom_notifications_new_release_v12_4.png)
+## Add release notes to Git tags
+
+You can add release notes to any Git tag using the notes feature. Release notes
+behave like any other markdown form in GitLab so you can write text and
+drag and drop files to it. Release notes are stored in GitLab's database.
+
+There are several ways to add release notes:
+
+- In the interface, when you create a new Git tag.
+- In the interface, by adding a note to an existing Git tag.
+- Using the GitLab API.
+
+To create a new tag, navigate to your project's **Repository > Tags** and
+click **New tag**. From there, you can fill the form with all the information
+about the release:
+
+![new_tag](img/new_tag_12_5.png "Creation of a new tag.")
+
+You can also edit an existing tag to add release notes:
+
+![tags](img/tags_12_5.png "Addition of note to an existing tag")
+
+## Release Evidence
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/26019) in GitLab 12.5.
+
+Each time a new release is created, specific related data is collected in
+parallel. This dataset will be a snapshot this new release (including linked
+milestones and issues) at moment of creation. Such collection of data will
+provide a chain of custody and facilitate processes like external audits, for example.
+
+The gathered Evidence data is stored in the database upon creation of a new
+release as a JSON object. In GitLab 12.5, a link to
+the Evidence data is provided for [each Release](#releases-list).
+
+Here's what this object can look like:
+
+```json
+{
+ "release": {
+ "id": 5,
+ "tag": "v4.0",
+ "name": "New release",
+ "project_id": 45,
+ "project_name": "Project name",
+ "released_at": "2019-06-28 13:23:40 UTC",
+ "milestones": [
+ {
+ "id": 11,
+ "title": "v4.0-rc1",
+ "state": "closed",
+ "due_date": "2019-05-12 12:00:00 UTC",
+ "created_at": "2019-04-17 15:45:12 UTC",
+ "issues": [
+ {
+ "id": 82,
+ "title": "The top-right popup is broken",
+ "author_name": "John Doe",
+ "author_email": "john@doe.com",
+ "state": "closed",
+ "due_date": "2019-05-10 12:00:00 UTC"
+ },
+ {
+ "id": 89,
+ "title": "The title of this page is misleading",
+ "author_name": "Jane Smith",
+ "author_email": "jane@smith.com",
+ "state": "closed",
+ "due_date": "nil"
+ }
+ ]
+ },
+ {
+ "id": 12,
+ "title": "v4.0-rc2",
+ "state": "closed",
+ "due_date": "2019-05-30 18:30:00 UTC",
+ "created_at": "2019-04-17 15:45:12 UTC",
+ "issues": []
+ }
+ ]
+ }
+}
+```
+
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
diff --git a/doc/user/project/repository/file_finder.md b/doc/user/project/repository/file_finder.md
new file mode 100644
index 00000000000..576001d4305
--- /dev/null
+++ b/doc/user/project/repository/file_finder.md
@@ -0,0 +1,45 @@
+---
+disqus_identifier: 'https://docs.gitlab.com/ee/workflow/file_finder.html'
+---
+
+# File finder
+
+> [Introduced][gh-9889] in GitLab 8.4.
+
+The file finder feature allows you to search for a file in a repository using the
+GitLab UI.
+
+You can find the **Find File** button when in the **Files** section of a
+project.
+
+![Find file button](img/file_finder_find_button.png)
+
+For those who prefer to keep their fingers on the keyboard, there is a
+[shortcut button](../../shortcuts.md) as well, which you can invoke from _anywhere_
+in a project.
+
+Press `t` to launch the File search function when in **Issues**,
+**Merge requests**, **Milestones**, even the project's settings.
+
+Start typing what you are searching for and watch the magic happen. With the
+up/down arrows, you go up and down the results, with `Esc` you close the search
+and go back to **Files**.
+
+## How it works
+
+The File finder feature is powered by the [Fuzzy filter](https://github.com/jeancroy/fuzz-aldrin-plus) library.
+
+It implements a fuzzy search with highlight, and tries to provide intuitive
+results by recognizing patterns that people use while searching.
+
+For example, consider the [GitLab CE repository][ce] and that we want to open
+the `app/controllers/admin/deploy_keys_controller.rb` file.
+
+Using fuzzy search, we start by typing letters that get us closer to the file.
+
+**Protip:** To narrow down your search, include `/` in your search terms.
+
+![Find file button](img/file_finder_find_file.png)
+
+[gh-9889]: https://github.com/gitlabhq/gitlabhq/pull/9889 "File finder pull request"
+[ce]: https://gitlab.com/gitlab-org/gitlab-foss/tree/master "GitLab CE repository"
diff --git a/doc/user/project/repository/forking_workflow.md b/doc/user/project/repository/forking_workflow.md
new file mode 100644
index 00000000000..8756760fe4b
--- /dev/null
+++ b/doc/user/project/repository/forking_workflow.md
@@ -0,0 +1,55 @@
+---
+disqus_identifier: 'https://docs.gitlab.com/ee/workflow/forking_workflow.html'
+---
+
+# Project forking workflow
+
+Forking a project to your own namespace is useful if you have no write
+access to the project you want to contribute to. If you do have write
+access or can request it, we recommend working together in the same
+repository since it is simpler. See our [GitLab Flow](../../../topics/gitlab_flow.md)
+document more information about using branches to work together.
+
+## Creating a fork
+
+Forking a project is in most cases a two-step process.
+
+1. Click on the fork button located located in between the star and clone buttons on the project's home page.
+
+ ![Fork button](img/forking_workflow_fork_button.png)
+
+1. Once you do that, you'll be presented with a screen where you can choose
+ the namespace to fork to. Only namespaces (groups and your own
+ namespace) where you have write access to, will be shown. Click on the
+ namespace to create your fork there.
+
+ ![Choose namespace](img/forking_workflow_choose_namespace.png)
+
+ **Note:**
+ If the namespace you chose to fork the project to has another project with
+ the same path name, you will be presented with a warning that the forking
+ could not be completed. Try to resolve the error before repeating the forking
+ process.
+
+ ![Path taken error](img/forking_workflow_path_taken_error.png)
+
+After the forking is done, you can start working on the newly created
+repository. There, you will have full [Owner](../../permissions.md)
+access, so you can set it up as you please.
+
+## Merging upstream
+
+Once you are ready to send your code back to the main project, you need
+to create a merge request. Choose your forked project's main branch as
+the source and the original project's main branch as the destination and
+create the [merge request](../merge_requests/index.md).
+
+![Selecting branches](img/forking_workflow_branch_select.png)
+
+You can then assign the merge request to someone to have them review
+your changes. Upon pressing the 'Submit Merge Request' button, your
+changes will be added to the repository and branch you're merging into.
+
+![New merge request](img/forking_workflow_merge_request.png)
+
+[gitlab flow]: https://about.gitlab.com/blog/2014/09/29/gitlab-flow/ "GitLab Flow blog post"
diff --git a/doc/workflow/img/file_finder_find_button.png b/doc/user/project/repository/img/file_finder_find_button.png
index 0c2d7d7bc73..0c2d7d7bc73 100644
--- a/doc/workflow/img/file_finder_find_button.png
+++ b/doc/user/project/repository/img/file_finder_find_button.png
Binary files differ
diff --git a/doc/workflow/img/file_finder_find_file.png b/doc/user/project/repository/img/file_finder_find_file.png
index c2212c7cd9e..c2212c7cd9e 100644
--- a/doc/workflow/img/file_finder_find_file.png
+++ b/doc/user/project/repository/img/file_finder_find_file.png
Binary files differ
diff --git a/doc/workflow/forking/branch_select.png b/doc/user/project/repository/img/forking_workflow_branch_select.png
index 0ea5410f832..0ea5410f832 100644
--- a/doc/workflow/forking/branch_select.png
+++ b/doc/user/project/repository/img/forking_workflow_branch_select.png
Binary files differ
diff --git a/doc/workflow/img/forking_workflow_choose_namespace.png b/doc/user/project/repository/img/forking_workflow_choose_namespace.png
index eb023ca85f2..eb023ca85f2 100644
--- a/doc/workflow/img/forking_workflow_choose_namespace.png
+++ b/doc/user/project/repository/img/forking_workflow_choose_namespace.png
Binary files differ
diff --git a/doc/workflow/img/forking_workflow_fork_button.png b/doc/user/project/repository/img/forking_workflow_fork_button.png
index 7fb07529b6d..7fb07529b6d 100644
--- a/doc/workflow/img/forking_workflow_fork_button.png
+++ b/doc/user/project/repository/img/forking_workflow_fork_button.png
Binary files differ
diff --git a/doc/workflow/forking/merge_request.png b/doc/user/project/repository/img/forking_workflow_merge_request.png
index 43851203f3f..43851203f3f 100644
--- a/doc/workflow/forking/merge_request.png
+++ b/doc/user/project/repository/img/forking_workflow_merge_request.png
Binary files differ
diff --git a/doc/workflow/img/forking_workflow_path_taken_error.png b/doc/user/project/repository/img/forking_workflow_path_taken_error.png
index ef62d0ab6a9..ef62d0ab6a9 100644
--- a/doc/workflow/img/forking_workflow_path_taken_error.png
+++ b/doc/user/project/repository/img/forking_workflow_path_taken_error.png
Binary files differ
diff --git a/doc/workflow/img/copy_ssh_public_key_button.png b/doc/user/project/repository/img/repository_mirroring_copy_ssh_public_key_button.png
index e20dae09a4d..e20dae09a4d 100644
--- a/doc/workflow/img/copy_ssh_public_key_button.png
+++ b/doc/user/project/repository/img/repository_mirroring_copy_ssh_public_key_button.png
Binary files differ
diff --git a/doc/workflow/img/repository_mirroring_force_update.png b/doc/user/project/repository/img/repository_mirroring_force_update.png
index 1e6dcb9ea08..1e6dcb9ea08 100644
--- a/doc/workflow/img/repository_mirroring_force_update.png
+++ b/doc/user/project/repository/img/repository_mirroring_force_update.png
Binary files differ
diff --git a/doc/workflow/img/repository_mirroring_pull_settings_lower.png b/doc/user/project/repository/img/repository_mirroring_pull_settings_lower.png
index a3e0b74ddf8..a3e0b74ddf8 100644
--- a/doc/workflow/img/repository_mirroring_pull_settings_lower.png
+++ b/doc/user/project/repository/img/repository_mirroring_pull_settings_lower.png
Binary files differ
diff --git a/doc/workflow/img/repository_mirroring_pull_settings_upper.png b/doc/user/project/repository/img/repository_mirroring_pull_settings_upper.png
index 8e15b5a0784..8e15b5a0784 100644
--- a/doc/workflow/img/repository_mirroring_pull_settings_upper.png
+++ b/doc/user/project/repository/img/repository_mirroring_pull_settings_upper.png
Binary files differ
diff --git a/doc/workflow/img/repository_mirroring_push_settings.png b/doc/user/project/repository/img/repository_mirroring_push_settings.png
index 3c0eacaa2df..3c0eacaa2df 100644
--- a/doc/workflow/img/repository_mirroring_push_settings.png
+++ b/doc/user/project/repository/img/repository_mirroring_push_settings.png
Binary files differ
diff --git a/doc/user/project/repository/index.md b/doc/user/project/repository/index.md
index c14783b72bd..5a6e011220c 100644
--- a/doc/user/project/repository/index.md
+++ b/doc/user/project/repository/index.md
@@ -11,7 +11,8 @@ A repository is part of a [project](../index.md), which has a lot of other featu
## Create a repository
To create a new repository, all you need to do is
-[create a new project](../../../gitlab-basics/create-project.md).
+[create a new project](../../../gitlab-basics/create-project.md) or
+[fork an existing project](forking_workflow.md).
Once you create a new project, you can add new files via UI
(read the section below) or via command line.
@@ -55,7 +56,7 @@ To get started with the command line, please read through the
### Find files
-Use GitLab's [file finder](../../../workflow/file_finder.md) to search for files in a repository.
+Use GitLab's [file finder](file_finder.md) to search for files in a repository.
### Supported markup languages and extensions
diff --git a/doc/user/project/repository/repository_mirroring.md b/doc/user/project/repository/repository_mirroring.md
new file mode 100644
index 00000000000..a682983ab83
--- /dev/null
+++ b/doc/user/project/repository/repository_mirroring.md
@@ -0,0 +1,430 @@
+---
+disqus_identifier: 'https://docs.gitlab.com/ee/workflow/repository_mirroring.html'
+---
+
+# Repository mirroring
+
+Repository mirroring allows for mirroring of repositories to and from external sources. It can be
+used to mirror branches, tags, and commits between repositories.
+
+A repository mirror at GitLab will be updated automatically. You can also manually trigger an update
+at most once every 5 minutes.
+
+## Overview
+
+Repository mirroring is useful when you want to use a repository outside of GitLab.
+
+There are two kinds of repository mirroring supported by GitLab:
+
+- Push: for mirroring a GitLab repository to another location.
+- Pull: for mirroring a repository from another location to GitLab. **(STARTER)**
+
+When the mirror repository is updated, all new branches, tags, and commits will be visible in the
+project's activity feed.
+
+Users with at least [developer access](../../permissions.md) to the project can also force an
+immediate update, unless:
+
+- The mirror is already being updated.
+- 5 minutes haven't elapsed since its last update.
+
+## Use cases
+
+The following are some possible use cases for repository mirroring:
+
+- You migrated to GitLab but still need to keep your project in another source. In that case, you
+ can simply set it up to mirror to GitLab (pull) and all the essential history of commits, tags,
+ and branches will be available in your GitLab instance. **(STARTER)**
+- You have old projects in another source that you don't use actively anymore, but don't want to
+ remove for archiving purposes. In that case, you can create a push mirror so that your active
+ GitLab repository can push its changes to the old location.
+
+## Pushing to a remote repository **(CORE)**
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/249) in GitLab Enterprise Edition 8.7.
+> - [Moved to GitLab Core](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/18715) in 10.8.
+
+For an existing project, you can set up push mirroring as follows:
+
+1. Navigate to your project's **Settings > Repository** and expand the **Mirroring repositories** section.
+1. Enter a repository URL.
+1. Select **Push** from the **Mirror direction** dropdown.
+1. Select an authentication method from the **Authentication method** dropdown, if necessary.
+1. Check the **Only mirror protected branches** box, if necessary.
+1. Click the **Mirror repository** button to save the configuration.
+
+![Repository mirroring push settings screen](img/repository_mirroring_push_settings.png)
+
+When push mirroring is enabled, only push commits directly to the mirrored repository to prevent the
+mirror diverging. All changes will end up in the mirrored repository whenever:
+
+- Commits are pushed to GitLab.
+- A [forced update](#forcing-an-update-core) is initiated.
+
+Changes pushed to files in the repository are automatically pushed to the remote mirror at least:
+
+- Within five minutes of being received.
+- Within one minute if **Only mirror protected branches** is enabled.
+
+In the case of a diverged branch, you will see an error indicated at the **Mirroring repositories**
+section.
+
+### Push only protected branches **(CORE)**
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/3350) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.3.
+> - [Moved to GitLab Core](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/18715) in 10.8.
+
+You can choose to only push your protected branches from GitLab to your remote repository.
+
+To use this option, check the **Only mirror protected branches** box when creating a repository
+mirror.
+
+## Setting up a push mirror from GitLab to GitHub **(CORE)**
+
+To set up a mirror from GitLab to GitHub, you need to follow these steps:
+
+1. Create a [GitHub personal access token](https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line) with the `public_repo` box checked.
+1. Fill in the **Git repository URL** field using this format: `https://<your_github_username>@github.com/<your_github_group>/<your_github_project>.git`.
+1. Fill in **Password** field with your GitHub personal access token.
+1. Click the **Mirror repository** button.
+
+The mirrored repository will be listed. For example, `https://*****:*****@github.com/<your_github_group>/<your_github_project>.git`.
+
+The repository will push soon. To force a push, click the appropriate button.
+
+## Setting up a push mirror to another GitLab instance with 2FA activated
+
+1. On the destination GitLab instance, create a [personal access token](../../profile/personal_access_tokens.md) with `API` scope.
+1. On the source GitLab instance:
+ 1. Fill in the **Git repository URL** field using this format: `https://oauth2@<destination host>/<your_gitlab_group_or_name>/<your_gitlab_project>.git`.
+ 1. Fill in **Password** field with the GitLab personal access token created on the destination GitLab instance.
+ 1. Click the **Mirror repository** button.
+
+## Pulling from a remote repository **(STARTER)**
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/51) in GitLab Enterprise Edition 8.2.
+> - [Added Git LFS support](https://gitlab.com/gitlab-org/gitlab/issues/10871) in [GitLab Starter](https://about.gitlab.com/pricing/) 11.11.
+
+NOTE: **Note:** This feature [is available for free](https://gitlab.com/gitlab-org/gitlab/issues/10361) to
+GitLab.com users until March 22nd, 2020.
+
+You can set up a repository to automatically have its branches, tags, and commits updated from an
+upstream repository.
+
+This is useful when a repository you're interested in is located on a different server, and you want
+to be able to browse its content and its activity using the familiar GitLab interface.
+
+To configure mirror pulling for an existing project:
+
+1. Navigate to your project's **Settings > Repository** and expand the **Mirroring repositories**
+ section.
+1. Enter a repository URL.
+1. Select **Pull** from the **Mirror direction** dropdown.
+1. Select an authentication method from the **Authentication method** dropdown, if necessary.
+1. If necessary, check the following boxes:
+ - **Overwrite diverged branches**.
+ - **Trigger pipelines for mirror updates**.
+ - **Only mirror protected branches**.
+1. Click the **Mirror repository** button to save the configuration.
+
+![Repository mirroring pull settings screen - upper part](img/repository_mirroring_pull_settings_upper.png)
+
+---
+
+![Repository mirroring pull settings screen - lower part](img/repository_mirroring_pull_settings_lower.png)
+
+Because GitLab is now set to pull changes from the upstream repository, you should not push commits
+directly to the repository on GitLab. Instead, any commits should be pushed to the upstream repository.
+Changes pushed to the upstream repository will be pulled into the GitLab repository, either:
+
+- Automatically within a certain period of time.
+- When a [forced update](#forcing-an-update-core) is initiated.
+
+CAUTION: **Caution:**
+If you do manually update a branch in the GitLab repository, the branch will become diverged from
+upstream and GitLab will no longer automatically update this branch to prevent any changes from being lost.
+
+### How it works
+
+Once the pull mirroring feature has been enabled for a repository, the repository is added to a queue.
+
+Once per minute, a Sidekiq cron job schedules repository mirrors to update, based on:
+
+- The capacity available. This is determined by Sidekiq settings. For GitLab.com, see [GitLab.com Sidekiq settings](../../gitlab_com/index.md#sidekiq).
+- The number of repository mirrors already in the queue that are due to be updated. Being due depends on when the repository mirror was last updated and how many times it's been retried.
+
+Repository mirrors are updated as Sidekiq becomes available to process them. If the process of updating the repository mirror:
+
+- Succeeds, an update will be enqueued again with at least a 30 minute wait.
+- Fails (for example, a branch diverged from upstream), it will be attempted again later. Mirrors can fail
+ up to 14 times before they will not be enqueued for update again.
+
+### SSH authentication
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/2551) for Pull mirroring in [GitLab Starter](https://about.gitlab.com/pricing/) 9.5.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/22982) for Push mirroring in [GitLab Core](https://about.gitlab.com/pricing/) 11.6
+
+SSH authentication is mutual:
+
+- You have to prove to the server that you're allowed to access the repository.
+- The server also has to prove to *you* that it's who it claims to be.
+
+You provide your credentials as a password or public key. The server that the
+other repository resides on provides its credentials as a "host key", the
+fingerprint of which needs to be verified manually.
+
+If you're mirroring over SSH (that is, using an `ssh://` URL), you can authenticate using:
+
+- Password-based authentication, just as over HTTPS.
+- Public key authentication. This is often more secure than password authentication,
+ especially when the other repository supports [Deploy Keys](../../../ssh/README.md#deploy-keys).
+
+To get started:
+
+1. Navigate to your project's **Settings > Repository** and expand the **Mirroring repositories** section.
+1. Enter an `ssh://` URL for mirroring.
+
+NOTE: **Note:**
+SCP-style URLs (that is, `git@example.com:group/project.git`) are not supported at this time.
+
+Entering the URL adds two buttons to the page:
+
+- **Detect host keys**.
+- **Input host keys manually**.
+
+If you click the:
+
+- **Detect host keys** button, GitLab will fetch the host keys from the server and display the fingerprints.
+- **Input host keys manually** button, a field is displayed where you can paste in host keys.
+
+Assuming you used the former, you now need to verify that the fingerprints are
+those you expect. GitLab.com and other code hosting sites publish their
+fingerprints in the open for you to check:
+
+- [AWS CodeCommit](https://docs.aws.amazon.com/codecommit/latest/userguide/regions.html#regions-fingerprints)
+- [Bitbucket](https://confluence.atlassian.com/bitbucket/ssh-keys-935365775.html)
+- [GitHub](https://help.github.com/en/articles/githubs-ssh-key-fingerprints)
+- [GitLab.com](../../gitlab_com/index.md#ssh-host-keys-fingerprints)
+- [Launchpad](https://help.launchpad.net/SSHFingerprints)
+- [Savannah](http://savannah.gnu.org/maintenance/SshAccess/)
+- [SourceForge](https://sourceforge.net/p/forge/documentation/SSH%20Key%20Fingerprints/)
+
+Other providers will vary. If you're running self-managed GitLab, or otherwise
+have access to the server for the other repository, you can securely gather the
+key fingerprints:
+
+```sh
+$ cat /etc/ssh/ssh_host*pub | ssh-keygen -E md5 -l -f -
+256 MD5:f4:28:9f:23:99:15:21:1b:bf:ed:1f:8e:a0:76:b2:9d root@example.com (ECDSA)
+256 MD5:e6:eb:45:8a:3c:59:35:5f:e9:5b:80:12:be:7e:22:73 root@example.com (ED25519)
+2048 MD5:3f:72:be:3d:62:03:5c:62:83:e8:6e:14:34:3a:85:1d root@example.com (RSA)
+```
+
+NOTE: **Note:**
+You may need to exclude `-E md5` for some older versions of SSH.
+
+When mirroring the repository, GitLab will now check that at least one of the
+stored host keys matches before connecting. This can prevent malicious code from
+being injected into your mirror, or your password being stolen.
+
+### SSH public key authentication
+
+To use SSH public key authentication, you'll also need to choose that option
+from the **Authentication method** dropdown. When the mirror is created,
+GitLab generates a 4096-bit RSA key that can be copied by clicking the **Copy SSH public key** button.
+
+![Repository mirroring copy SSH public key to clipboard button](img/repository_mirroring_copy_ssh_public_key_button.png)
+
+You then need to add the public SSH key to the other repository's configuration:
+
+- If the other repository is hosted on GitLab, you should add the public SSH key
+ as a [Deploy Key](../../../ssh/README.md#deploy-keys).
+- If the other repository is hosted elsewhere, you may need to add the key to
+ your user's `authorized_keys` file. Paste the entire public SSH key into the
+ file on its own line and save it.
+
+If you need to change the key at any time, you can remove and re-add the mirror
+to generate a new key. You'll have to update the other repository with the new
+key to keep the mirror running.
+
+### Overwrite diverged branches **(STARTER)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/4559) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.6.
+
+You can choose to always update your local branches with remote versions, even if they have
+diverged from the remote.
+
+CAUTION: **Caution:**
+For mirrored branches, enabling this option results in the loss of local changes.
+
+To use this option, check the **Overwrite diverged branches** box when creating a repository mirror.
+
+### Only mirror protected branches **(STARTER)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/3326) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.3.
+
+You can choose to pull mirror only the protected branches from your remote repository to GitLab.
+Non-protected branches are not mirrored and can diverge.
+
+To use this option, check the **Only mirror protected branches** box when creating a repository mirror.
+
+### Hard failure **(STARTER)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/3117) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.2.
+
+Once the mirroring process is unsuccessfully retried 14 times in a row, it will get marked as hard
+failed. This will become visible in either the:
+
+- Project's main dashboard.
+- Pull mirror settings page.
+
+When a project is hard failed, it will no longer get picked up for mirroring. A user can resume the
+project mirroring again by [Forcing an update](#forcing-an-update-core).
+
+### Trigger update using API **(STARTER)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/3453) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.3.
+
+Pull mirroring uses polling to detect new branches and commits added upstream, often minutes
+afterwards. If you notify GitLab by [API](../../../api/projects.md#start-the-pull-mirroring-process-for-a-project-starter),
+updates will be pulled immediately.
+
+For more information, see [Start the pull mirroring process for a Project](../../../api/projects.md#start-the-pull-mirroring-process-for-a-project-starter).
+
+## Forcing an update **(CORE)**
+
+While mirrors are scheduled to update automatically, you can always force an update by using the
+update button which is available on the **Mirroring repositories** section of the **Repository Settings** page.
+
+![Repository mirroring force update user interface](img/repository_mirroring_force_update.png)
+
+## Bidirectional mirroring **(STARTER)**
+
+CAUTION: **Caution:**
+Bidirectional mirroring may cause conflicts.
+
+If you configure a GitLab repository to both pull from, and push to, the same remote source, there
+is no guarantee that either repository will update correctly. If you set up a repository for
+bidirectional mirroring, you should prepare for the likely conflicts by deciding who will resolve
+them and how they will be resolved.
+
+Rewriting any mirrored commit on either remote will cause conflicts and mirroring to fail. This can
+be prevented by:
+
+- [Pulling only protected branches](#only-mirror-protected-branches-starter).
+- [Pushing only protected branches](#push-only-protected-branches-core).
+
+You should [protect the branches](../protected_branches.md) you wish to mirror on both
+remotes to prevent conflicts caused by rewriting history.
+
+Bidirectional mirroring also creates a race condition where commits made close together to the same
+branch causes conflicts. The race condition can be mitigated by reducing the mirroring delay by using
+a [Push event webhook](../integrations/webhooks.md#push-events) to trigger an immediate
+pull to GitLab. Push mirroring from GitLab is rate limited to once per minute when only push mirroring
+protected branches.
+
+### Preventing conflicts using a `pre-receive` hook
+
+CAUTION: **Warning:**
+The solution proposed will negatively impact the performance of
+Git push operations because they will be proxied to the upstream Git
+repository.
+
+A server-side `pre-receive` hook can be used to prevent the race condition
+described above by only accepting the push after first pushing the commit to
+the upstream Git repository. In this configuration one Git repository acts as
+the authoritative upstream, and the other as downstream. The `pre-receive` hook
+will be installed on the downstream repository.
+
+Read about [configuring custom Git hooks](../../../administration/custom_hooks.md) on the GitLab server.
+
+A sample `pre-receive` hook is provided below.
+
+```bash
+#!/usr/bin/env bash
+
+# --- Assume only one push mirror target
+# Push mirroring remotes are named `remote_mirror_<id>`, this finds the first remote and uses that.
+TARGET_REPO=$(git remote | grep -m 1 remote_mirror)
+
+proxy_push()
+{
+ # --- Arguments
+ OLDREV=$(git rev-parse $1)
+ NEWREV=$(git rev-parse $2)
+ REFNAME="$3"
+
+ # --- Pattern of branches to proxy pushes
+ whitelisted=$(expr "$branch" : "\(master\)")
+
+ case "$refname" in
+ refs/heads/*)
+ branch=$(expr "$refname" : "refs/heads/\(.*\)")
+
+ if [ "$whitelisted" = "$branch" ]; then
+ error="$(git push --quiet $TARGET_REPO $NEWREV:$REFNAME 2>&1)"
+ fail=$?
+
+ if [ "$fail" != "0" ]; then
+ echo >&2 ""
+ echo >&2 " Error: updates were rejected by upstream server"
+ echo >&2 " This is usually caused by another repository pushing changes"
+ echo >&2 " to the same ref. You may want to first integrate remote changes"
+ echo >&2 ""
+ return
+ fi
+ fi
+ ;;
+ esac
+}
+
+# Allow dual mode: run from the command line just like the update hook, or
+# if no arguments are given then run as a hook script
+if [ -n "$1" -a -n "$2" -a -n "$3" ]; then
+ # Output to the terminal in command line mode - if someone wanted to
+ # resend an email; they could redirect the output to sendmail
+ # themselves
+ PAGER= proxy_push $2 $3 $1
+else
+ # Push is proxied upstream one ref at a time. Because of this it is possible
+ # for some refs to succeed, and others to fail. This will result in a failed
+ # push.
+ while read oldrev newrev refname
+ do
+ proxy_push $oldrev $newrev $refname
+ done
+fi
+```
+
+### Mirroring with Perforce Helix via Git Fusion **(STARTER)**
+
+CAUTION: **Warning:**
+Bidirectional mirroring should not be used as a permanent configuration. Refer to
+[Migrating from Perforce Helix](../import/perforce.md) for alternative migration approaches.
+
+[Git Fusion](https://www.perforce.com/manuals/git-fusion/#Git-Fusion/section_avy_hyc_gl.html) provides a Git interface
+to [Perforce Helix](https://www.perforce.com/products) which can be used by GitLab to bidirectionally
+mirror projects with GitLab. This may be useful in some situations when migrating from Perforce Helix
+to GitLab where overlapping Perforce Helix workspaces cannot be migrated simultaneously to GitLab.
+
+If using mirroring with Perforce Helix, you should only mirror protected branches. Perforce Helix
+will reject any pushes that rewrite history. Only the fewest number of branches should be mirrored
+due to the performance limitations of Git Fusion.
+
+When configuring mirroring with Perforce Helix via Git Fusion, the following Git Fusion
+settings are recommended:
+
+- `change-pusher` should be disabled. Otherwise, every commit will be rewritten as being committed
+ by the mirroring account, rather than being mapped to existing Perforce Helix users or the `unknown_git` user.
+- `unknown_git` user will be used as the commit author if the GitLab user does not exist in
+ Perforce Helix.
+
+Read about [Git Fusion settings on Perforce.com](https://www.perforce.com/manuals/git-fusion/Content/Git-Fusion/section_vss_bdw_w3.html#section_zdp_zz1_3l).
+
+## Troubleshooting
+
+Should an error occur during a push, GitLab will display an "Error" highlight for that repository. Details on the error can then be seen by hovering over the highlight text.
+
+### 13:Received RST_STREAM with error code 2 with GitHub
+
+If you receive an "13:Received RST_STREAM with error code 2" while mirroring to a GitHub repository, your GitHub settings might be set to block pushes that expose your email address used in commits. Either set your email address on GitHub to be public, or disable the [Block command line pushes that expose my email](https://github.com/settings/emails) setting.
diff --git a/doc/user/project/settings/index.md b/doc/user/project/settings/index.md
index 131999dbf60..2dc507901d0 100644
--- a/doc/user/project/settings/index.md
+++ b/doc/user/project/settings/index.md
@@ -49,10 +49,11 @@ Add an [issue description template](../description_templates.md#description-temp
Set up your project's merge request settings:
- Set up the merge request method (merge commit, [fast-forward merge](../merge_requests/fast_forward_merge.html)).
-- Merge request [description templates](../description_templates.md#description-templates).
+- Add merge request [description templates](../description_templates.md#description-templates).
- Enable [merge request approvals](../merge_requests/merge_request_approvals.md). **(STARTER)**
-- Enable [merge only of pipeline succeeds](../merge_requests/merge_when_pipeline_succeeds.md).
-- Enable [merge only when all discussions are resolved](../../discussions/index.md#only-allow-merge-requests-to-be-merged-if-all-threads-are-resolved).
+- Enable [merge only if pipeline succeeds](../merge_requests/merge_when_pipeline_succeeds.md).
+- Enable [merge only when all threads are resolved](../../discussions/index.md#only-allow-merge-requests-to-be-merged-if-all-threads-are-resolved).
+- Enable [`delete source branch after merge` option by default](../merge_requests/creating_merge_requests.md#deleting-the-source-branch)
![project's merge request settings](img/merge_requests_settings.png)
diff --git a/doc/user/project/time_tracking.md b/doc/user/project/time_tracking.md
new file mode 100644
index 00000000000..9cdee0f2b5a
--- /dev/null
+++ b/doc/user/project/time_tracking.md
@@ -0,0 +1,92 @@
+---
+type: reference
+disqus_identifier: 'https://docs.gitlab.com/ee/workflow/time_tracking.html'
+---
+
+# Time Tracking
+
+> Introduced in GitLab 8.14.
+
+Time Tracking allows you to track estimates and time spent on issues and merge
+requests within GitLab.
+
+## Overview
+
+Time Tracking allows you to:
+
+- Record the time spent working on an issue or a merge request.
+- Add an estimate of the amount of time needed to complete an issue or a merge
+ request.
+
+You don't have to indicate an estimate to enter the time spent, and vice versa.
+
+Data about time tracking is shown on the issue/merge request sidebar, as shown
+below.
+
+![Time tracking in the sidebar](img/time_tracking_sidebar_v8_16.png)
+
+## How to enter data
+
+Time Tracking uses two [quick actions](quick_actions.md)
+that GitLab introduced with this new feature: `/spend` and `/estimate`.
+
+Quick actions can be used in the body of an issue or a merge request, but also
+in a comment in both an issue or a merge request.
+
+Below is an example of how you can use those new quick actions inside a comment.
+
+![Time tracking example in a comment](img/time_tracking_example_v12_2.png)
+
+Adding time entries (time spent or estimates) is limited to project members.
+
+### Estimates
+
+To enter an estimate, write `/estimate`, followed by the time. For example, if
+you need to enter an estimate of 3 days, 5 hours and 10 minutes, you would write
+`/estimate 3d 5h 10m`. Time units that we support are listed at the bottom of
+this help page.
+
+Every time you enter a new time estimate, any previous time estimates will be
+overridden by this new value. There should only be one valid estimate in an
+issue or a merge request.
+
+To remove an estimation entirely, use `/remove_estimate`.
+
+### Time spent
+
+To enter a time spent, use `/spend 3d 5h 10m`.
+
+Every new time spent entry will be added to the current total time spent for the
+issue or the merge request.
+
+You can remove time by entering a negative amount: `/spend -3d` will remove 3
+days from the total time spent. You can't go below 0 minutes of time spent,
+so GitLab will automatically reset the time spent if you remove a larger amount
+of time compared to the time that was entered already.
+
+To remove all the time spent at once, use `/remove_time_spent`.
+
+## Configuration
+
+The following time units are available:
+
+- Months (mo)
+- Weeks (w)
+- Days (d)
+- Hours (h)
+- Minutes (m)
+
+Default conversion rates are 1mo = 4w, 1w = 5d and 1d = 8h.
+
+### Limit displayed units to hours **(CORE ONLY)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/29469/) in GitLab 12.1.
+
+In GitLab self-managed instances, the display of time units can be limited to
+hours through the option in **Admin Area > Settings > Preferences** under **Localization**.
+
+With this option enabled, `75h` is displayed instead of `1w 4d 3h`.
+
+## Other interesting links
+
+- [Time Tracking landing page in the GitLab handbook](https://about.gitlab.com/solutions/time-tracking/)
diff --git a/doc/user/search/advanced_search_syntax.md b/doc/user/search/advanced_search_syntax.md
index d65dd32fe11..faa3a118137 100644
--- a/doc/user/search/advanced_search_syntax.md
+++ b/doc/user/search/advanced_search_syntax.md
@@ -17,6 +17,8 @@ The Advanced Syntax Search is a subset of the
[Advanced Global Search](advanced_global_search.md), which you can use if you
want to have more specific search results.
+Advanced Global Search only supports searching the [default branch](../project/repository/branches/index.md#default-branch).
+
## Use cases
Let's say for example that the product you develop relies on the code of another
diff --git a/doc/user/search/img/issue_search_filter_v12_5.png b/doc/user/search/img/issue_search_filter_v12_5.png
new file mode 100644
index 00000000000..1e2dd3d98a3
--- /dev/null
+++ b/doc/user/search/img/issue_search_filter_v12_5.png
Binary files differ
diff --git a/doc/user/search/index.md b/doc/user/search/index.md
index 8d7b4a429aa..bc31052b758 100644
--- a/doc/user/search/index.md
+++ b/doc/user/search/index.md
@@ -32,13 +32,14 @@ on the search field on the top-right of your screen:
If you want to search for issues present in a specific project, navigate to
a project's **Issues** tab, and click on the field **Search or filter results...**. It will
display a dropdown menu, from which you can add filters per author, assignee, milestone,
-label, weight, and 'my-reaction' (based on your emoji votes). When done, press **Enter** on your keyboard to filter the issues.
+release, label, weight, confidentiality, and "my-reaction" (based on your emoji votes).
+When done, press **Enter** on your keyboard to filter the issues.
-![filter issues in a project](img/issue_search_filter.png)
+![filter issues in a project](img/issue_search_filter_v12_5.png)
The same process is valid for merge requests. Navigate to your project's **Merge Requests** tab,
and click **Search or filter results...**. Merge requests can be filtered by author, assignee,
-milestone, and label.
+approver, milestone, release, label, "my-reaction", "work in progess" status, and target branch.
### Filtering by **None** / **Any**
@@ -99,8 +100,8 @@ quickly access issues and merge requests created or assigned to you within that
## To-Do List
-Your [To-Do List](../../workflow/todos.md#gitlab-to-do-list) can be searched by "to do" and "done".
-You can [filter](../../workflow/todos.md#filtering-your-to-do-list) them per project,
+Your [To-Do List](../todos.md#gitlab-to-do-list) can be searched by "to do" and "done".
+You can [filter](../todos.md#filtering-your-to-do-list) them per project,
author, type, and action. Also, you can sort them by
[**Label priority**](../../user/project/labels.md#label-priority),
**Last created** and **Oldest created**.
diff --git a/doc/user/shortcuts.md b/doc/user/shortcuts.md
new file mode 100644
index 00000000000..54e7938d8f7
--- /dev/null
+++ b/doc/user/shortcuts.md
@@ -0,0 +1,135 @@
+---
+type: reference
+disqus_identifier: 'https://docs.gitlab.com/ee/workflow/shortcuts.html'
+---
+
+# GitLab keyboard shortcuts
+
+GitLab has many useful keyboard shortcuts to make it easier to access different features.
+You can see the quick reference sheet within GitLab itself with <kbd>Shift</kbd> + <kbd>?</kbd>.
+
+The [Global Shortcuts](#global-shortcuts) work from any area of GitLab, but you must
+be in specific pages for the other shortcuts to be available, as explained in each
+section below.
+
+## Global Shortcuts
+
+These shortcuts are available in most areas of GitLab
+
+| Keyboard Shortcut | Description |
+| ------------------------------- | ----------- |
+| <kbd>?</kbd> | Show/hide shortcut reference sheet. |
+| <kbd>Shift</kbd> + <kbd>p</kbd> | Go to your Projects page. |
+| <kbd>Shift</kbd> + <kbd>g</kbd> | Go to your Groups page. |
+| <kbd>Shift</kbd> + <kbd>a</kbd> | Go to your Activity page. |
+| <kbd>Shift</kbd> + <kbd>l</kbd> | Go to your Milestones page. |
+| <kbd>Shift</kbd> + <kbd>s</kbd> | Go to your Snippets page. |
+| <kbd>s</kbd> | Put cursor in the issues/merge requests search. |
+| <kbd>Shift</kbd> + <kbd>i</kbd> | Go to your Issues page. |
+| <kbd>Shift</kbd> + <kbd>m</kbd> | Go to your Merge requests page.|
+| <kbd>Shift</kbd> + <kbd>t</kbd> | Go to your To-Do List page. |
+| <kbd>p</kbd> + <kbd>b</kbd> | Show/hide the Performance Bar. |
+
+Additionally, the following shortcuts are available when editing text in text fields,
+for example comments, replies, or issue and merge request descriptions:
+
+| Keyboard Shortcut | Description |
+| ---------------------------------------------------------------------- | ----------- |
+| <kbd>↑</kbd> | Edit your last comment. You must be in a blank text field below a thread, and you must already have at least one comment in the thread. |
+| <kbd>⌘</kbd> (Mac) / <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>p</kbd> | Toggle Markdown preview, when editing text in a text field that has **Write** and **Preview** tabs at the top. |
+
+## Project
+
+These shortcuts are available from any page within a project. You must type them
+relatively quickly to work, and they will take you to another page in the project.
+
+| Keyboard Shortcut | Description |
+| --------------------------- | ----------- |
+| <kbd>g</kbd> + <kbd>p</kbd> | Go to the project home page (**Project > Details**). |
+| <kbd>g</kbd> + <kbd>v</kbd> | Go to the project activity feed (**Project > Activity**). |
+| <kbd>g</kbd> + <kbd>r</kbd> | Go to the project releases list (**Project > Releases**). |
+| <kbd>g</kbd> + <kbd>f</kbd> | Go to the [project files](#project-files) list (**Repository > Files**). |
+| <kbd>t</kbd> | Go to the project file search page. (**Repository > Files**, click **Find Files**). |
+| <kbd>g</kbd> + <kbd>c</kbd> | Go to the project commits list (**Repository > Commits**). |
+| <kbd>g</kbd> + <kbd>n</kbd> | Go to the [repository graph](#repository-graph) page (**Repository > Graph**). |
+| <kbd>g</kbd> + <kbd>d</kbd> | Go to repository charts (**Repository > Charts**). |
+| <kbd>g</kbd> + <kbd>i</kbd> | Go to the project issues list (**Issues > List**). |
+| <kbd>i</kbd> | Go to the New Issue page (**Issues**, click **New Issue** ). |
+| <kbd>g</kbd> + <kbd>b</kbd> | Go to the project issue boards list (**Issues > Boards**). |
+| <kbd>g</kbd> + <kbd>m</kbd> | Go to the project merge requests list (**Merge Requests**). |
+| <kbd>g</kbd> + <kbd>j</kbd> | Go to the CI/CD jobs list (**CI/CD > Jobs**). |
+| <kbd>g</kbd> + <kbd>l</kbd> | Go to the project metrics (**Operations > Metrics**). |
+| <kbd>g</kbd> + <kbd>e</kbd> | Go to the project environments (**Operations > Environments**). |
+| <kbd>g</kbd> + <kbd>k</kbd> | Go to the project Kubernetes cluster integration page (**Operations > Kubernetes**). Note that you must have at least [`maintainer` permissions](permissions.md) to access this page. |
+| <kbd>g</kbd> + <kbd>s</kbd> | Go to the project snippets list (**Snippets**). |
+| <kbd>g</kbd> + <kbd>w</kbd> | Go to the project wiki (**Wiki**), if enabled. |
+
+### Issues and Merge Requests
+
+These shortcuts are available when viewing issues and merge requests.
+
+| Keyboard Shortcut | Description |
+| ---------------------------- | ----------- |
+| <kbd>e</kbd> | Edit description. |
+| <kbd>a</kbd> | Change assignee. |
+| <kbd>m</kbd> | Change milestone. |
+| <kbd>l</kbd> | Change label. |
+| <kbd>r</kbd> | Start writing a comment. If any text is selected, it will be quoted in the comment. Can't be used to reply within a thread. |
+| <kbd>n</kbd> | Move to next unresolved discussion (Merge requests only). |
+| <kbd>p</kbd> | Move to previous unresolved discussion (Merge requests only). |
+| <kbd>]</kbd> or <kbd>j</kbd> | Move to next file (Merge requests only). |
+| <kbd>[</kbd> or <kbd>k</kbd> | Move to previous file (Merge requests only). |
+
+### Project Files
+
+These shortcuts are available when browsing the files in a project (navigate to
+**Repository** > **Files**):
+
+| Keyboard Shortcut | Description |
+| ----------------- | ----------- |
+| <kbd>↑</kbd> | Move selection up. |
+| <kbd>↓</kbd> | Move selection down. |
+| <kbd>enter</kbd> | Open selection. |
+| <kbd>esc</kbd> | Go back to file list screen (only while searching for files, **Repository > Files** then click on **Find File**). |
+| <kbd>y</kbd> | Go to file permalink (only while viewing a file). |
+
+### Web IDE
+
+These shortcuts are available when editing a file with the [Web IDE](project/web_ide/index.md):
+
+| Keyboard Shortcut | Description |
+| ------------------------------------------------------- | ----------- |
+| <kbd>⌘</kbd> (Mac) / <kbd>Ctrl</kbd> + <kbd>p</kbd> | Search for, and then open another file for editing. |
+| <kbd>⌘</kbd> (Mac) / <kbd>Ctrl</kbd> + <kbd>Enter</kbd> | Commit (when editing the commit message). |
+
+### Repository Graph
+
+These shortcuts are available when viewing the project [repository graph](project/repository/index.md#repository-graph)
+page (navigate to **Repository > Graph**):
+
+| Keyboard Shortcut | Description |
+| ------------------------------------------------------------------ | ----------- |
+| <kbd>←</kbd> or <kbd>h</kbd> | Scroll left. |
+| <kbd>→</kbd> or <kbd>l</kbd> | Scroll right. |
+| <kbd>↑</kbd> or <kbd>k</kbd> | Scroll up. |
+| <kbd>↓</kbd> or <kbd>j</kbd> | Scroll down. |
+| <kbd>Shift</kbd> + <kbd>↑</kbd> or <kbd>Shift</kbd> + <kbd>k</kbd> | Scroll to top. |
+| <kbd>Shift</kbd> + <kbd>↓</kbd> or <kbd>Shift</kbd> + <kbd>j</kbd> | Scroll to bottom. |
+
+### Wiki pages
+
+This shortcut is available when viewing a [wiki page](project/wiki/index.md):
+
+| Keyboard Shortcut | Description |
+| ----------------- | ----------- |
+| <kbd>e</kbd> | Edit wiki page. |
+
+## Epics **(ULTIMATE)**
+
+These shortcuts are available when viewing [Epics](group/epics/index.md):
+
+| Keyboard Shortcut | Description |
+| ----------------- | ----------- |
+| <kbd>r</kbd> | Start writing a comment. If any text is selected, it will be quoted in the comment. Can't be used to reply within a thread. |
+| <kbd>e</kbd> | Edit description. |
+| <kbd>l</kbd> | Change label. |
diff --git a/doc/user/todos.md b/doc/user/todos.md
new file mode 100644
index 00000000000..d53baa688a4
--- /dev/null
+++ b/doc/user/todos.md
@@ -0,0 +1,142 @@
+---
+disqus_identifier: 'https://docs.gitlab.com/ee/workflow/todos.html'
+---
+
+# GitLab To-Do List
+
+> [Introduced][ce-2817] in GitLab 8.5.
+
+When you log into GitLab, you normally want to see where you should spend your
+time, take some action, or know what you need to keep an eye on without
+a huge pile of e-mail notifications. GitLab is where you do your work,
+so being able to get started quickly is important.
+
+Your To-Do List offers a chronological list of items that are waiting for your input, all
+in a simple dashboard.
+
+![To Do screenshot showing a list of items to check on](img/todos_index.png)
+
+You can quickly access your To-Do List by clicking the checkmark icon next to the
+search bar in the top navigation. If the count is:
+
+- Less than 100, the number in blue is the number of To-Do items.
+- 100 or more, the number displays as 99+. The exact number displays
+ on the To-Do List.
+you still have open. Otherwise, the number displays as 99+. The exact number
+displays on the To-Do List.
+
+![To Do icon](img/todos_icon.png)
+
+## What triggers a To Do
+
+A To Do displays on your To-Do List when:
+
+- An issue or merge request is assigned to you
+- You are `@mentioned` in the description or comment of an:
+ - Issue
+ - Merge Request
+ - Epic **(ULTIMATE)**
+- You are `@mentioned` in a comment on a commit
+- A job in the CI pipeline running for your merge request failed, but this
+ job is not allowed to fail
+- An open merge request becomes unmergeable due to conflict, and you are either:
+ - The author
+ - Have set it to automatically merge once the pipeline succeeds
+
+To-do triggers are not affected by [GitLab Notification Email settings](profile/notifications.md).
+
+NOTE: **Note:**
+When a user no longer has access to a resource related to a To Do (like an issue, merge request, project, or group) the related To-Do items are deleted within the next hour for security reasons. The delete is delayed to prevent data loss, in case the user's access was revoked by mistake.
+
+### Directly addressing a To Do
+
+> [Introduced][ce-7926] in GitLab 9.0.
+
+If you are mentioned at the start of a line, the To Do you receive will be listed
+as 'directly addressed'. For example, in this comment:
+
+```markdown
+@alice What do you think? cc: @bob
+
+- @carol can you please have a look?
+
+>>>
+@dan what do you think?
+>>>
+
+@erin @frank thank you!
+```
+
+The people receiving directly addressed To-Do items are `@alice`, `@erin`, and
+`@frank`. Directly addressed To-Do items only differ from mentions in their type
+for filtering purposes; otherwise, they appear as normal.
+
+### Manually creating a To Do
+
+You can also add the following to your To-Do List by clicking the **Add a To Do** button on an:
+
+- Issue
+- Merge Request
+- Epic **(ULTIMATE)**
+
+![Adding a To Do from the issuable sidebar](img/todos_add_todo_sidebar.png)
+
+## Marking a To Do as done
+
+Any action to the following will mark the corresponding To Do as done:
+
+- Issue
+- Merge Request
+- Epic **(ULTIMATE)**
+
+Actions that dismiss To-Do items include:
+
+- Changing the assignee
+- Changing the milestone
+- Adding/removing a label
+- Commenting on the issue
+
+Your To-Do List is personal, and items are only marked as done if the action comes from
+you. If you close the issue or merge request, your To Do is automatically
+marked as done.
+
+To prevent other users from closing issues without you being notified, if someone else closes, merges, or takes action on the any of the following, your To Do will remain pending:
+
+- Issue
+- Merge request
+- Epic **(ULTIMATE)**
+
+There is just one To Do for each of these, so mentioning a user a hundred times in an issue will only trigger one To Do.
+
+If no action is needed, you can manually mark the To Do as done by clicking the
+corresponding **Done** button, and it will disappear from your To-Do List.
+
+![A To Do in the To-Do List](img/todos_todo_list_item.png)
+
+You can also mark a To Do as done by clicking the **Mark as done** button in the sidebar of the following:
+
+- Issue
+- Merge Request
+- Epic **(ULTIMATE)**
+
+![Mark as done from the issuable sidebar](img/todos_mark_done_sidebar.png)
+
+You can mark all your To-Do items as done at once by clicking the **Mark all as
+done** button.
+
+## Filtering your To-Do List
+
+There are four kinds of filters you can use on your To-Do List.
+
+| Filter | Description |
+| ------- | ----------- |
+| Project | Filter by project |
+| Group | Filter by group |
+| Author | Filter by the author that triggered the To Do |
+| Type | Filter by issue, merge request, or epic **(ULTIMATE)** |
+| Action | Filter by the action that triggered the To Do |
+
+You can also filter by more than one of these at the same time. The possible Actions are `Any Action`, `Assigned`, `Mentioned`, `Added`, `Pipelines`, and `Directly Addressed`, [as described above](#what-triggers-a-to-do).
+
+[ce-2817]: https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/2817
+[ce-7926]: https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/7926
diff --git a/doc/workflow/README.md b/doc/workflow/README.md
index c6396672e59..9836255932a 100644
--- a/doc/workflow/README.md
+++ b/doc/workflow/README.md
@@ -2,53 +2,10 @@
comments: false
---
-# Workflow
+# Workflow (Deprecated)
-- [Automatic issue closing](../user/project/issues/managing_issues.md#closing-issues-automatically)
-- [Change your time zone](timezone.md)
-- [Cycle Analytics](../user/project/cycle_analytics.md)
-- [Description templates](../user/project/description_templates.md)
-- [Feature branch workflow](workflow.md)
-- [GitLab Flow](gitlab_flow.md)
-- [Groups](../user/group/index.md)
-- Issues - The GitLab Issue Tracker is an advanced and complete tool for
- tracking the evolution of a new idea or the process of solving a problem.
- - [Exporting Issues](../user/project/issues/csv_export.md) **(STARTER)** Export issues as a CSV, emailed as an attachment.
- - [Confidential issues](../user/project/issues/confidential_issues.md)
- - [Due date for issues](../user/project/issues/due_dates.md)
-- [Issue Board](../user/project/issue_board.md)
-- [Keyboard shortcuts](shortcuts.md)
-- [File finder](file_finder.md)
-- [File lock](../user/project/file_lock.md) **(PREMIUM)**
-- [Labels](../user/project/labels.md)
-- [Issue weight](issue_weight.md) **(STARTER)**
-- [Notification emails](notifications.md)
-- [Projects](../user/project/index.md)
-- [Project forking workflow](forking_workflow.md)
-- [Project users](../user/project/members/index.md)
-- [Protected branches](../user/project/protected_branches.md)
-- [Protected tags](../user/project/protected_tags.md)
-- [Quick Actions](../user/project/quick_actions.md)
-- [Sharing projects with groups](../user/project/members/share_project_with_groups.md)
-- [Time tracking](time_tracking.md)
-- [Web Editor](../user/project/repository/web_editor.md)
-- [Releases](releases.md)
-- [Milestones](../user/project/milestones/index.md)
-- [Merge Requests](../user/project/merge_requests/index.md)
- - [Authorization for merge requests](../user/project/merge_requests/authorization_for_merge_requests.md)
- - [Cherry-pick changes](../user/project/merge_requests/cherry_pick_changes.md)
- - [Merge when pipeline succeeds](../user/project/merge_requests/merge_when_pipeline_succeeds.md)
- - [Resolve threads in merge requests reviews](../user/discussions/index.md)
- - [Resolve merge conflicts in the UI](../user/project/merge_requests/resolve_conflicts.md)
- - [Revert changes in the UI](../user/project/merge_requests/revert_changes.md)
- - [Merge requests versions](../user/project/merge_requests/versions.md)
- - ["Work In Progress" merge requests](../user/project/merge_requests/work_in_progress_merge_requests.md)
- - [Fast-forward merge requests](../user/project/merge_requests/fast_forward_merge.md)
- - [Merge request approvals](../user/project/merge_requests/merge_request_approvals.md) **(STARTER)**
-- [Repository mirroring](repository_mirroring.md) **(STARTER)**
-- [Service Desk](../user/project/service_desk.md) **(PREMIUM)**
-- [Manage large binaries with Git LFS](lfs/manage_large_binaries_with_git_lfs.md)
-- [Importing from SVN, GitHub, Bitbucket, etc](importing/README.md)
-- [Todos](todos.md)
-- [Snippets](../user/snippets.md)
-- [Subgroups](../user/group/subgroups/index.md)
+This page was deprecated, with all content previously stored under the `/workflow` path moved
+to other locations in the documentation site, organized by topic. You can use the search
+box to find the content you are looking for, browse the main [GitLab Documentation page](../README.md),
+or view the [issue that deprecated this page](https://gitlab.com/gitlab-org/gitlab/issues/32940)
+for more details.
diff --git a/doc/workflow/file_finder.md b/doc/workflow/file_finder.md
index 8eb705b5363..f7098c88fd1 100644
--- a/doc/workflow/file_finder.md
+++ b/doc/workflow/file_finder.md
@@ -1,41 +1,5 @@
-# File finder
+---
+redirect_to: '../user/project/repository/file_finder.md'
+---
-> [Introduced][gh-9889] in GitLab 8.4.
-
-The file finder feature allows you to quickly shortcut your way when you are
-searching for a file in a repository using the GitLab UI.
-
-You can find the **Find File** button when in the **Files** section of a
-project.
-
-![Find file button](img/file_finder_find_button.png)
-
-For those who prefer to keep their fingers on the keyboard, there is a
-[shortcut button](shortcuts.md) as well, which you can invoke from _anywhere_
-in a project.
-
-Press `t` to launch the File search function when in **Issues**,
-**Merge requests**, **Milestones**, even the project's settings.
-
-Start typing what you are searching for and watch the magic happen. With the
-up/down arrows, you go up and down the results, with `Esc` you close the search
-and go back to **Files**.
-
-## How it works
-
-The File finder feature is powered by the [Fuzzy filter](https://github.com/jeancroy/fuzz-aldrin-plus) library.
-
-It implements a fuzzy search with highlight, and tries to provide intuitive
-results by recognizing patterns that people use while searching.
-
-For example, consider the [GitLab CE repository][ce] and that we want to open
-the `app/controllers/admin/deploy_keys_controller.rb` file.
-
-Using fuzzy search, we start by typing letters that get us closer to the file.
-
-**Protip:** To narrow down your search, include `/` in your search terms.
-
-![Find file button](img/file_finder_find_file.png)
-
-[gh-9889]: https://github.com/gitlabhq/gitlabhq/pull/9889 "File finder pull request"
-[ce]: https://gitlab.com/gitlab-org/gitlab-foss/tree/master "GitLab CE repository"
+This document was moved to [another location](../user/project/repository/file_finder.md).
diff --git a/doc/workflow/forking_workflow.md b/doc/workflow/forking_workflow.md
index 48be38b2eca..fa617d859a5 100644
--- a/doc/workflow/forking_workflow.md
+++ b/doc/workflow/forking_workflow.md
@@ -1,51 +1,5 @@
-# Project forking workflow
+---
+redirect_to: '../user/project/repository/forking_workflow.md'
+---
-Forking a project to your own namespace is useful if you have no write
-access to the project you want to contribute to. If you do have write
-access or can request it, we recommend working together in the same
-repository since it is simpler. See our [GitLab Flow](gitlab_flow.md)
-document more information about using branches to work together.
-
-## Creating a fork
-
-Forking a project is in most cases a two-step process.
-
-1. Click on the fork button located located in between the star and clone buttons on the project's home page.
-
- ![Fork button](img/forking_workflow_fork_button.png)
-
-1. Once you do that, you'll be presented with a screen where you can choose
- the namespace to fork to. Only namespaces (groups and your own
- namespace) where you have write access to, will be shown. Click on the
- namespace to create your fork there.
-
- ![Choose namespace](img/forking_workflow_choose_namespace.png)
-
- **Note:**
- If the namespace you chose to fork the project to has another project with
- the same path name, you will be presented with a warning that the forking
- could not be completed. Try to resolve the error before repeating the forking
- process.
-
- ![Path taken error](img/forking_workflow_path_taken_error.png)
-
-After the forking is done, you can start working on the newly created
-repository. There, you will have full [Owner](../user/permissions.md)
-access, so you can set it up as you please.
-
-## Merging upstream
-
-Once you are ready to send your code back to the main project, you need
-to create a merge request. Choose your forked project's main branch as
-the source and the original project's main branch as the destination and
-create the [merge request](merge_requests.md).
-
-![Selecting branches](forking/branch_select.png)
-
-You can then assign the merge request to someone to have them review
-your changes. Upon pressing the 'Submit Merge Request' button, your
-changes will be added to the repository and branch you're merging into.
-
-![New merge request](forking/merge_request.png)
-
-[gitlab flow]: https://about.gitlab.com/blog/2014/09/29/gitlab-flow/ "GitLab Flow blog post"
+This document was moved to [another location](../user/project/repository/forking_workflow.md).
diff --git a/doc/workflow/git_annex.md b/doc/workflow/git_annex.md
index 84d49569a95..e54d52ea70d 100644
--- a/doc/workflow/git_annex.md
+++ b/doc/workflow/git_annex.md
@@ -1,238 +1,5 @@
-# Git annex
-
-> **Warning:** GitLab has [completely
-removed][deprecate-annex-issue] in GitLab 9.0 (2017/03/22).
-Read through the [migration guide from git-annex to Git LFS][guide].
-
-The biggest limitation of Git, compared to some older centralized version
-control systems, has been the maximum size of the repositories.
-
-The general recommendation is to not have Git repositories larger than 1GB to
-preserve performance. Although GitLab has no limit (some repositories in GitLab
-are over 50GB!), we subscribe to the advice to keep repositories as small as
-you can.
-
-Not being able to version control large binaries is a big problem for many
-larger organizations.
-Videos, photos, audio, compiled binaries and many other types of files are too
-large. As a workaround, people keep artwork-in-progress in a Dropbox folder and
-only check in the final result. This results in using outdated files, not
-having a complete history and increases the risk of losing work.
-
-This problem is solved in GitLab Enterprise Edition by integrating the
-[git-annex] application.
-
-`git-annex` allows managing large binaries with Git without checking the
-contents into Git.
-You check-in only a symlink that contains the SHA-1 of the large binary. If you
-need the large binary, you can sync it from the GitLab server over `rsync`, a
-very fast file copying tool.
-
-## GitLab git-annex Configuration
-
-`git-annex` is disabled by default in GitLab. Below you will find the
-configuration options required to enable it.
-
-### Requirements
-
-`git-annex` needs to be installed both on the server and the client side.
-
-For Debian-like systems (e.g., Debian, Ubuntu) this can be achieved by running:
-
-```
-sudo apt-get update && sudo apt-get install git-annex
-```
-
-For RedHat-like systems (e.g., CentOS, RHEL) this can be achieved by running:
-
-```
-sudo yum install epel-release && sudo yum install git-annex
-```
-
-### Configuration for Omnibus packages
-
-For Omnibus GitLab packages, only one configuration setting is needed.
-The Omnibus package will internally set the correct options in all locations.
-
-1. In `/etc/gitlab/gitlab.rb` add the following line:
-
- ```ruby
- gitlab_shell['git_annex_enabled'] = true
- ```
-
-1. Save the file and [reconfigure GitLab][] for the changes to take effect.
-
-### Configuration for installations from source
-
-There are 2 settings to enable git-annex on your GitLab server.
-
-One is located in `config/gitlab.yml` of the GitLab repository and the other
-one is located in `config.yml` of GitLab Shell.
-
-1. In `config/gitlab.yml` add or edit the following lines:
-
- ```yaml
- gitlab_shell:
- git_annex_enabled: true
- ```
-
-1. In `config.yml` of GitLab Shell add or edit the following lines:
-
- ```yaml
- git_annex_enabled: true
- ```
-
-1. Save the files and [restart GitLab][] for the changes to take effect.
-
-## Using GitLab git-annex
-
-> **Note:**
-> Your Git remotes must be using the SSH protocol, not HTTP(S).
-
-Here is an example workflow of uploading a very large file and then checking it
-into your Git repository:
-
-```bash
-git clone git@example.com:group/project.git
-
-git annex init 'My Laptop' # initialize the annex project and give an optional description
-cp ~/tmp/debian.iso ./ # copy a large file into the current directory
-git annex add debian.iso # add the large file to git annex
-git commit -am "Add Debian iso" # commit the file metadata
-git annex sync --content # sync the Git repo and large file to the GitLab server
-```
-
-The output should look like this:
-
-```
-commit
-On branch master
-Your branch is ahead of 'origin/master' by 1 commit.
- (use "git push" to publish your local commits)
-nothing to commit, working tree clean
-ok
-pull origin
-remote: Counting objects: 5, done.
-remote: Compressing objects: 100% (4/4), done.
-remote: Total 5 (delta 2), reused 0 (delta 0)
-Unpacking objects: 100% (5/5), done.
-From example.com:group/project
- 497842b..5162f80 git-annex -> origin/git-annex
-ok
-(merging origin/git-annex into git-annex...)
-(recording state in git...)
-copy debian.iso (checking origin...) (to origin...)
-SHA256E-s26214400--8092b3d482fb1b7a5cf28c43bc1425c8f2d380e86869c0686c49aa7b0f086ab2.iso
- 26,214,400 100% 638.88kB/s 0:00:40 (xfr#1, to-chk=0/1)
-ok
-pull origin
-ok
-(recording state in git...)
-push origin
-Counting objects: 15, done.
-Delta compression using up to 4 threads.
-Compressing objects: 100% (13/13), done.
-Writing objects: 100% (15/15), 1.64 KiB | 0 bytes/s, done.
-Total 15 (delta 1), reused 0 (delta 0)
-To example.com:group/project.git
- * [new branch] git-annex -> synced/git-annex
- * [new branch] master -> synced/master
-ok
-```
-
-Your files can be found in the `master` branch, but you'll notice that there
-are more branches created by the `annex sync` command.
-
-Git Annex will also create a new directory at `.git/annex/` and will record the
-tracked files in the `.git/config` file. The files you assign to be tracked
-with `git-annex` will not affect the existing `.git/config` records. The files
-are turned into symbolic links that point to data in `.git/annex/objects/`.
-
-The `debian.iso` file in the example will contain the symbolic link:
-
-```
-.git/annex/objects/ZW/1k/SHA256E-s82701--6384039733b5035b559efd5a2e25a493ab6e09aabfd5162cc03f6f0ec238429d.png/SHA256E-s82701--6384039733b5035b559efd5a2e25a493ab6e09aabfd5162cc03f6f0ec238429d.iso
-```
-
-Use `git annex info` to retrieve the information about the local copy of your
-repository.
-
+---
+redirect_to: '../administration/git_annex.md'
---
-Downloading a single large file is also very simple:
-
-```bash
-git clone git@gitlab.example.com:group/project.git
-
-git annex sync # sync Git branches but not the large file
-git annex get debian.iso # download the large file
-```
-
-To download all files:
-
-```bash
-git clone git@gitlab.example.com:group/project.git
-
-git annex sync --content # sync Git branches and download all the large files
-```
-
-By using `git-annex` without GitLab, anyone that can access the server can also
-access the files of all projects, but GitLab Annex ensures that you can only
-access files of projects you have access to (developer, maintainer, or owner role).
-
-## How it works
-
-Internally GitLab uses [GitLab Shell] to handle SSH access and this was a great
-integration point for `git-annex`.
-There is a setting in GitLab Shell so you can disable GitLab Annex support
-if you want to.
-
-## Troubleshooting tips
-
-Differences in version of `git-annex` on the GitLab server and on local machines
-can cause `git-annex` to raise unpredicted warnings and errors.
-
-Consult the [Annex upgrade page][annex-upgrade] for more information about
-the differences between versions. You can find out which version is installed
-on your server by navigating to <https://pkgs.org/download/git-annex> and
-searching for your distribution.
-
-Although there is no general guide for `git-annex` errors, there are a few tips
-on how to go around the warnings.
-
-### `git-annex-shell: Not a git-annex or gcrypt repository`
-
-This warning can appear on the initial `git annex sync --content` and is caused
-by differences in `git-annex-shell`. You can read more about it
-[in this git-annex issue][issue].
-
-One important thing to note is that despite the warning, the `sync` succeeds
-and the files are pushed to the GitLab repository.
-
-If you get hit by this, you can run the following command inside the repository
-that the warning was raised:
-
-```
-git config remote.origin.annex-ignore false
-```
-
-Consecutive runs of `git annex sync --content` **should not** produce this
-warning and the output should look like this:
-
-```
-commit ok
-pull origin
-ok
-pull origin
-ok
-push origin
-```
-
-[annex-upgrade]: https://git-annex.branchable.com/upgrades/
-[deprecate-annex-issue]: https://gitlab.com/gitlab-org/gitlab/issues/1648
-[git-annex]: https://git-annex.branchable.com/ "git-annex website"
-[gitlab shell]: https://gitlab.com/gitlab-org/gitlab-shell "GitLab Shell repository"
-[guide]: lfs/migrate_from_git_annex_to_git_lfs.html
-[issue]: https://git-annex.branchable.com/forum/Error_from_git-annex-shell_on_creation_of_gcrypt_special_remote/ "git-annex issue"
-[reconfigure GitLab]: ../administration/restart_gitlab.md#omnibus-gitlab-reconfigure
-[restart GitLab]: ../administration/restart_gitlab.md#installations-from-source
+This document was moved to [another location](../administration/git_annex.md).
diff --git a/doc/workflow/git_lfs.md b/doc/workflow/git_lfs.md
index da217b0a5da..0a8c33c264c 100644
--- a/doc/workflow/git_lfs.md
+++ b/doc/workflow/git_lfs.md
@@ -1,5 +1,5 @@
---
-redirect_to: 'lfs/manage_large_binaries_with_git_lfs.md'
+redirect_to: '../administration/lfs/manage_large_binaries_with_git_lfs.md'
---
-This document was moved to [another location](lfs/manage_large_binaries_with_git_lfs.md).
+This document was moved to [another location](../administration/lfs/manage_large_binaries_with_git_lfs.md).
diff --git a/doc/workflow/gitlab_flow.md b/doc/workflow/gitlab_flow.md
index e3568d6489d..e03281c0ffc 100644
--- a/doc/workflow/gitlab_flow.md
+++ b/doc/workflow/gitlab_flow.md
@@ -1,326 +1,5 @@
-# Introduction to GitLab Flow
+---
+redirect_to: '../topics/gitlab_flow.md'
+---
-![GitLab Flow](img/gitlab_flow.png)
-
-Git allows a wide variety of branching strategies and workflows.
-Because of this, many organizations end up with workflows that are too complicated, not clearly defined, or not integrated with issue tracking systems.
-Therefore, we propose GitLab flow as a clearly defined set of best practices.
-It combines [feature-driven development](https://en.wikipedia.org/wiki/Feature-driven_development) and [feature branches](https://martinfowler.com/bliki/FeatureBranch.html) with issue tracking.
-
-Organizations coming to Git from other version control systems frequently find it hard to develop a productive workflow.
-This article describes GitLab flow, which integrates the Git workflow with an issue tracking system.
-It offers a simple, transparent, and effective way to work with Git.
-
-![Four stages (working copy, index, local repo, remote repo) and three steps between them](img/four_stages.png)
-
-When converting to Git, you have to get used to the fact that it takes three steps to share a commit with colleagues.
-Most version control systems have only one step: committing from the working copy to a shared server.
-In Git, you add files from the working copy to the staging area. After that, you commit them to your local repo.
-The third step is pushing to a shared remote repository.
-After getting used to these three steps, the next challenge is the branching model.
-
-![Multiple long-running branches and merging in all directions](img/messy_flow.png)
-
-Since many organizations new to Git have no conventions for how to work with it, their repositories can quickly become messy.
-The biggest problem is that many long-running branches emerge that all contain part of the changes.
-People have a hard time figuring out which branch has the latest code, or which branch to deploy to production.
-Frequently, the reaction to this problem is to adopt a standardized pattern such as [Git flow](https://nvie.com/posts/a-successful-git-branching-model/) and [GitHub flow](http://scottchacon.com/2011/08/31/github-flow.html).
-We think there is still room for improvement. In this document, we describe a set of practices we call GitLab flow.
-
-For a video introduction of how this works in GitLab, see [GitLab Flow](https://youtu.be/InKNIvky2KE).
-
-## Git flow and its problems
-
-![Git Flow timeline by Vincent Driessen, used with permission](img/gitdashflow.png)
-
-Git flow was one of the first proposals to use Git branches, and it has received a lot of attention.
-It suggests a `master` branch and a separate `develop` branch, as well as supporting branches for features, releases, and hotfixes.
-The development happens on the `develop` branch, moves to a release branch, and is finally merged into the `master` branch.
-
-Git flow is a well-defined standard, but its complexity introduces two problems.
-The first problem is that developers must use the `develop` branch and not `master`. `master` is reserved for code that is released to production.
-It is a convention to call your default branch `master` and to mostly branch from and merge to this.
-Since most tools automatically use the `master` branch as the default, it is annoying to have to switch to another branch.
-
-The second problem of Git flow is the complexity introduced by the hotfix and release branches.
-These branches can be a good idea for some organizations but are overkill for the vast majority of them.
-Nowadays, most organizations practice continuous delivery, which means that your default branch can be deployed.
-Continuous delivery removes the need for hotfix and release branches, including all the ceremony they introduce.
-An example of this ceremony is the merging back of release branches.
-Though specialized tools do exist to solve this, they require documentation and add complexity.
-Frequently, developers make mistakes such as merging changes only into `master` and not into the `develop` branch.
-The reason for these errors is that Git flow is too complicated for most use cases.
-For example, many projects do releases but don't need to do hotfixes.
-
-## GitHub flow as a simpler alternative
-
-![Master branch with feature branches merged in](img/github_flow.png)
-
-In reaction to Git flow, GitHub created a simpler alternative.
-[GitHub flow](https://guides.github.com/introduction/flow/index.html) has only feature branches and a `master` branch.
-This flow is clean and straightforward, and many organizations have adopted it with great success.
-Atlassian recommends [a similar strategy](https://www.atlassian.com/blog/git/simple-git-workflow-is-simple), although they rebase feature branches.
-Merging everything into the `master` branch and frequently deploying means you minimize the amount of unreleased code, which is in line with lean and continuous delivery best practices.
-However, this flow still leaves a lot of questions unanswered regarding deployments, environments, releases, and integrations with issues.
-With GitLab flow, we offer additional guidance for these questions.
-
-## Production branch with GitLab flow
-
-![Master branch and production branch with an arrow that indicates a deployment](img/production_branch.png)
-
-GitHub flow assumes you can deploy to production every time you merge a feature branch.
-While this is possible in some cases, such as SaaS applications, there are many cases where this is not possible.
-One case is where you don't control the timing of a release, for example, an iOS application that is released when it passes App Store validation.
-Another case is when you have deployment windows &mdash; for example, workdays from 10&nbsp;AM to 4&nbsp;PM when the operations team is at full capacity &mdash; but you also merge code at other times.
-In these cases, you can make a production branch that reflects the deployed code.
-You can deploy a new version by merging `master` into the production branch.
-If you need to know what code is in production, you can just checkout the production branch to see.
-The approximate time of deployment is easily visible as the merge commit in the version control system.
-This time is pretty accurate if you automatically deploy your production branch.
-If you need a more exact time, you can have your deployment script create a tag on each deployment.
-This flow prevents the overhead of releasing, tagging, and merging that happens with Git flow.
-
-## Environment branches with GitLab flow
-
-![Multiple branches with the code cascading from one to another](img/environment_branches.png)
-
-It might be a good idea to have an environment that is automatically updated to the `master` branch.
-Only, in this case, the name of this environment might differ from the branch name.
-Suppose you have a staging environment, a pre-production environment, and a production environment.
-In this case, deploy the `master` branch to staging.
-To deploy to pre-production, create a merge request from the `master` branch to the pre-production branch.
-Go live by merging the pre-production branch into the production branch.
-This workflow, where commits only flow downstream, ensures that everything is tested in all environments.
-If you need to cherry-pick a commit with a hotfix, it is common to develop it on a feature branch and merge it into `master` with a merge request.
-In this case, do not delete the feature branch yet.
-If `master` passes automatic testing, you then merge the feature branch into the other branches.
-If this is not possible because more manual testing is required, you can send merge requests from the feature branch to the downstream branches.
-
-## Release branches with GitLab flow
-
-![Master and multiple release branches that vary in length with cherry-picks from master](img/release_branches.png)
-
-You only need to work with release branches if you need to release software to the outside world.
-In this case, each branch contains a minor version, for example, 2-3-stable, 2-4-stable, etc.
-Create stable branches using `master` as a starting point, and branch as late as possible.
-By doing this, you minimize the length of time during which you have to apply bug fixes to multiple branches.
-After announcing a release branch, only add serious bug fixes to the branch.
-If possible, first merge these bug fixes into `master`, and then cherry-pick them into the release branch.
-If you start by merging into the release branch, you might forget to cherry-pick them into `master`, and then you'd encounter the same bug in subsequent releases.
-Merging into `master` and then cherry-picking into release is called an "upstream first" policy, which is also practiced by [Google](https://www.chromium.org/chromium-os/chromiumos-design-docs/upstream-first) and [Red Hat](https://www.redhat.com/en/blog/a-community-for-using-openstack-with-red-hat-rdo).
-Every time you include a bug fix in a release branch, increase the patch version (to comply with [Semantic Versioning](https://semver.org/)) by setting a new tag.
-Some projects also have a stable branch that points to the same commit as the latest released branch.
-In this flow, it is not common to have a production branch (or Git flow `master` branch).
-
-## Merge/pull requests with GitLab flow
-
-![Merge request with inline comments](img/mr_inline_comments.png)
-
-Merge or pull requests are created in a Git management application. They ask an assigned person to merge two branches.
-Tools such as GitHub and Bitbucket choose the name "pull request" since the first manual action is to pull the feature branch.
-Tools such as GitLab and others choose the name "merge request" since the final action is to merge the feature branch.
-In this article, we'll refer to them as merge requests.
-
-If you work on a feature branch for more than a few hours, it is good to share the intermediate result with the rest of the team.
-To do this, create a merge request without assigning it to anyone.
-Instead, mention people in the description or a comment, for example, "/cc @mark @susan."
-This indicates that the merge request is not ready to be merged yet, but feedback is welcome.
-Your team members can comment on the merge request in general or on specific lines with line comments.
-The merge request serves as a code review tool, and no separate code review tools should be needed.
-If the review reveals shortcomings, anyone can commit and push a fix.
-Usually, the person to do this is the creator of the merge request.
-The diff in the merge request automatically updates when new commits are pushed to the branch.
-
-When you are ready for your feature branch to be merged, assign the merge request to the person who knows most about the codebase you are changing.
-Also, mention any other people from whom you would like feedback.
-After the assigned person feels comfortable with the result, they can merge the branch.
-If the assigned person does not feel comfortable, they can request more changes or close the merge request without merging.
-
-In GitLab, it is common to protect the long-lived branches, e.g., the `master` branch, so that [most developers can't modify them](../permissions/permissions.md).
-So, if you want to merge into a protected branch, assign your merge request to someone with maintainer permissions.
-
-After you merge a feature branch, you should remove it from the source control software.
-In GitLab, you can do this when merging.
-Removing finished branches ensures that the list of branches shows only work in progress.
-It also ensures that if someone reopens the issue, they can use the same branch name without causing problems.
-
-NOTE: **Note:**
-When you reopen an issue you need to create a new merge request.
-
-![Remove checkbox for branch in merge requests](img/remove_checkbox.png)
-
-## Issue tracking with GitLab flow
-
-![Merge request with the branch name "15-require-a-password-to-change-it" and assignee field shown](img/merge_request.png)
-
-GitLab flow is a way to make the relation between the code and the issue tracker more transparent.
-
-Any significant change to the code should start with an issue that describes the goal.
-Having a reason for every code change helps to inform the rest of the team and to keep the scope of a feature branch small.
-In GitLab, each change to the codebase starts with an issue in the issue tracking system.
-If there is no issue yet, create the issue, as long as the change will take a significant amount of work, i.e., more than 1 hour.
-In many organizations, raising an issue is part of the development process because they are used in sprint planning.
-The issue title should describe the desired state of the system.
-For example, the issue title "As an administrator, I want to remove users without receiving an error" is better than "Admin can't remove users."
-
-When you are ready to code, create a branch for the issue from the `master` branch.
-This branch is the place for any work related to this change.
-
-NOTE: **Note:**
-The name of a branch might be dictated by organizational standards.
-
-When you are done or want to discuss the code, open a merge request.
-A merge request is an online place to discuss the change and review the code.
-
-If you open the merge request but do not assign it to anyone, it is a "Work In Progress" merge request.
-These are used to discuss the proposed implementation but are not ready for inclusion in the `master` branch yet.
-Start the title of the merge request with `[WIP]` or `WIP:` to prevent it from being merged before it's ready.
-
-When you think the code is ready, assign the merge request to a reviewer.
-The reviewer can merge the changes when they think the code is ready for inclusion in the `master` branch.
-When they press the merge button, GitLab merges the code and creates a merge commit that makes this event easily visible later on.
-Merge requests always create a merge commit, even when the branch could be merged without one.
-This merge strategy is called "no fast-forward" in Git.
-After the merge, delete the feature branch since it is no longer needed.
-In GitLab, this deletion is an option when merging.
-
-Suppose that a branch is merged but a problem occurs and the issue is reopened.
-In this case, it is no problem to reuse the same branch name since the first branch was deleted when it was merged.
-At any time, there is at most one branch for every issue.
-It is possible that one feature branch solves more than one issue.
-
-## Linking and closing issues from merge requests
-
-![Merge request showing the linked issues that will be closed](img/close_issue_mr.png)
-
-Link to issues by mentioning them in commit messages or the description of a merge request, for example, "Fixes #16" or "Duck typing is preferred. See #12."
-GitLab then creates links to the mentioned issues and creates comments in the issues linking back to the merge request.
-
-To automatically close linked issues, mention them with the words "fixes" or "closes," for example, "fixes #14" or "closes #67." GitLab closes these issues when the code is merged into the default branch.
-
-If you have an issue that spans across multiple repositories, create an issue for each repository and link all issues to a parent issue.
-
-## Squashing commits with rebase
-
-![Vim screen showing the rebase view](img/rebase.png)
-
-With Git, you can use an interactive rebase (`rebase -i`) to squash multiple commits into one or reorder them.
-This functionality is useful if you want to replace a couple of small commits with a single commit, or if you want to make the order more logical.
-
-However, you should never rebase commits you have pushed to a remote server.
-Rebasing creates new commits for all your changes, which can cause confusion because the same change would have multiple identifiers.
-It also causes merge errors for anyone working on the same branch because their history would not match with yours.
-Also, if someone has already reviewed your code, rebasing makes it hard to tell what changed since the last review.
-
-You should also never rebase commits authored by other people.
-Not only does this rewrite history, but it also loses authorship information.
-Rebasing prevents the other authors from being attributed and sharing part of the [`git blame`](https://git-scm.com/docs/git-blame).
-
-If a merge involves many commits, it may seem more difficult to undo.
-You might think to solve this by squashing all the changes into one commit before merging, but as discussed earlier, it is a bad idea to rebase commits that you have already pushed.
-Fortunately, there is an easy way to undo a merge with all its commits.
-The way to do this is by reverting the merge commit.
-Preserving this ability to revert a merge is a good reason to always use the "no fast-forward" (`--no-ff`) strategy when you merge manually.
-
-NOTE: **Note:**
-If you revert a merge commit and then change your mind, revert the revert commit to redo the merge.
-Git does not allow you to merge the code again otherwise.
-
-## Reducing merge commits in feature branches
-
-![List of sequential merge commits](img/merge_commits.png)
-
-Having lots of merge commits can make your repository history messy.
-Therefore, you should try to avoid merge commits in feature branches.
-Often, people avoid merge commits by just using rebase to reorder their commits after the commits on the `master` branch.
-Using rebase prevents a merge commit when merging `master` into your feature branch, and it creates a neat linear history.
-However, as discussed in [the section about rebasing](#squashing-commits-with-rebase), you should never rebase commits you have pushed to a remote server.
-This restriction makes it impossible to rebase work in progress that you already shared with your team, which is something we recommend.
-
-Rebasing also creates more work, since every time you rebase, you have to resolve similar conflicts.
-Sometimes you can reuse recorded resolutions (`rerere`), but merging is better since you only have to resolve conflicts once.
-Atlassian has a more thorough explanation of the tradeoffs between merging and rebasing [on their blog](https://www.atlassian.com/blog/git/git-team-workflows-merge-or-rebase).
-
-A good way to prevent creating many merge commits is to not frequently merge `master` into the feature branch.
-There are three reasons to merge in `master`: utilizing new code, resolving merge conflicts, and updating long-running branches.
-
-If you need to utilize some code that was introduced in `master` after you created the feature branch, you can often solve this by just cherry-picking a commit.
-
-If your feature branch has a merge conflict, creating a merge commit is a standard way of solving this.
-
-NOTE: **Note:**
-Sometimes you can use .gitattributes to reduce merge conflicts.
-For example, you can set your changelog file to use the [union merge driver](https://git-scm.com/docs/gitattributes#gitattributes-union) so that multiple new entries don't conflict with each other.
-
-The last reason for creating merge commits is to keep long-running feature branches up-to-date with the latest state of the project.
-The solution here is to keep your feature branches short-lived.
-Most feature branches should take less than one day of work.
-If your feature branches often take more than a day of work, try to split your features into smaller units of work.
-
-If you need to keep a feature branch open for more than a day, there are a few strategies to keep it up-to-date.
-One option is to use continuous integration (CI) to merge in `master` at the start of the day.
-Another option is to only merge in from well-defined points in time, for example, a tagged release.
-You could also use [feature toggles](https://martinfowler.com/bliki/FeatureToggle.html) to hide incomplete features so you can still merge back into `master` every day.
-
-> **Note:** Don't confuse automatic branch testing with continuous integration.
-> Martin Fowler makes this distinction in [his article about feature branches](https://martinfowler.com/bliki/FeatureBranch.html):
->
-> "I've heard people say they are doing CI because they are running builds, perhaps using a CI server, on every branch with every commit.
-> That's continuous building, and a Good Thing, but there's no *integration*, so it's not CI."
-
-In conclusion, you should try to prevent merge commits, but not eliminate them.
-Your codebase should be clean, but your history should represent what actually happened.
-Developing software happens in small, messy steps, and it is OK to have your history reflect this.
-You can use tools to view the network graphs of commits and understand the messy history that created your code.
-If you rebase code, the history is incorrect, and there is no way for tools to remedy this because they can't deal with changing commit identifiers.
-
-## Commit often and push frequently
-
-Another way to make your development work easier is to commit often.
-Every time you have a working set of tests and code, you should make a commit.
-Splitting up work into individual commits provides context for developers looking at your code later.
-Smaller commits make it clear how a feature was developed, and they make it easy to roll back to a specific good point in time or to revert one code change without reverting several unrelated changes.
-
-Committing often also makes it easy to share your work, which is important so that everyone is aware of what you are working on.
-You should push your feature branch frequently, even when it is not yet ready for review.
-By sharing your work in a feature branch or [a merge request](#mergepull-requests-with-gitlab-flow), you prevent your team members from duplicating work.
-Sharing your work before it's complete also allows for discussion and feedback about the changes, which can help improve the code before it gets to review.
-
-## How to write a good commit message
-
-![Good and bad commit message](img/good_commit.png)
-
-A commit message should reflect your intention, not just the contents of the commit.
-It is easy to see the changes in a commit, so the commit message should explain why you made those changes.
-An example of a good commit message is: "Combine templates to reduce duplicate code in the user views."
-The words "change," "improve," "fix," and "refactor" don't add much information to a commit message.
-For example, "Improve XML generation" could be better written as "Properly escape special characters in XML generation."
-For more information about formatting commit messages, please see this excellent [blog post by Tim Pope](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
-
-## Testing before merging
-
-![Merge requests showing the test states: red, yellow, and green](img/ci_mr.png)
-
-In old workflows, the continuous integration (CI) server commonly ran tests on the `master` branch only.
-Developers had to ensure their code did not break the `master` branch.
-When using GitLab flow, developers create their branches from this `master` branch, so it is essential that it never breaks.
-Therefore, each merge request must be tested before it is accepted.
-CI software like Travis CI and GitLab CI show the build results right in the merge request itself to make this easy.
-
-There is one drawback to testing merge requests: the CI server only tests the feature branch itself, not the merged result.
-Ideally, the server could also test the `master` branch after each change.
-However, retesting on every commit to `master` is computationally expensive and means you are more frequently waiting for test results.
-Since feature branches should be short-lived, testing just the branch is an acceptable risk.
-If new commits in `master` cause merge conflicts with the feature branch, merge `master` back into the branch to make the CI server re-run the tests.
-As said before, if you often have feature branches that last for more than a few days, you should make your issues smaller.
-
-## Working with feature branches
-
-![Shell output showing git pull output](img/git_pull.png)
-
-When creating a feature branch, always branch from an up-to-date `master`.
-If you know before you start that your work depends on another branch, you can also branch from there.
-If you need to merge in another branch after starting, explain the reason in the merge commit.
-If you have not pushed your commits to a shared location yet, you can also incorporate changes by rebasing on `master` or another feature branch.
-Do not merge from upstream again if your code can work and merge cleanly without doing so.
-Merging only when needed prevents creating merge commits in your feature branch that later end up littering the `master` history.
+This document was moved to [another location](../topics/gitlab_flow.md).
diff --git a/doc/workflow/issue_weight.md b/doc/workflow/issue_weight.md
index 79b8e5f5164..94eb38356e8 100644
--- a/doc/workflow/issue_weight.md
+++ b/doc/workflow/issue_weight.md
@@ -1,21 +1,5 @@
-# Issue weight **(STARTER)**
+---
+redirect_to: '../user/project/issues/issue_weight.md'
+---
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/76) in [GitLab Starter](https://about.gitlab.com/pricing/) 8.3.
-
-When you have a lot of issues, it can be hard to get an overview.
-By adding a weight to each issue, you can get a better idea of how much time,
-value or complexity a given issue has or will cost.
-
-You can set the weight of an issue during its creation, by simply changing the
-value in the dropdown menu. You can set it to a non-negative integer
-value from 0, 1, 2, and so on. (The database stores a 4-byte value, so the
-upper bound is essentially limitless).
-You can remove weight from an issue
-as well.
-
-This value will appear on the right sidebar of an individual issue, as well as
-in the issues page next to a distinctive balance scale icon.
-
-As an added bonus, you can see the total sum of all issues on the milestone page.
-
-![issue page](issue_weight/issue.png)
+This document was moved to [another location](../user/project/issues/issue_weight.md).
diff --git a/doc/workflow/lfs/lfs_administration.md b/doc/workflow/lfs/lfs_administration.md
index 7ad87982501..58c48b4f6e6 100644
--- a/doc/workflow/lfs/lfs_administration.md
+++ b/doc/workflow/lfs/lfs_administration.md
@@ -1,269 +1,5 @@
-# GitLab Git LFS Administration
+---
+redirect_to: '../../administration/lfs/lfs_administration.md'
+---
-Documentation on how to use Git LFS are under [Managing large binary files with Git LFS doc](manage_large_binaries_with_git_lfs.md).
-
-## Requirements
-
-- Git LFS is supported in GitLab starting with version 8.2.
-- Support for object storage, such as AWS S3, was introduced in 10.0.
-- Users need to install [Git LFS client](https://git-lfs.github.com) version 1.0.1 and up.
-
-## Configuration
-
-Git LFS objects can be large in size. By default, they are stored on the server
-GitLab is installed on.
-
-There are various configuration options to help GitLab server administrators:
-
-- Enabling/disabling Git LFS support
-- Changing the location of LFS object storage
-- Setting up object storage supported by [Fog](http://fog.io/about/provider_documentation.html)
-
-### Configuration for Omnibus installations
-
-In `/etc/gitlab/gitlab.rb`:
-
-```ruby
-# Change to true to enable lfs - enabled by default if not defined
-gitlab_rails['lfs_enabled'] = false
-
-# Optionally, change the storage path location. Defaults to
-# `#{gitlab_rails['shared_path']}/lfs-objects`. Which evaluates to
-# `/var/opt/gitlab/gitlab-rails/shared/lfs-objects` by default.
-gitlab_rails['lfs_storage_path'] = "/mnt/storage/lfs-objects"
-```
-
-### Configuration for installations from source
-
-In `config/gitlab.yml`:
-
-```yaml
-# Change to true to enable lfs
- lfs:
- enabled: false
- storage_path: /mnt/storage/lfs-objects
-```
-
-## Storing LFS objects in remote object storage
-
-> [Introduced][ee-2760] in [GitLab Premium][eep] 10.0. Brought to GitLab Core in 10.7.
-
-It is possible to store LFS objects in remote object storage which allows you
-to offload local hard disk R/W operations, and free up disk space significantly.
-GitLab is tightly integrated with `Fog`, so you can refer to its [documentation](http://fog.io/about/provider_documentation.html)
-to check which storage services can be integrated with GitLab.
-You can also use external object storage in a private local network. For example,
-[MinIO](https://min.io/) is a standalone object storage service, is easy to set up, and works well with GitLab instances.
-
-GitLab provides two different options for the uploading mechanism: "Direct upload" and "Background upload".
-
-**Option 1. Direct upload**
-
-1. User pushes an lfs file to the GitLab instance
-1. GitLab-workhorse uploads the file directly to the external object storage
-1. GitLab-workhorse notifies GitLab-rails that the upload process is complete
-
-**Option 2. Background upload**
-
-1. User pushes an lfs file to the GitLab instance
-1. GitLab-rails stores the file in the local file storage
-1. GitLab-rails then uploads the file to the external object storage asynchronously
-
-The following general settings are supported.
-
-| Setting | Description | Default |
-|---------|-------------|---------|
-| `enabled` | Enable/disable object storage | `false` |
-| `remote_directory` | The bucket name where LFS objects will be stored| |
-| `direct_upload` | Set to true to enable direct upload of LFS without the need of local shared storage. Option may be removed once we decide to support only single storage for all files. | `false` |
-| `background_upload` | Set to false to disable automatic upload. Option may be removed once upload is direct to S3 | `true` |
-| `proxy_download` | Set to true to enable proxying all files served. Option allows to reduce egress traffic as this allows clients to download directly from remote storage instead of proxying all data | `false` |
-| `connection` | Various connection options described below | |
-
-The `connection` settings match those provided by [Fog](https://github.com/fog).
-
-Here is a configuration example with S3.
-
-| Setting | Description | example |
-|---------|-------------|---------|
-| `provider` | The provider name | AWS |
-| `aws_access_key_id` | AWS credentials, or compatible | `ABC123DEF456` |
-| `aws_secret_access_key` | AWS credentials, or compatible | `ABC123DEF456ABC123DEF456ABC123DEF456` |
-| `aws_signature_version` | AWS signature version to use. 2 or 4 are valid options. Digital Ocean Spaces and other providers may need 2. | 4 |
-| `enable_signature_v4_streaming` | Set to true to enable HTTP chunked transfers with [AWS v4 signatures](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-streaming.html). Oracle Cloud S3 needs this to be false | true |
-| `region` | AWS region | us-east-1 |
-| `host` | S3 compatible host for when not using AWS, e.g. `localhost` or `storage.example.com` | s3.amazonaws.com |
-| `endpoint` | Can be used when configuring an S3 compatible service such as [MinIO](https://min.io), by entering a URL such as `http://127.0.0.1:9000` | (optional) |
-| `path_style` | Set to true to use `host/bucket_name/object` style paths instead of `bucket_name.host/object`. Leave as false for AWS S3 | false |
-| `use_iam_profile` | Set to true to use IAM profile instead of access keys | false
-
-Here is a configuration example with GCS.
-
-| Setting | Description | example |
-|---------|-------------|---------|
-| `provider` | The provider name | `Google` |
-| `google_project` | GCP project name | `gcp-project-12345` |
-| `google_client_email` | The email address of the service account | `foo@gcp-project-12345.iam.gserviceaccount.com` |
-| `google_json_key_location` | The json key path | `/path/to/gcp-project-12345-abcde.json` |
-
-NOTE: **Note:**
-The service account must have permission to access the bucket.
-[See more](https://cloud.google.com/storage/docs/authentication)
-
-Here is a configuration example with Rackspace Cloud Files.
-
-| Setting | Description | example |
-|---------|-------------|---------|
-| `provider` | The provider name | `Rackspace` |
-| `rackspace_username` | The username of the Rackspace account with access to the container | `joe.smith` |
-| `rackspace_api_key` | The API key of the Rackspace account with access to the container | `ABC123DEF456ABC123DEF456ABC123DE` |
-| `rackspace_region` | The Rackspace storage region to use, a three letter code from the [list of service access endpoints](https://developer.rackspace.com/docs/cloud-files/v1/general-api-info/service-access/) | `iad` |
-| `rackspace_temp_url_key` | The private key you have set in the Rackspace API for temporary URLs. Read more [here](https://developer.rackspace.com/docs/cloud-files/v1/use-cases/public-access-to-your-cloud-files-account/#tempurl) | `ABC123DEF456ABC123DEF456ABC123DE` |
-
-NOTE: **Note:**
-Regardless of whether the container has public access enabled or disabled, Fog will
-use the TempURL method to grant access to LFS objects. If you see errors in logs referencing
-instantiating storage with a temp-url-key, ensure that you have set they key properly
-on the Rackspace API and in `gitlab.rb`. You can verify the value of the key Rackspace
-has set by sending a GET request with token header to the service access endpoint URL
-and comparing the output of the returned headers.
-
-### Manual uploading to an object storage
-
-There are two ways to manually do the same thing as automatic uploading (described above).
-
-**Option 1: rake task**
-
-```sh
-rake gitlab:lfs:migrate
-```
-
-**Option 2: rails console**
-
-```sh
-$ sudo gitlab-rails console # Login to rails console
-
-> # Upload LFS files manually
-> LfsObject.where(file_store: [nil, 1]).find_each do |lfs_object|
-> lfs_object.file.migrate!(ObjectStorage::Store::REMOTE) if lfs_object.file.file.exists?
-> end
-```
-
-### S3 for Omnibus installations
-
-On Omnibus installations, the settings are prefixed by `lfs_object_store_`:
-
-1. Edit `/etc/gitlab/gitlab.rb` and add the following lines by replacing with
- the values you want:
-
- ```ruby
- gitlab_rails['lfs_object_store_enabled'] = true
- gitlab_rails['lfs_object_store_remote_directory'] = "lfs-objects"
- gitlab_rails['lfs_object_store_connection'] = {
- 'provider' => 'AWS',
- 'region' => 'eu-central-1',
- 'aws_access_key_id' => '1ABCD2EFGHI34JKLM567N',
- 'aws_secret_access_key' => 'abcdefhijklmnopQRSTUVwxyz0123456789ABCDE',
- # The below options configure an S3 compatible host instead of AWS
- 'host' => 'localhost',
- 'endpoint' => 'http://127.0.0.1:9000',
- 'path_style' => true
- }
- ```
-
-1. Save the file and [reconfigure GitLab]s for the changes to take effect.
-1. Migrate any existing local LFS objects to the object storage:
-
- ```bash
- gitlab-rake gitlab:lfs:migrate
- ```
-
- This will migrate existing LFS objects to object storage. New LFS objects
- will be forwarded to object storage unless
- `gitlab_rails['lfs_object_store_background_upload']` is set to false.
-
-### S3 for installations from source
-
-For source installations the settings are nested under `lfs:` and then
-`object_store:`:
-
-1. Edit `/home/git/gitlab/config/gitlab.yml` and add or amend the following
- lines:
-
- ```yaml
- lfs:
- enabled: true
- object_store:
- enabled: false
- remote_directory: lfs-objects # Bucket name
- connection:
- provider: AWS
- aws_access_key_id: 1ABCD2EFGHI34JKLM567N
- aws_secret_access_key: abcdefhijklmnopQRSTUVwxyz0123456789ABCDE
- region: eu-central-1
- # Use the following options to configure an AWS compatible host such as Minio
- host: 'localhost'
- endpoint: 'http://127.0.0.1:9000'
- path_style: true
- ```
-
-1. Save the file and [restart GitLab][] for the changes to take effect.
-1. Migrate any existing local LFS objects to the object storage:
-
- ```bash
- sudo -u git -H bundle exec rake gitlab:lfs:migrate RAILS_ENV=production
- ```
-
- This will migrate existing LFS objects to object storage. New LFS objects
- will be forwarded to object storage unless `background_upload` is set to
- false.
-
-### Migrating back to local storage
-
-In order to migrate back to local storage:
-
-1. Set both `direct_upload` and `background_upload` to false under the LFS object storage settings. Don't forget to restart GitLab.
-1. Run `rake gitlab:lfs:migrate_to_local` on your console.
-1. Disable `object_storage` for LFS objects in `gitlab.rb`. Remember to restart GitLab afterwards.
-
-## Storage statistics
-
-You can see the total storage used for LFS objects on groups and projects
-in the administration area, as well as through the [groups](../../api/groups.md)
-and [projects APIs](../../api/projects.md).
-
-## Troubleshooting: `Google::Apis::TransmissionError: execution expired`
-
-If LFS integration is configred with Google Cloud Storage and background uploads (`background_upload: true` and `direct_upload: false`),
-Sidekiq workers may encouter this error. This is because the uploading timed out with very large files.
-LFS files up to 6Gb can be uploaded without any extra steps, otherwise you need to use the following workaround.
-
-```shell
-$ sudo gitlab-rails console # Login to rails console
-
-> # Set up timeouts. 20 minutes is enough to upload 30GB LFS files.
-> # These settings are only in effect for the same session, i.e. they are not effective for sidekiq workers.
-> ::Google::Apis::ClientOptions.default.open_timeout_sec = 1200
-> ::Google::Apis::ClientOptions.default.read_timeout_sec = 1200
-> ::Google::Apis::ClientOptions.default.send_timeout_sec = 1200
-
-> # Upload LFS files manually. This process does not use sidekiq at all.
-> LfsObject.where(file_store: [nil, 1]).find_each do |lfs_object|
-> lfs_object.file.migrate!(ObjectStorage::Store::REMOTE) if lfs_object.file.file.exists?
-> end
-```
-
-See more information in [!19581](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/19581)
-
-## Known limitations
-
-- Support for removing unreferenced LFS objects was added in 8.14 onwards.
-- LFS authentications via SSH was added with GitLab 8.12.
-- Only compatible with the Git LFS client versions 1.1.0 and up, or 1.0.2.
-- The storage statistics currently count each LFS object multiple times for
- every project linking to it.
-
-[reconfigure gitlab]: ../../administration/restart_gitlab.md#omnibus-gitlab-reconfigure "How to reconfigure Omnibus GitLab"
-[restart gitlab]: ../../administration/restart_gitlab.md#installations-from-source "How to restart GitLab"
-[eep]: https://about.gitlab.com/pricing/ "GitLab Premium"
-[ee-2760]: https://gitlab.com/gitlab-org/gitlab/merge_requests/2760
+This document was moved to [another location](../../administration/lfs/lfs_administration.md).
diff --git a/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md b/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md
index f747a7b5196..56e2f72284a 100644
--- a/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md
+++ b/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md
@@ -1,262 +1,5 @@
-# Git LFS
+---
+redirect_to: '../../administration/lfs/manage_large_binaries_with_git_lfs.md'
+---
-Managing large files such as audio, video and graphics files has always been one
-of the shortcomings of Git. The general recommendation is to not have Git repositories
-larger than 1GB to preserve performance.
-
-![Git LFS tracking status](img/lfs-icon.png)
-
-An LFS icon is shown on files tracked by Git LFS to denote if a file is stored
-as a blob or as an LFS pointer.
-
-## How it works
-
-Git LFS client talks with the GitLab server over HTTPS. It uses HTTP Basic Authentication
-to authorize client requests. Once the request is authorized, Git LFS client receives
-instructions from where to fetch or where to push the large file.
-
-## GitLab server configuration
-
-Documentation for GitLab instance administrators is under [LFS administration doc](lfs_administration.md).
-
-## Requirements
-
-- Git LFS is supported in GitLab starting with version 8.2
-- Git LFS must be enabled under project settings
-- [Git LFS client](https://git-lfs.github.com) version 1.0.1 and up
-
-## Known limitations
-
-- Git LFS v1 original API is not supported since it was deprecated early in LFS
- development
-- When SSH is set as a remote, Git LFS objects still go through HTTPS
-- Any Git LFS request will ask for HTTPS credentials to be provided so a good Git
- credentials store is recommended
-- Git LFS always assumes HTTPS so if you have GitLab server on HTTP you will have
- to add the URL to Git config manually (see [troubleshooting](#troubleshooting))
-
-NOTE: **Note:**
-With 8.12 GitLab added LFS support to SSH. The Git LFS communication
-still goes over HTTP, but now the SSH client passes the correct credentials
-to the Git LFS client, so no action is required by the user.
-
-## Using Git LFS
-
-Lets take a look at the workflow when you need to check large files into your Git
-repository with Git LFS. For example, if you want to upload a very large file and
-check it into your Git repository:
-
-```bash
-git clone git@gitlab.example.com:group/project.git
-git lfs install # initialize the Git LFS project
-git lfs track "*.iso" # select the file extensions that you want to treat as large files
-```
-
-Once a certain file extension is marked for tracking as a LFS object you can use
-Git as usual without having to redo the command to track a file with the same extension:
-
-```bash
-cp ~/tmp/debian.iso ./ # copy a large file into the current directory
-git add . # add the large file to the project
-git commit -am "Added Debian iso" # commit the file meta data
-git push origin master # sync the git repo and large file to the GitLab server
-```
-
-**Make sure** that `.gitattributes` is tracked by Git. Otherwise Git
-LFS will not be working properly for people cloning the project:
-
-```bash
-git add .gitattributes
-```
-
-Cloning the repository works the same as before. Git automatically detects the
-LFS-tracked files and clones them via HTTP. If you performed the `git clone`
-command with a SSH URL, you have to enter your GitLab credentials for HTTP
-authentication.
-
-```bash
-git clone git@gitlab.example.com:group/project.git
-```
-
-If you already cloned the repository and you want to get the latest LFS object
-that are on the remote repository, eg. for a branch from origin:
-
-```bash
-git lfs fetch origin master
-```
-
-### Migrate an existing repo to Git LFS
-
-Read the documentation on how to [migrate an existing Git repo with Git LFS](../../topics/git/migrate_to_git_lfs/index.md).
-
-## File Locking
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/issues/35856) in GitLab 10.5.
-
-The first thing to do before using File Locking is to tell Git LFS which
-kind of files are lockable. The following command will store PNG files
-in LFS and flag them as lockable:
-
-```bash
-git lfs track "*.png" --lockable
-```
-
-After executing the above command a file named `.gitattributes` will be
-created or updated with the following content:
-
-```bash
-*.png filter=lfs diff=lfs merge=lfs -text lockable
-```
-
-You can also register a file type as lockable without using LFS
-(In order to be able to lock/unlock a file you need a remote server that implements the LFS File Locking API),
-in order to do that you can edit the `.gitattributes` file manually:
-
-```bash
-*.pdf lockable
-```
-
-After a file type has been registered as lockable, Git LFS will make
-them readonly on the file system automatically. This means you will
-need to lock the file before editing it.
-
-### Managing Locked Files
-
-Once you're ready to edit your file you need to lock it first:
-
-```bash
-git lfs lock images/banner.png
-Locked images/banner.png
-```
-
-This will register the file as locked in your name on the server:
-
-```bash
-git lfs locks
-images/banner.png joe ID:123
-```
-
-Once you have pushed your changes, you can unlock the file so others can
-also edit it:
-
-```bash
-git lfs unlock images/banner.png
-```
-
-You can also unlock by id:
-
-```bash
-git lfs unlock --id=123
-```
-
-If for some reason you need to unlock a file that was not locked by you,
-you can use the `--force` flag as long as you have a `maintainer` access on
-the project:
-
-```bash
-git lfs unlock --id=123 --force
-```
-
-## Troubleshooting
-
-### error: Repository or object not found
-
-There are a couple of reasons why this error can occur:
-
-- You don't have permissions to access certain LFS object
-
-Check if you have permissions to push to the project or fetch from the project.
-
-- Project is not allowed to access the LFS object
-
-LFS object you are trying to push to the project or fetch from the project is not
-available to the project anymore. Probably the object was removed from the server.
-
-- Local Git repository is using deprecated LFS API
-
-### Invalid status for `<url>` : 501
-
-Git LFS will log the failures into a log file.
-To view this log file, while in project directory:
-
-```bash
-git lfs logs last
-```
-
-If the status `error 501` is shown, it is because:
-
-- Git LFS is not enabled in project settings. Check your project settings and
- enable Git LFS.
-
-- Git LFS support is not enabled on the GitLab server. Check with your GitLab
- administrator why Git LFS is not enabled on the server. See
- [LFS administration documentation](lfs_administration.md) for instructions
- on how to enable LFS support.
-
-- Git LFS client version is not supported by GitLab server. Check your Git LFS
- version with `git lfs version`. Check the Git config of the project for traces
- of deprecated API with `git lfs -l`. If `batch = false` is set in the config,
- remove the line and try to update your Git LFS client. Only version 1.0.1 and
- newer are supported.
-
-### getsockopt: connection refused
-
-If you push a LFS object to a project and you receive an error similar to:
-`Post <URL>/info/lfs/objects/batch: dial tcp IP: getsockopt: connection refused`,
-the LFS client is trying to reach GitLab through HTTPS. However, your GitLab
-instance is being served on HTTP.
-
-This behaviour is caused by Git LFS using HTTPS connections by default when a
-`lfsurl` is not set in the Git config.
-
-To prevent this from happening, set the lfs url in project Git config:
-
-```bash
-git config --add lfs.url "http://gitlab.example.com/group/project.git/info/lfs"
-```
-
-### Credentials are always required when pushing an object
-
-NOTE: **Note:**
-With 8.12 GitLab added LFS support to SSH. The Git LFS communication
-still goes over HTTP, but now the SSH client passes the correct credentials
-to the Git LFS client, so no action is required by the user.
-
-Given that Git LFS uses HTTP Basic Authentication to authenticate the user pushing
-the LFS object on every push for every object, user HTTPS credentials are required.
-
-By default, Git has support for remembering the credentials for each repository
-you use. This is described in [Git credentials man pages](https://git-scm.com/docs/gitcredentials).
-
-For example, you can tell Git to remember the password for a period of time in
-which you expect to push the objects:
-
-```bash
-git config --global credential.helper 'cache --timeout=3600'
-```
-
-This will remember the credentials for an hour after which Git operations will
-require re-authentication.
-
-If you are using OS X you can use `osxkeychain` to store and encrypt your credentials.
-For Windows, you can use `wincred` or Microsoft's [Git Credential Manager for Windows](https://github.com/Microsoft/Git-Credential-Manager-for-Windows/releases).
-
-More details about various methods of storing the user credentials can be found
-on [Git Credential Storage documentation](https://git-scm.com/book/en/v2/Git-Tools-Credential-Storage).
-
-### LFS objects are missing on push
-
-GitLab checks files to detect LFS pointers on push. If LFS pointers are detected, GitLab tries to verify that those files already exist in LFS on GitLab.
-
-Verify that LFS in installed locally and consider a manual push with `git lfs push --all`.
-
-If you are storing LFS files outside of GitLab you can disable LFS on the project by setting `lfs_enabled: false` with the [projects API](../../api/projects.md#edit-project).
-
-### Hosting LFS objects externally
-
-It is possible to host LFS objects externally by setting a custom LFS url with `git config -f .lfsconfig lfs.url https://example.com/<project>.git/info/lfs`.
-
-You might choose to do this if you are using an appliance like a Sonatype Nexus to store LFS data. If you choose to use an external LFS store,
-GitLab will not be able to verify LFS objects which means that pushes will fail if you have GitLab LFS support enabled.
-
-To stop push failure, LFS support can be disabled in the [Project settings](../../user/project/settings/index.md). This means you will lose GitLab LFS value-adds (Verifying LFS objects, UI integration for LFS).
+This document was moved to [another location](../../administration/lfs/manage_large_binaries_with_git_lfs.md).
diff --git a/doc/workflow/lfs/migrate_from_git_annex_to_git_lfs.md b/doc/workflow/lfs/migrate_from_git_annex_to_git_lfs.md
index 8f24929c9dc..997ef8938a6 100644
--- a/doc/workflow/lfs/migrate_from_git_annex_to_git_lfs.md
+++ b/doc/workflow/lfs/migrate_from_git_annex_to_git_lfs.md
@@ -1,254 +1,5 @@
-# Migration guide from Git Annex to Git LFS
-
->**Note:**
-Git Annex support [has been removed][issue-remove-annex] in GitLab Enterprise
-Edition 9.0 (2017/03/22).
-
-Both [Git Annex][] and [Git LFS][] are tools to manage large files in Git.
-
-## History
-
-Git Annex [was introduced in GitLab Enterprise Edition 7.8][post-3], at a time
-where Git LFS didn't yet exist. A few months later, GitLab brought support for
-Git LFS in [GitLab 8.2][post-2] and is available for both Community and
-Enterprise editions.
-
-## Differences between Git Annex and Git LFS
-
-Some items below are general differences between the two protocols and some are
-ones that GitLab developed.
-
-- Git Annex works only through SSH, whereas Git LFS works both with SSH and HTTPS
- (SSH support was added in GitLab 8.12).
-- Annex files are stored in a sub-directory of the normal repositories, whereas
- LFS files are stored outside of the repositories in a place you can define.
-- Git Annex requires a more complex setup, but has much more options than Git
- LFS. You can compare the commands each one offers by running `man git-annex`
- and `man git-lfs`.
-- Annex files cannot be browsed directly in GitLab's interface, whereas LFS
- files can.
-
-## Migration steps
-
->**Note:**
-Since Git Annex files are stored in a sub-directory of the normal repositories
-(`.git/annex/objects`) and LFS files are stored outside of the repositories,
-they are not compatible as they are using a different scheme. Therefore, the
-migration has to be done manually per repository.
-
-There are basically two steps you need to take in order to migrate from Git
-Annex to Git LFS.
-
-### TL; DR
-
-If you know what you are doing and want to skip the reading, this is what you
-need to do (we assume you have [git-annex enabled](../git_annex.md#using-gitlab-git-annex) in your
-repository and that you have made backups in case something goes wrong).
-Fire up a terminal, navigate to your Git repository and:
-
-1. Disable `git-annex`:
-
- ```bash
- git annex sync --content
- git annex direct
- git annex uninit
- git annex indirect
- ```
-
-1. Enable `git-lfs`:
-
- ```
- git lfs install
- git lfs track <files>
- git add .
- git commit -m "commit message"
- git push
- ```
-
-### Disabling Git Annex in your repo
-
-Before changing anything, make sure you have a backup of your repository first.
-There are a couple of ways to do that, but you can simply clone it to another
-local path and maybe push it to GitLab if you want a remote backup as well.
-Here you'll find a guide on
-[how to back up a **git-annex** repository to an external hard drive][bkp-ext-drive].
-
-Since Annex files are stored as objects with symlinks and cannot be directly
-modified, we need to first remove those symlinks.
-
-NOTE: **Note:**
-Make sure the you read about the [`direct` mode][annex-direct] as it contains
-useful information that may fit in your use case. Note that `annex direct` is
-deprecated in Git Annex version 6, so you may need to upgrade your repository
-if the server also has Git Annex 6 installed. Read more in the
-[Git Annex troubleshooting tips](../git_annex.md#troubleshooting-tips) section.
-
-1. Backup your repository
-
- ```bash
- cd repository
- git annex sync --content
- cd ..
- git clone repository repository-backup
- cd repository-backup
- git annex get
- cd ..
- ```
-
-1. Use `annex direct`:
-
- ```bash
- cd repository
- git annex direct
- ```
-
- The output should be similar to this:
-
- ```bash
- commit
- On branch master
- Your branch is up-to-date with 'origin/master'.
- nothing to commit, working tree clean
- ok
- direct debian.iso ok
- direct ok
- ```
-
-1. Disable Git Annex with [`annex uninit`][uninit]:
-
- ```bash
- git annex uninit
- ```
-
- The output should be similar to this:
-
- ```bash
- unannex debian.iso ok
- Deleted branch git-annex (was 2534d2c).
- ```
-
- This will `unannex` every file in the repository, leaving the original files.
-
-1. Switch back to `indirect` mode:
-
- ```bash
- git annex indirect
- ```
-
- The output should be similar to this:
-
- ```bash
- (merging origin/git-annex into git-annex...)
- (recording state in git...)
- commit (recording state in git...)
-
- ok
- (recording state in git...)
- [master fac3194] commit before switching to indirect mode
- 1 file changed, 1 deletion(-)
- delete mode 120000 alpine-virt-3.4.4-x86_64.iso
- ok
- indirect ok
- ok
- ```
-
+---
+redirect_to: '../../administration/lfs/migrate_from_git_annex_to_git_lfs.md'
---
-At this point, you have two options. Either add, commit and push the files
-directly back to GitLab or switch to Git LFS. We will tackle the LFS switch in
-the next section.
-
-### Enabling Git LFS in your repo
-
-Git LFS is enabled by default on all GitLab products (GitLab CE, GitLab EE,
-GitLab.com), therefore, you don't need to do anything server-side.
-
-1. First, make sure you have `git-lfs` installed locally:
-
- ```bash
- git lfs help
- ```
-
- If the terminal doesn't prompt you with a full response on `git-lfs` commands,
- [install the Git LFS client][install-lfs] first.
-
-1. Inside the repo, run the following command to initiate LFS:
-
- ```bash
- git lfs install
- ```
-
-1. Enable `git-lfs` for the group of files you want to track. You
- can track specific files, all files containing the same extension, or an
- entire directory:
-
- ```bash
- git lfs track images/01.png # per file
- git lfs track **/*.png # per extension
- git lfs track images/ # per directory
- ```
-
- Once you do that, run `git status` and you'll see `.gitattributes` added
- to your repo. It collects all file patterns that you chose to track via
- `git-lfs`.
-
-1. Add the files, commit and push them to GitLab:
-
- ```bash
- git add .
- git commit -m "commit message"
- git push
- ```
-
- If your remote is set up with HTTP, you will be asked to enter your login
- credentials. If you have [2FA enabled](../../user/profile/account/two_factor_authentication.md), make sure to use a
- [personal access token](../../user/profile/account/two_factor_authentication.md#personal-access-tokens)
- instead of your password.
-
-## Removing the Git Annex branches
-
-After the migration finishes successfully, you can remove all `git-annex`
-related branches from your repository.
-
-On GitLab, navigate to your project's **Repository ➔ Branches** and delete all
-branches created by Git Annex: `git-annex`, and all under `synced/`.
-
-![repository branches](images/git-annex-branches.png)
-
-You can also do this on the command line with:
-
-```bash
-git branch -d synced/master
-git branch -d synced/git-annex
-git push origin :synced/master
-git push origin :synced/git-annex
-git push origin :git-annex
-git remote prune origin
-```
-
-If there are still some Annex objects inside your repository (`.git/annex/`)
-or references inside `.git/config`, run `annex uninit` again:
-
-```bash
-git annex uninit
-```
-
-## Further Reading
-
-- (Blog Post) [Getting Started with Git FLS][post-1]
-- (Blog Post) [Announcing LFS Support in GitLab][post-2]
-- (Blog Post) [GitLab Annex Solves the Problem of Versioning Large Binaries with Git][post-3]
-- (GitLab Docs) [Git Annex](../git_annex.md)
-- (GitLab Docs) [Git LFS](manage_large_binaries_with_git_lfs.md)
-
-[annex-direct]: https://git-annex.branchable.com/direct_mode/
-[bkp-ext-drive]: https://www.thomas-krenn.com/en/wiki/Git-annex_Repository_on_an_External_Hard_Drive
-[Git Annex]: http://git-annex.branchable.com/
-[Git LFS]: https://git-lfs.github.com/
-[install-lfs]: https://git-lfs.github.com/
-[issue-remove-annex]: https://gitlab.com/gitlab-org/gitlab/issues/1648
-[lfs-track]: https://about.gitlab.com/blog/2017/01/30/getting-started-with-git-lfs-tutorial/#tracking-files-with-lfs
-[post-1]: https://about.gitlab.com/blog/2017/01/30/getting-started-with-git-lfs-tutorial/
-[post-2]: https://about.gitlab.com/blog/2015/11/23/announcing-git-lfs-support-in-gitlab/
-[post-3]: https://about.gitlab.com/blog/2015/02/17/gitlab-annex-solves-the-problem-of-versioning-large-binaries-with-git/
-[uninit]: https://git-annex.branchable.com/git-annex-uninit/
+This document was moved to [another location](../../administration/lfs/migrate_from_git_annex_to_git_lfs.md).
diff --git a/doc/workflow/notifications.md b/doc/workflow/notifications.md
index d619c870c5e..23f96360484 100644
--- a/doc/workflow/notifications.md
+++ b/doc/workflow/notifications.md
@@ -1,172 +1,5 @@
-# GitLab Notification Emails
+---
+redirect_to: '../user/profile/notifications.md'
+---
-GitLab has a notification system in place to notify a user of events that are important for the workflow.
-
-## Notification settings
-
-You can find notification settings under the user profile.
-
-![notification settings](img/notification_global_settings.png)
-
-Notification settings are divided into three groups:
-
-- Global settings
-- Group settings
-- Project settings
-
-Each of these settings have levels of notification:
-
-- Global: For groups and projects, notifications as per global settings.
-- Watch: Receive notifications for any activity.
-- Participate: Receive notifications for threads you have participated in.
-- On Mention: Receive notifications when `@mentioned` in comments.
-- Disabled: Turns off notifications.
-- Custom: Receive notifications for custom selected events.
-
-> Introduced in GitLab 12.0
-
-You can also select an email address to receive notifications for each group you belong to.
-
-### Global Settings
-
-Global settings are at the bottom of the hierarchy.
-Any setting set here will be overridden by a setting at the group or a project level.
-
-Group or Project settings can use `global` notification setting which will then use
-anything that is set at Global Settings.
-
-### Group Settings
-
-![notification settings](img/notification_group_settings.png)
-
-Group settings are taking precedence over Global Settings but are on a level below Project or Subgroup settings:
-
-```
-Group < Subgroup < Project
-```
-
-This means that you can set a different level of notifications per group while still being able
-to have a finer level setting per project or subgroup.
-Organization like this is suitable for users that belong to different groups but don't have the
-same need for being notified for every group they are member of.
-These settings can be configured on group page under the name of the group. It will be the dropdown with the bell icon. They can also be configured on the user profile notifications dropdown.
-
-The group owner can disable email notifications for a group, which also includes
-it's subgroups and projects. If this is the case, you will not receive any corresponding notifications,
-and the notification button will be disabled with an explanatory tooltip.
-
-### Project Settings
-
-![notification settings](img/notification_project_settings.png)
-
-Project settings are at the top level and any setting placed at this level will take precedence of any
-other setting.
-This is suitable for users that have different needs for notifications per project basis.
-These settings can be configured on project page under the name of the project. It will be the dropdown with the bell icon. They can also be configured on the user profile notifications dropdown.
-
-The project owner (or it's group owner) can disable email notifications for the project.
-If this is the case, you will not receive any corresponding notifications, and the notification
-button will be disabled with an explanatory tooltip.
-
-## Notification events
-
-Below is the table of events users can be notified of:
-
-| Event | Sent to | Settings level |
-|------------------------------|---------------------|------------------------------|
-| New SSH key added | User | Security email, always sent. |
-| New email added | User | Security email, always sent. |
-| Email changed | User | Security email, always sent. |
-| Password changed | User | Security email, always sent. |
-| New user created | User | Sent on user creation, except for OmniAuth (LDAP)|
-| User added to project | User | Sent when user is added to project |
-| Project access level changed | User | Sent when user project access level is changed |
-| User added to group | User | Sent when user is added to group |
-| Group access level changed | User | Sent when user group access level is changed |
-| Project moved | Project members (1) | (1) not disabled |
-| New release | Project members | Custom notification |
-
-### Issue / Epics / Merge request events
-
-In most of the below cases, the notification will be sent to:
-
-- Participants:
- - the author and assignee of the issue/merge request
- - authors of comments on the issue/merge request
- - anyone mentioned by `@username` in the title or description of the issue, merge request or epic **(ULTIMATE)**
- - anyone with notification level "Participating" or higher that is mentioned by `@username`
- in any of the comments on the issue, merge request, or epic **(ULTIMATE)**
-- Watchers: users with notification level "Watch"
-- Subscribers: anyone who manually subscribed to the issue, merge request, or epic **(ULTIMATE)**
-- Custom: Users with notification level "custom" who turned on notifications for any of the events present in the table below
-
-| Event | Sent to |
-|------------------------|---------|
-| New issue | |
-| Close issue | |
-| Reassign issue | The above, plus the old assignee |
-| Reopen issue | |
-| Due issue | Participants and Custom notification level with this event selected |
-| Change milestone issue | Subscribers, participants mentioned, and Custom notification level with this event selected |
-| Remove milestone issue | Subscribers, participants mentioned, and Custom notification level with this event selected |
-| New merge request | |
-| Push to merge request | Participants and Custom notification level with this event selected |
-| Reassign merge request | The above, plus the old assignee |
-| Close merge request | |
-| Reopen merge request | |
-| Merge merge request | |
-| Change milestone merge request | Subscribers, participants mentioned, and Custom notification level with this event selected |
-| Remove milestone merge request | Subscribers, participants mentioned, and Custom notification level with this event selected |
-| New comment | The above, plus anyone mentioned by `@username` in the comment, with notification level "Mention" or higher |
-| Failed pipeline | The author of the pipeline |
-| Successful pipeline | The author of the pipeline, if they have the custom notification setting for successful pipelines set |
-| New epic **(ULTIMATE)** | |
-| Close epic **(ULTIMATE)** | |
-| Reopen epic **(ULTIMATE)** | |
-
-In addition, if the title or description of an Issue or Merge Request is
-changed, notifications will be sent to any **new** mentions by `@username` as
-if they had been mentioned in the original text.
-
-You won't receive notifications for Issues, Merge Requests or Milestones created
-by yourself (except when an issue is due). You will only receive automatic
-notifications when somebody else comments or adds changes to the ones that
-you've created or mentions you.
-
-If an open merge request becomes unmergeable due to conflict, its author will be notified about the cause.
-If a user has also set the merge request to automatically merge once pipeline succeeds,
-then that user will also be notified.
-
-### Email Headers
-
-Notification emails include headers that provide extra content about the notification received:
-
-| Header | Description |
-|-----------------------------|-------------------------------------------------------------------------|
-| X-GitLab-Project | The name of the project the notification belongs to |
-| X-GitLab-Project-Id | The ID of the project |
-| X-GitLab-Project-Path | The path of the project |
-| X-GitLab-(Resource)-ID | The ID of the resource the notification is for, where resource is `Issue`, `MergeRequest`, `Commit`, etc|
-| X-GitLab-Discussion-ID | Only in comment emails, the ID of the thread the comment is from |
-| X-GitLab-Pipeline-Id | Only in pipeline emails, the ID of the pipeline the notification is for |
-| X-GitLab-Reply-Key | A unique token to support reply by email |
-| X-GitLab-NotificationReason | The reason for being notified. "mentioned", "assigned", etc |
-| List-Id | The path of the project in a RFC 2919 mailing list identifier useful for email organization, for example, with Gmail filters |
-
-#### X-GitLab-NotificationReason
-
-This header holds the reason for the notification to have been sent out,
-where reason can be `mentioned`, `assigned`, `own_activity`, etc.
-Only one reason is sent out according to its priority:
-
-- `own_activity`
-- `assigned`
-- `mentioned`
-
-The reason in this header will also be shown in the footer of the notification email. For example an email with the
-reason `assigned` will have this sentence in the footer:
-`"You are receiving this email because you have been assigned an item on {configured GitLab hostname}"`
-
-NOTE: **Note:**
-Only reasons listed above have been implemented so far.
-Further implementation is [being discussed](https://gitlab.com/gitlab-org/gitlab-foss/issues/42062).
+This document was moved to [another location](../user/profile/notifications.md).
diff --git a/doc/workflow/releases.md b/doc/workflow/releases.md
index 1fd63a556c6..f3ba61f6a5c 100644
--- a/doc/workflow/releases.md
+++ b/doc/workflow/releases.md
@@ -1,22 +1,5 @@
-# Releases
+---
+redirect_to: '../user/project/releases/index.md#add-release-notes-to-git-tags'
+---
-NOTE: In GitLab 11.7, we introduced the full fledged [Releases](../user/project/releases/index.md)
-feature. You can still create release notes on this page, but the new method is preferred.
-
-You can add release notes to any Git tag using the notes feature. Release notes
-behave like any other markdown form in GitLab so you can write text and
-drag-n-drop files to it. Release notes are stored in GitLab's database.
-
-There are several ways to add release notes:
-
-- In the interface, when you create a new Git tag
-- In the interface, by adding a note to an existing Git tag
-- Using the GitLab API
-
-## New tag page with release notes text area
-
-![new_tag](releases/new_tag.png)
-
-## Tags page with button to add or edit release notes for existing Git tag
-
-![tags](releases/tags.png)
+This document was moved to [another location](../user/project/releases/index.md#add-release-notes-to-git-tags).
diff --git a/doc/workflow/repository_mirroring.md b/doc/workflow/repository_mirroring.md
index 6d1a5913789..dc77f4f47af 100644
--- a/doc/workflow/repository_mirroring.md
+++ b/doc/workflow/repository_mirroring.md
@@ -1,426 +1,5 @@
-# Repository mirroring
-
-Repository mirroring allows for mirroring of repositories to and from external sources. It can be
-used to mirror branches, tags, and commits between repositories.
-
-A repository mirror at GitLab will be updated automatically. You can also manually trigger an update
-at most once every 5 minutes.
-
-## Overview
-
-Repository mirroring is useful when you want to use a repository outside of GitLab.
-
-There are two kinds of repository mirroring supported by GitLab:
-
-- Push: for mirroring a GitLab repository to another location.
-- Pull: for mirroring a repository from another location to GitLab. **(STARTER)**
-
-When the mirror repository is updated, all new branches, tags, and commits will be visible in the
-project's activity feed.
-
-Users with at least [developer access](../user/permissions.md) to the project can also force an
-immediate update, unless:
-
-- The mirror is already being updated.
-- 5 minutes haven't elapsed since its last update.
-
-## Use cases
-
-The following are some possible use cases for repository mirroring:
-
-- You migrated to GitLab but still need to keep your project in another source. In that case, you
- can simply set it up to mirror to GitLab (pull) and all the essential history of commits, tags,
- and branches will be available in your GitLab instance. **(STARTER)**
-- You have old projects in another source that you don't use actively anymore, but don't want to
- remove for archiving purposes. In that case, you can create a push mirror so that your active
- GitLab repository can push its changes to the old location.
-
-## Pushing to a remote repository **(CORE)**
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/249) in GitLab Enterprise Edition 8.7.
-> - [Moved to GitLab Core](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/18715) in 10.8.
-
-For an existing project, you can set up push mirroring as follows:
-
-1. Navigate to your project's **Settings > Repository** and expand the **Mirroring repositories** section.
-1. Enter a repository URL.
-1. Select **Push** from the **Mirror direction** dropdown.
-1. Select an authentication method from the **Authentication method** dropdown, if necessary.
-1. Check the **Only mirror protected branches** box, if necessary.
-1. Click the **Mirror repository** button to save the configuration.
-
-![Repository mirroring push settings screen](img/repository_mirroring_push_settings.png)
-
-When push mirroring is enabled, only push commits directly to the mirrored repository to prevent the
-mirror diverging. All changes will end up in the mirrored repository whenever:
-
-- Commits are pushed to GitLab.
-- A [forced update](#forcing-an-update-core) is initiated.
-
-Changes pushed to files in the repository are automatically pushed to the remote mirror at least:
-
-- Within five minutes of being received.
-- Within one minute if **Only mirror protected branches** is enabled.
-
-In the case of a diverged branch, you will see an error indicated at the **Mirroring repositories**
-section.
-
-### Push only protected branches **(CORE)**
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/3350) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.3.
-> - [Moved to GitLab Core](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/18715) in 10.8.
-
-You can choose to only push your protected branches from GitLab to your remote repository.
-
-To use this option, check the **Only mirror protected branches** box when creating a repository
-mirror.
-
-## Setting up a push mirror from GitLab to GitHub **(CORE)**
-
-To set up a mirror from GitLab to GitHub, you need to follow these steps:
-
-1. Create a [GitHub personal access token](https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line) with the `public_repo` box checked.
-1. Fill in the **Git repository URL** field using this format: `https://<your_github_username>@github.com/<your_github_group>/<your_github_project>.git`.
-1. Fill in **Password** field with your GitHub personal access token.
-1. Click the **Mirror repository** button.
-
-The mirrored repository will be listed. For example, `https://*****:*****@github.com/<your_github_group>/<your_github_project>.git`.
-
-The repository will push soon. To force a push, click the appropriate button.
-
-## Setting up a push mirror to another GitLab instance with 2FA activated
-
-1. On the destination GitLab instance, create a [personal access token](../user/profile/personal_access_tokens.md) with `API` scope.
-1. On the source GitLab instance:
- 1. Fill in the **Git repository URL** field using this format: `https://oauth2@<destination host>/<your_gitlab_group_or_name>/<your_gitlab_project>.git`.
- 1. Fill in **Password** field with the GitLab personal access token created on the destination GitLab instance.
- 1. Click the **Mirror repository** button.
-
-## Pulling from a remote repository **(STARTER)**
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/51) in GitLab Enterprise Edition 8.2.
-> - [Added Git LFS support](https://gitlab.com/gitlab-org/gitlab/issues/10871) in [GitLab Starter](https://about.gitlab.com/pricing/) 11.11.
-
-NOTE: **Note:** This feature [is available for free](https://gitlab.com/gitlab-org/gitlab/issues/10361) to
-GitLab.com users until March 22nd, 2020.
-
-You can set up a repository to automatically have its branches, tags, and commits updated from an
-upstream repository.
-
-This is useful when a repository you're interested in is located on a different server, and you want
-to be able to browse its content and its activity using the familiar GitLab interface.
-
-To configure mirror pulling for an existing project:
-
-1. Navigate to your project's **Settings > Repository** and expand the **Mirroring repositories**
- section.
-1. Enter a repository URL.
-1. Select **Pull** from the **Mirror direction** dropdown.
-1. Select an authentication method from the **Authentication method** dropdown, if necessary.
-1. If necessary, check the following boxes:
- - **Overwrite diverged branches**.
- - **Trigger pipelines for mirror updates**.
- - **Only mirror protected branches**.
-1. Click the **Mirror repository** button to save the configuration.
-
-![Repository mirroring pull settings screen - upper part](img/repository_mirroring_pull_settings_upper.png)
-
+---
+redirect_to: '../user/project/repository/repository_mirroring.md'
---
-![Repository mirroring pull settings screen - lower part](img/repository_mirroring_pull_settings_lower.png)
-
-Because GitLab is now set to pull changes from the upstream repository, you should not push commits
-directly to the repository on GitLab. Instead, any commits should be pushed to the upstream repository.
-Changes pushed to the upstream repository will be pulled into the GitLab repository, either:
-
-- Automatically within a certain period of time.
-- When a [forced update](#forcing-an-update-core) is initiated.
-
-CAUTION: **Caution:**
-If you do manually update a branch in the GitLab repository, the branch will become diverged from
-upstream and GitLab will no longer automatically update this branch to prevent any changes from being lost.
-
-### How it works
-
-Once the pull mirroring feature has been enabled for a repository, the repository is added to a queue.
-
-Once per minute, a Sidekiq cron job schedules repository mirrors to update, based on:
-
-- The capacity available. This is determined by Sidekiq settings. For GitLab.com, see [GitLab.com Sidekiq settings](../user/gitlab_com/index.md#sidekiq).
-- The number of repository mirrors already in the queue that are due to be updated. Being due depends on when the repository mirror was last updated and how many times it's been retried.
-
-Repository mirrors are updated as Sidekiq becomes available to process them. If the process of updating the repository mirror:
-
-- Succeeds, an update will be enqueued again with at least a 30 minute wait.
-- Fails (for example, a branch diverged from upstream), it will be attempted again later. Mirrors can fail
- up to 14 times before they will not be enqueued for update again.
-
-### SSH authentication
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/2551) for Pull mirroring in [GitLab Starter](https://about.gitlab.com/pricing/) 9.5.
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/22982) for Push mirroring in [GitLab Core](https://about.gitlab.com/pricing/) 11.6
-
-SSH authentication is mutual:
-
-- You have to prove to the server that you're allowed to access the repository.
-- The server also has to prove to *you* that it's who it claims to be.
-
-You provide your credentials as a password or public key. The server that the
-other repository resides on provides its credentials as a "host key", the
-fingerprint of which needs to be verified manually.
-
-If you're mirroring over SSH (that is, using an `ssh://` URL), you can authenticate using:
-
-- Password-based authentication, just as over HTTPS.
-- Public key authentication. This is often more secure than password authentication,
- especially when the other repository supports [Deploy Keys](../ssh/README.md#deploy-keys).
-
-To get started:
-
-1. Navigate to your project's **Settings > Repository** and expand the **Mirroring repositories** section.
-1. Enter an `ssh://` URL for mirroring.
-
-NOTE: **Note:**
-SCP-style URLs (that is, `git@example.com:group/project.git`) are not supported at this time.
-
-Entering the URL adds two buttons to the page:
-
-- **Detect host keys**.
-- **Input host keys manually**.
-
-If you click the:
-
-- **Detect host keys** button, GitLab will fetch the host keys from the server and display the fingerprints.
-- **Input host keys manually** button, a field is displayed where you can paste in host keys.
-
-Assuming you used the former, you now need to verify that the fingerprints are
-those you expect. GitLab.com and other code hosting sites publish their
-fingerprints in the open for you to check:
-
-- [AWS CodeCommit](https://docs.aws.amazon.com/codecommit/latest/userguide/regions.html#regions-fingerprints)
-- [Bitbucket](https://confluence.atlassian.com/bitbucket/ssh-keys-935365775.html)
-- [GitHub](https://help.github.com/en/articles/githubs-ssh-key-fingerprints)
-- [GitLab.com](../user/gitlab_com/index.md#ssh-host-keys-fingerprints)
-- [Launchpad](https://help.launchpad.net/SSHFingerprints)
-- [Savannah](http://savannah.gnu.org/maintenance/SshAccess/)
-- [SourceForge](https://sourceforge.net/p/forge/documentation/SSH%20Key%20Fingerprints/)
-
-Other providers will vary. If you're running self-managed GitLab, or otherwise
-have access to the server for the other repository, you can securely gather the
-key fingerprints:
-
-```sh
-$ cat /etc/ssh/ssh_host*pub | ssh-keygen -E md5 -l -f -
-256 MD5:f4:28:9f:23:99:15:21:1b:bf:ed:1f:8e:a0:76:b2:9d root@example.com (ECDSA)
-256 MD5:e6:eb:45:8a:3c:59:35:5f:e9:5b:80:12:be:7e:22:73 root@example.com (ED25519)
-2048 MD5:3f:72:be:3d:62:03:5c:62:83:e8:6e:14:34:3a:85:1d root@example.com (RSA)
-```
-
-NOTE: **Note:**
-You may need to exclude `-E md5` for some older versions of SSH.
-
-When mirroring the repository, GitLab will now check that at least one of the
-stored host keys matches before connecting. This can prevent malicious code from
-being injected into your mirror, or your password being stolen.
-
-### SSH public key authentication
-
-To use SSH public key authentication, you'll also need to choose that option
-from the **Authentication method** dropdown. When the mirror is created,
-GitLab generates a 4096-bit RSA key that can be copied by clicking the **Copy SSH public key** button.
-
-![Repository mirroring copy SSH public key to clipboard button](img/copy_ssh_public_key_button.png)
-
-You then need to add the public SSH key to the other repository's configuration:
-
-- If the other repository is hosted on GitLab, you should add the public SSH key
- as a [Deploy Key](../ssh/README.md#deploy-keys).
-- If the other repository is hosted elsewhere, you may need to add the key to
- your user's `authorized_keys` file. Paste the entire public SSH key into the
- file on its own line and save it.
-
-If you need to change the key at any time, you can remove and re-add the mirror
-to generate a new key. You'll have to update the other repository with the new
-key to keep the mirror running.
-
-### Overwrite diverged branches **(STARTER)**
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/4559) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.6.
-
-You can choose to always update your local branches with remote versions, even if they have
-diverged from the remote.
-
-CAUTION: **Caution:**
-For mirrored branches, enabling this option results in the loss of local changes.
-
-To use this option, check the **Overwrite diverged branches** box when creating a repository mirror.
-
-### Only mirror protected branches **(STARTER)**
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/3326) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.3.
-
-You can choose to pull mirror only the protected branches from your remote repository to GitLab.
-Non-protected branches are not mirrored and can diverge.
-
-To use this option, check the **Only mirror protected branches** box when creating a repository mirror.
-
-### Hard failure **(STARTER)**
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/3117) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.2.
-
-Once the mirroring process is unsuccessfully retried 14 times in a row, it will get marked as hard
-failed. This will become visible in either the:
-
-- Project's main dashboard.
-- Pull mirror settings page.
-
-When a project is hard failed, it will no longer get picked up for mirroring. A user can resume the
-project mirroring again by [Forcing an update](#forcing-an-update-core).
-
-### Trigger update using API **(STARTER)**
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/3453) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.3.
-
-Pull mirroring uses polling to detect new branches and commits added upstream, often minutes
-afterwards. If you notify GitLab by [API](../api/projects.md#start-the-pull-mirroring-process-for-a-project-starter),
-updates will be pulled immediately.
-
-For more information, see [Start the pull mirroring process for a Project](../api/projects.md#start-the-pull-mirroring-process-for-a-project-starter).
-
-## Forcing an update **(CORE)**
-
-While mirrors are scheduled to update automatically, you can always force an update by using the
-update button which is available on the **Mirroring repositories** section of the **Repository Settings** page.
-
-![Repository mirroring force update user interface](img/repository_mirroring_force_update.png)
-
-## Bidirectional mirroring **(STARTER)**
-
-CAUTION: **Caution:**
-Bidirectional mirroring may cause conflicts.
-
-If you configure a GitLab repository to both pull from, and push to, the same remote source, there
-is no guarantee that either repository will update correctly. If you set up a repository for
-bidirectional mirroring, you should prepare for the likely conflicts by deciding who will resolve
-them and how they will be resolved.
-
-Rewriting any mirrored commit on either remote will cause conflicts and mirroring to fail. This can
-be prevented by:
-
-- [Pulling only protected branches](#only-mirror-protected-branches-starter).
-- [Pushing only protected branches](#push-only-protected-branches-core).
-
-You should [protect the branches](../user/project/protected_branches.md) you wish to mirror on both
-remotes to prevent conflicts caused by rewriting history.
-
-Bidirectional mirroring also creates a race condition where commits made close together to the same
-branch causes conflicts. The race condition can be mitigated by reducing the mirroring delay by using
-a [Push event webhook](../user/project/integrations/webhooks.md#push-events) to trigger an immediate
-pull to GitLab. Push mirroring from GitLab is rate limited to once per minute when only push mirroring
-protected branches.
-
-### Preventing conflicts using a `pre-receive` hook
-
-CAUTION: **Warning:**
-The solution proposed will negatively impact the performance of
-Git push operations because they will be proxied to the upstream Git
-repository.
-
-A server-side `pre-receive` hook can be used to prevent the race condition
-described above by only accepting the push after first pushing the commit to
-the upstream Git repository. In this configuration one Git repository acts as
-the authoritative upstream, and the other as downstream. The `pre-receive` hook
-will be installed on the downstream repository.
-
-Read about [configuring custom Git hooks](../administration/custom_hooks.md) on the GitLab server.
-
-A sample `pre-receive` hook is provided below.
-
-```bash
-#!/usr/bin/env bash
-
-# --- Assume only one push mirror target
-# Push mirroring remotes are named `remote_mirror_<id>`, this finds the first remote and uses that.
-TARGET_REPO=$(git remote | grep -m 1 remote_mirror)
-
-proxy_push()
-{
- # --- Arguments
- OLDREV=$(git rev-parse $1)
- NEWREV=$(git rev-parse $2)
- REFNAME="$3"
-
- # --- Pattern of branches to proxy pushes
- whitelisted=$(expr "$branch" : "\(master\)")
-
- case "$refname" in
- refs/heads/*)
- branch=$(expr "$refname" : "refs/heads/\(.*\)")
-
- if [ "$whitelisted" = "$branch" ]; then
- error="$(git push --quiet $TARGET_REPO $NEWREV:$REFNAME 2>&1)"
- fail=$?
-
- if [ "$fail" != "0" ]; then
- echo >&2 ""
- echo >&2 " Error: updates were rejected by upstream server"
- echo >&2 " This is usually caused by another repository pushing changes"
- echo >&2 " to the same ref. You may want to first integrate remote changes"
- echo >&2 ""
- return
- fi
- fi
- ;;
- esac
-}
-
-# Allow dual mode: run from the command line just like the update hook, or
-# if no arguments are given then run as a hook script
-if [ -n "$1" -a -n "$2" -a -n "$3" ]; then
- # Output to the terminal in command line mode - if someone wanted to
- # resend an email; they could redirect the output to sendmail
- # themselves
- PAGER= proxy_push $2 $3 $1
-else
- # Push is proxied upstream one ref at a time. Because of this it is possible
- # for some refs to succeed, and others to fail. This will result in a failed
- # push.
- while read oldrev newrev refname
- do
- proxy_push $oldrev $newrev $refname
- done
-fi
-```
-
-### Mirroring with Perforce Helix via Git Fusion **(STARTER)**
-
-CAUTION: **Warning:**
-Bidirectional mirroring should not be used as a permanent configuration. Refer to
-[Migrating from Perforce Helix](../user/project/import/perforce.md) for alternative migration approaches.
-
-[Git Fusion](https://www.perforce.com/manuals/git-fusion/#Git-Fusion/section_avy_hyc_gl.html) provides a Git interface
-to [Perforce Helix](https://www.perforce.com/products) which can be used by GitLab to bidirectionally
-mirror projects with GitLab. This may be useful in some situations when migrating from Perforce Helix
-to GitLab where overlapping Perforce Helix workspaces cannot be migrated simultaneously to GitLab.
-
-If using mirroring with Perforce Helix, you should only mirror protected branches. Perforce Helix
-will reject any pushes that rewrite history. Only the fewest number of branches should be mirrored
-due to the performance limitations of Git Fusion.
-
-When configuring mirroring with Perforce Helix via Git Fusion, the following Git Fusion
-settings are recommended:
-
-- `change-pusher` should be disabled. Otherwise, every commit will be rewritten as being committed
- by the mirroring account, rather than being mapped to existing Perforce Helix users or the `unknown_git` user.
-- `unknown_git` user will be used as the commit author if the GitLab user does not exist in
- Perforce Helix.
-
-Read about [Git Fusion settings on Perforce.com](https://www.perforce.com/manuals/git-fusion/Content/Git-Fusion/section_vss_bdw_w3.html#section_zdp_zz1_3l).
-
-## Troubleshooting
-
-Should an error occur during a push, GitLab will display an "Error" highlight for that repository. Details on the error can then be seen by hovering over the highlight text.
-
-### 13:Received RST_STREAM with error code 2 with GitHub
-
-If you receive an "13:Received RST_STREAM with error code 2" while mirroring to a GitHub repository, your GitHub settings might be set to block pushes that expose your email address used in commits. Either set your email address on GitHub to be public, or disable the [Block command line pushes that expose my email](https://github.com/settings/emails) setting.
+This document was moved to [another location](../user/project/repository/repository_mirroring.md).
diff --git a/doc/workflow/shortcuts.md b/doc/workflow/shortcuts.md
index 2ec733182f8..4b35c61ec5e 100644
--- a/doc/workflow/shortcuts.md
+++ b/doc/workflow/shortcuts.md
@@ -1,134 +1,5 @@
---
-type: reference
+redirect_to: '../user/shortcuts.md'
---
-# GitLab keyboard shortcuts
-
-GitLab has many useful keyboard shortcuts to make it easier to access different features.
-You can see the quick reference sheet within GitLab itself with <kbd>Shift</kbd> + <kbd>?</kbd>.
-
-The [Global Shortcuts](#global-shortcuts) work from any area of GitLab, but you must
-be in specific pages for the other shortcuts to be available, as explained in each
-section below.
-
-## Global Shortcuts
-
-These shortcuts are available in most areas of GitLab
-
-| Keyboard Shortcut | Description |
-| ------------------------------- | ----------- |
-| <kbd>?</kbd> | Show/hide shortcut reference sheet. |
-| <kbd>Shift</kbd> + <kbd>p</kbd> | Go to your Projects page. |
-| <kbd>Shift</kbd> + <kbd>g</kbd> | Go to your Groups page. |
-| <kbd>Shift</kbd> + <kbd>a</kbd> | Go to your Activity page. |
-| <kbd>Shift</kbd> + <kbd>l</kbd> | Go to your Milestones page. |
-| <kbd>Shift</kbd> + <kbd>s</kbd> | Go to your Snippets page. |
-| <kbd>s</kbd> | Put cursor in the issues/merge requests search. |
-| <kbd>Shift</kbd> + <kbd>i</kbd> | Go to your Issues page. |
-| <kbd>Shift</kbd> + <kbd>m</kbd> | Go to your Merge requests page.|
-| <kbd>Shift</kbd> + <kbd>t</kbd> | Go to your To-Do List page. |
-| <kbd>p</kbd> + <kbd>b</kbd> | Show/hide the Performance Bar. |
-
-Additionally, the following shortcuts are available when editing text in text fields,
-for example comments, replies, or issue and merge request descriptions:
-
-| Keyboard Shortcut | Description |
-| ---------------------------------------------------------------------- | ----------- |
-| <kbd>↑</kbd> | Edit your last comment. You must be in a blank text field below a thread, and you must already have at least one comment in the thread. |
-| <kbd>⌘</kbd> (Mac) / <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>p</kbd> | Toggle Markdown preview, when editing text in a text field that has **Write** and **Preview** tabs at the top. |
-
-## Project
-
-These shortcuts are available from any page within a project. You must type them
-relatively quickly to work, and they will take you to another page in the project.
-
-| Keyboard Shortcut | Description |
-| --------------------------- | ----------- |
-| <kbd>g</kbd> + <kbd>p</kbd> | Go to the project home page (**Project > Details**). |
-| <kbd>g</kbd> + <kbd>v</kbd> | Go to the project activity feed (**Project > Activity**). |
-| <kbd>g</kbd> + <kbd>r</kbd> | Go to the project releases list (**Project > Releases**). |
-| <kbd>g</kbd> + <kbd>f</kbd> | Go to the [project files](#project-files) list (**Repository > Files**). |
-| <kbd>t</kbd> | Go to the project file search page. (**Repository > Files**, click **Find Files**). |
-| <kbd>g</kbd> + <kbd>c</kbd> | Go to the project commits list (**Repository > Commits**). |
-| <kbd>g</kbd> + <kbd>n</kbd> | Go to the [repository graph](#repository-graph) page (**Repository > Graph**). |
-| <kbd>g</kbd> + <kbd>d</kbd> | Go to repository charts (**Repository > Charts**). |
-| <kbd>g</kbd> + <kbd>i</kbd> | Go to the project issues list (**Issues > List**). |
-| <kbd>i</kbd> | Go to the New Issue page (**Issues**, click **New Issue** ). |
-| <kbd>g</kbd> + <kbd>b</kbd> | Go to the project issue boards list (**Issues > Boards**). |
-| <kbd>g</kbd> + <kbd>m</kbd> | Go to the project merge requests list (**Merge Requests**). |
-| <kbd>g</kbd> + <kbd>j</kbd> | Go to the CI/CD jobs list (**CI/CD > Jobs**). |
-| <kbd>g</kbd> + <kbd>l</kbd> | Go to the project metrics (**Operations > Metrics**). |
-| <kbd>g</kbd> + <kbd>e</kbd> | Go to the project environments (**Operations > Environments**). |
-| <kbd>g</kbd> + <kbd>k</kbd> | Go to the project Kubernetes cluster integration page (**Operations > Kubernetes**). Note that you must have at least [`maintainer` permissions](../user/permissions.md) to access this page. |
-| <kbd>g</kbd> + <kbd>s</kbd> | Go to the project snippets list (**Snippets**). |
-| <kbd>g</kbd> + <kbd>w</kbd> | Go to the project wiki (**Wiki**), if enabled. |
-
-### Issues and Merge Requests
-
-These shortcuts are available when viewing issues and merge requests.
-
-| Keyboard Shortcut | Description |
-| ---------------------------- | ----------- |
-| <kbd>e</kbd> | Edit description. |
-| <kbd>a</kbd> | Change assignee. |
-| <kbd>m</kbd> | Change milestone. |
-| <kbd>l</kbd> | Change label. |
-| <kbd>r</kbd> | Start writing a comment. If any text is selected, it will be quoted in the comment. Can't be used to reply within a thread. |
-| <kbd>n</kbd> | Move to next unresolved discussion (Merge requests only). |
-| <kbd>p</kbd> | Move to previous unresolved discussion (Merge requests only). |
-| <kbd>]</kbd> or <kbd>j</kbd> | Move to next file (Merge requests only). |
-| <kbd>[</kbd> or <kbd>k</kbd> | Move to previous file (Merge requests only). |
-
-### Project Files
-
-These shortcuts are available when browsing the files in a project (navigate to
-**Repository** > **Files**):
-
-| Keyboard Shortcut | Description |
-| ----------------- | ----------- |
-| <kbd>↑</kbd> | Move selection up. |
-| <kbd>↓</kbd> | Move selection down. |
-| <kbd>enter</kbd> | Open selection. |
-| <kbd>esc</kbd> | Go back to file list screen (only while searching for files, **Repository > Files** then click on **Find File**). |
-| <kbd>y</kbd> | Go to file permalink (only while viewing a file). |
-
-### Web IDE
-
-These shortcuts are available when editing a file with the [Web IDE](../user/project/web_ide/index.md):
-
-| Keyboard Shortcut | Description |
-| ------------------------------------------------------- | ----------- |
-| <kbd>⌘</kbd> (Mac) / <kbd>Ctrl</kbd> + <kbd>p</kbd> | Search for, and then open another file for editing. |
-| <kbd>⌘</kbd> (Mac) / <kbd>Ctrl</kbd> + <kbd>Enter</kbd> | Commit (when editing the commit message). |
-
-### Repository Graph
-
-These shortcuts are available when viewing the project [repository graph](../user/project/repository/index.md#repository-graph)
-page (navigate to **Repository > Graph**):
-
-| Keyboard Shortcut | Description |
-| ------------------------------------------------------------------ | ----------- |
-| <kbd>←</kbd> or <kbd>h</kbd> | Scroll left. |
-| <kbd>→</kbd> or <kbd>l</kbd> | Scroll right. |
-| <kbd>↑</kbd> or <kbd>k</kbd> | Scroll up. |
-| <kbd>↓</kbd> or <kbd>j</kbd> | Scroll down. |
-| <kbd>Shift</kbd> + <kbd>↑</kbd> or <kbd>Shift</kbd> + <kbd>k</kbd> | Scroll to top. |
-| <kbd>Shift</kbd> + <kbd>↓</kbd> or <kbd>Shift</kbd> + <kbd>j</kbd> | Scroll to bottom. |
-
-### Wiki pages
-
-This shortcut is available when viewing a [wiki page](../user/project/wiki/index.md):
-
-| Keyboard Shortcut | Description |
-| ----------------- | ----------- |
-| <kbd>e</kbd> | Edit wiki page. |
-
-## Epics **(ULTIMATE)**
-
-These shortcuts are available when viewing [Epics](../user/group/epics/index.md):
-
-| Keyboard Shortcut | Description |
-| ----------------- | ----------- |
-| <kbd>r</kbd> | Start writing a comment. If any text is selected, it will be quoted in the comment. Can't be used to reply within a thread. |
-| <kbd>e</kbd> | Edit description. |
-| <kbd>l</kbd> | Change label. |
+This document was moved to [another location](../user/shortcuts.md).
diff --git a/doc/workflow/time_tracking.md b/doc/workflow/time_tracking.md
index 3d2e1de24da..e109410e22d 100644
--- a/doc/workflow/time_tracking.md
+++ b/doc/workflow/time_tracking.md
@@ -1,91 +1,5 @@
---
-type: reference
+redirect_to: '../user/project/time_tracking.md'
---
-# Time Tracking
-
-> Introduced in GitLab 8.14.
-
-Time Tracking allows you to track estimates and time spent on issues and merge
-requests within GitLab.
-
-## Overview
-
-Time Tracking allows you to:
-
-- Record the time spent working on an issue or a merge request.
-- Add an estimate of the amount of time needed to complete an issue or a merge
- request.
-
-You don't have to indicate an estimate to enter the time spent, and vice versa.
-
-Data about time tracking is shown on the issue/merge request sidebar, as shown
-below.
-
-![Time tracking in the sidebar](time_tracking/img/time_tracking_sidebar_v8_16.png)
-
-## How to enter data
-
-Time Tracking uses two [quick actions](../user/project/quick_actions.md)
-that GitLab introduced with this new feature: `/spend` and `/estimate`.
-
-Quick actions can be used in the body of an issue or a merge request, but also
-in a comment in both an issue or a merge request.
-
-Below is an example of how you can use those new quick actions inside a comment.
-
-![Time tracking example in a comment](time_tracking/img/time_tracking_example_v12_2.png)
-
-Adding time entries (time spent or estimates) is limited to project members.
-
-### Estimates
-
-To enter an estimate, write `/estimate`, followed by the time. For example, if
-you need to enter an estimate of 3 days, 5 hours and 10 minutes, you would write
-`/estimate 3d 5h 10m`. Time units that we support are listed at the bottom of
-this help page.
-
-Every time you enter a new time estimate, any previous time estimates will be
-overridden by this new value. There should only be one valid estimate in an
-issue or a merge request.
-
-To remove an estimation entirely, use `/remove_estimate`.
-
-### Time spent
-
-To enter a time spent, use `/spend 3d 5h 10m`.
-
-Every new time spent entry will be added to the current total time spent for the
-issue or the merge request.
-
-You can remove time by entering a negative amount: `/spend -3d` will remove 3
-days from the total time spent. You can't go below 0 minutes of time spent,
-so GitLab will automatically reset the time spent if you remove a larger amount
-of time compared to the time that was entered already.
-
-To remove all the time spent at once, use `/remove_time_spent`.
-
-## Configuration
-
-The following time units are available:
-
-- Months (mo)
-- Weeks (w)
-- Days (d)
-- Hours (h)
-- Minutes (m)
-
-Default conversion rates are 1mo = 4w, 1w = 5d and 1d = 8h.
-
-### Limit displayed units to hours **(CORE ONLY)**
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/29469/) in GitLab 12.1.
-
-In GitLab self-managed instances, the display of time units can be limited to
-hours through the option in **Admin Area > Settings > Preferences** under **Localization**.
-
-With this option enabled, `75h` is displayed instead of `1w 4d 3h`.
-
-## Other interesting links
-
-- [Time Tracking landing page in the GitLab handbook](https://about.gitlab.com/solutions/time-tracking/)
+This document was moved to [another location](../user/project/time_tracking.md).
diff --git a/doc/workflow/timezone.md b/doc/workflow/timezone.md
index 3594ba19181..f1a2e1af66a 100644
--- a/doc/workflow/timezone.md
+++ b/doc/workflow/timezone.md
@@ -1,37 +1,5 @@
-# Changing your time zone
+---
+redirect_to: '../administration/timezone.md'
+---
-The global time zone configuration parameter can be changed in `config/gitlab.yml`:
-
-```text
-# time_zone: 'UTC'
-```
-
-Uncomment and customize if you want to change the default time zone of the GitLab application.
-
-## Viewing available timezones
-
-To see all available time zones, run `bundle exec rake time:zones:all`.
-
-For Omnibus installations, run `gitlab-rake time:zones:all`.
-
-NOTE: **Note:**
-Currently, this rake task does not list timezones in TZInfo format required by GitLab Omnibus during a reconfigure: [#58672](https://gitlab.com/gitlab-org/gitlab-foss/issues/58672).
-
-## Changing time zone in Omnibus installations
-
-GitLab defaults its time zone to UTC. It has a global timezone configuration parameter in `/etc/gitlab/gitlab.rb`.
-
-To obtain a list of timezones, log in to your GitLab application server and run a command that generates a list of timezones in TZInfo format for the server. For example, install `timedatectl` and run `timedatectl list-timezones`.
-
-To update, add the timezone that best applies to your location. For example:
-
-```ruby
-gitlab_rails['time_zone'] = 'America/New_York'
-```
-
-After adding the configuration parameter, reconfigure and restart your GitLab instance:
-
-```sh
-gitlab-ctl reconfigure
-gitlab-ctl restart
-```
+This document was moved to [another location](../administration/timezone.md).
diff --git a/doc/workflow/todos.md b/doc/workflow/todos.md
index 5d576d8ff35..48c9a3faf1d 100644
--- a/doc/workflow/todos.md
+++ b/doc/workflow/todos.md
@@ -1,138 +1,5 @@
-# GitLab To-Do List
+---
+redirect_to: '../user/todos.md'
+---
-> [Introduced][ce-2817] in GitLab 8.5.
-
-When you log into GitLab, you normally want to see where you should spend your
-time, take some action, or know what you need to keep an eye on without
-a huge pile of e-mail notifications. GitLab is where you do your work,
-so being able to get started quickly is important.
-
-Your To-Do List offers a chronological list of items that are waiting for your input, all
-in a simple dashboard.
-
-![To Do screenshot showing a list of items to check on](img/todos_index.png)
-
-You can quickly access your To-Do List by clicking the checkmark icon next to the
-search bar in the top navigation. If the count is:
-
-- Less than 100, the number in blue is the number of To-Do items.
-- 100 or more, the number displays as 99+. The exact number displays
- on the To-Do List.
-you still have open. Otherwise, the number displays as 99+. The exact number
-displays on the To-Do List.
-
-![To Do icon](img/todos_icon.png)
-
-## What triggers a To Do
-
-A To Do displays on your To-Do List when:
-
-- An issue or merge request is assigned to you
-- You are `@mentioned` in the description or comment of an:
- - Issue
- - Merge Request
- - Epic **(ULTIMATE)**
-- You are `@mentioned` in a comment on a commit
-- A job in the CI pipeline running for your merge request failed, but this
- job is not allowed to fail
-- An open merge request becomes unmergeable due to conflict, and you are either:
- - The author
- - Have set it to automatically merge once the pipeline succeeds
-
-To-do triggers are not affected by [GitLab Notification Email settings](notifications.md).
-
-NOTE: **Note:**
-When a user no longer has access to a resource related to a To Do (like an issue, merge request, project, or group) the related To-Do items are deleted within the next hour for security reasons. The delete is delayed to prevent data loss, in case the user's access was revoked by mistake.
-
-### Directly addressing a To Do
-
-> [Introduced][ce-7926] in GitLab 9.0.
-
-If you are mentioned at the start of a line, the To Do you receive will be listed
-as 'directly addressed'. For example, in this comment:
-
-```markdown
-@alice What do you think? cc: @bob
-
-- @carol can you please have a look?
-
->>>
-@dan what do you think?
->>>
-
-@erin @frank thank you!
-```
-
-The people receiving directly addressed To-Do items are `@alice`, `@erin`, and
-`@frank`. Directly addressed To-Do items only differ from mentions in their type
-for filtering purposes; otherwise, they appear as normal.
-
-### Manually creating a To Do
-
-You can also add the following to your To-Do List by clicking the **Add a To Do** button on an:
-
-- Issue
-- Merge Request
-- Epic **(ULTIMATE)**
-
-![Adding a To Do from the issuable sidebar](img/todos_add_todo_sidebar.png)
-
-## Marking a To Do as done
-
-Any action to the following will mark the corresponding To Do as done:
-
-- Issue
-- Merge Request
-- Epic **(ULTIMATE)**
-
-Actions that dismiss To-Do items include:
-
-- Changing the assignee
-- Changing the milestone
-- Adding/removing a label
-- Commenting on the issue
-
-Your To-Do List is personal, and items are only marked as done if the action comes from
-you. If you close the issue or merge request, your To Do is automatically
-marked as done.
-
-To prevent other users from closing issues without you being notified, if someone else closes, merges, or takes action on the any of the following, your To Do will remain pending:
-
-- Issue
-- Merge request
-- Epic **(ULTIMATE)**
-
-There is just one To Do for each of these, so mentioning a user a hundred times in an issue will only trigger one To Do.
-
-If no action is needed, you can manually mark the To Do as done by clicking the
-corresponding **Done** button, and it will disappear from your To-Do List.
-
-![A To Do in the To-Do List](img/todo_list_item.png)
-
-You can also mark a To Do as done by clicking the **Mark as done** button in the sidebar of the following:
-
-- Issue
-- Merge Request
-- Epic **(ULTIMATE)**
-
-![Mark as done from the issuable sidebar](img/todos_mark_done_sidebar.png)
-
-You can mark all your To-Do items as done at once by clicking the **Mark all as
-done** button.
-
-## Filtering your To-Do List
-
-There are four kinds of filters you can use on your To-Do List.
-
-| Filter | Description |
-| ------- | ----------- |
-| Project | Filter by project |
-| Group | Filter by group |
-| Author | Filter by the author that triggered the To Do |
-| Type | Filter by issue, merge request, or epic **(ULTIMATE)** |
-| Action | Filter by the action that triggered the To Do |
-
-You can also filter by more than one of these at the same time. The possible Actions are `Any Action`, `Assigned`, `Mentioned`, `Added`, `Pipelines`, and `Directly Addressed`, [as described above](#what-triggers-a-to-do).
-
-[ce-2817]: https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/2817
-[ce-7926]: https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/7926
+This document was moved to [another location](../user/todos.md).
diff --git a/doc/workflow/workflow.md b/doc/workflow/workflow.md
index 7fac41c3b6f..c77d95cd326 100644
--- a/doc/workflow/workflow.md
+++ b/doc/workflow/workflow.md
@@ -1,31 +1,5 @@
-# Feature branch workflow
+---
+redirect_to: '../gitlab-basics/feature_branch_workflow.md'
+---
-1. Clone project:
-
- ```bash
- git clone git@example.com:project-name.git
- ```
-
-1. Create branch with your feature:
-
- ```bash
- git checkout -b $feature_name
- ```
-
-1. Write code. Commit changes:
-
- ```bash
- git commit -am "My feature is ready"
- ```
-
-1. Push your branch to GitLab:
-
- ```bash
- git push origin $feature_name
- ```
-
-1. Review your code on commits page.
-
-1. Create a merge request.
-
-1. Your team lead will review the code &amp; merge it to the main branch.
+This document was moved to [another location](../gitlab-basics/feature_branch_workflow.md).