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
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-04-09 18:09:10 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-04-09 18:09:10 +0300
commit9ea69b43c3502c4c63e6d47da40786875197fcf3 (patch)
tree34a74f05ff8321a9dc16bb22dd3d3fe6ef55d3e7
parent45c999c8bcab0cd8ea766919634580465e5080d9 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab-ci.yml5
-rw-r--r--.gitlab/ci/untamper-my-lockfile.yml26
-rw-r--r--.gitlab/merge_request_templates/Quarantine End to End Test.md12
-rw-r--r--.rubocop_manual_todo.yml16
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock12
-rw-r--r--app/assets/images/learn_gitlab/section_deploy.svg16
-rw-r--r--app/assets/images/learn_gitlab/section_plan.svg1
-rw-r--r--app/assets/images/learn_gitlab/section_workspace.svg1
-rw-r--r--app/assets/javascripts/issuable_show/components/issuable_body.vue5
-rw-r--r--app/assets/javascripts/issuable_show/components/issuable_edit_form.vue8
-rw-r--r--app/assets/javascripts/issuable_show/components/issuable_show_root.vue6
-rw-r--r--app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_a.vue64
-rw-r--r--app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_b.vue3
-rw-r--r--app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_card.vue52
-rw-r--r--app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue43
-rw-r--r--app/assets/javascripts/pages/projects/learn_gitlab/constants/index.js41
-rw-r--r--app/assets/stylesheets/application_dark.scss57
-rw-r--r--app/assets/stylesheets/framework/header.scss12
-rw-r--r--app/assets/stylesheets/framework/variables.scss2
-rw-r--r--app/assets/stylesheets/lazy_bundles/select2_overrides.scss56
-rw-r--r--app/assets/stylesheets/page_bundles/build.scss22
-rw-r--r--app/assets/stylesheets/page_bundles/learn_gitlab.scss8
-rw-r--r--app/assets/stylesheets/themes/theme_light.scss46
-rw-r--r--app/helpers/ci/pipeline_editor_helper.rb18
-rw-r--r--app/models/ci/pipeline.rb23
-rw-r--r--app/services/ci/abort_pipelines_service.rb17
-rw-r--r--app/views/admin/application_settings/_registry.html.haml4
-rw-r--r--app/views/devise/sessions/_new_ldap.html.haml6
-rw-r--r--app/views/profiles/chat_names/_chat_name.html.haml2
-rw-r--r--app/views/projects/ci/pipeline_editor/show.html.haml14
-rw-r--r--app/views/projects/triggers/_index.html.haml32
-rw-r--r--changelogs/unreleased/202423-remove-records-without-group-from-webhooks.yml5
-rw-r--r--changelogs/unreleased/324796-update-deprecated-glicon-size-and-remove-use-deprecated-sizes.yml5
-rw-r--r--changelogs/unreleased/Externalise-strings-in-_registry-html-haml.yml5
-rw-r--r--changelogs/unreleased/Externalise-strings-in-chat_names-_chat_name-html-haml.yml5
-rw-r--r--changelogs/unreleased/Externalize-strings-in-ssessions_new_ldap-html-haml.yml5
-rw-r--r--changelogs/unreleased/fix-commit-status-with-child-pipeline.yml5
-rw-r--r--changelogs/unreleased/fix-gb-avoid-inflating-memory-when-aborting-pipelines.yml5
-rw-r--r--changelogs/unreleased/id-bump-devise-two-factor.yml5
-rw-r--r--changelogs/unreleased/issue-325836-fix-empty-line-after-let-it-be-api-helpers.yml5
-rw-r--r--changelogs/unreleased/issue-325836-fix-empty-line-after-let-it-be-gitlab-github-import.yml5
-rw-r--r--changelogs/unreleased/issue-325836-fix-empty-line-after-let-it-be-gitlab-imoport-export.yml5
-rw-r--r--changelogs/unreleased/jonstonchan-fix-triggers-externalization.yml5
-rw-r--r--changelogs/unreleased/optimize-query-for-cherry-picked-merge-requests.yml5
-rw-r--r--changelogs/unreleased/psi-dark-build.yml5
-rw-r--r--changelogs/unreleased/psi-dark-navbar.yml5
-rw-r--r--changelogs/unreleased/psi-dark-select2.yml5
-rw-r--r--config/feature_flags/development/async_add_build_failure_todo.yml2
-rw-r--r--config/gitlab.yml.example2
-rw-r--r--config/initializers/smtp_settings.rb.sample2
-rw-r--r--config/metrics/counts_all/20210216180246_web_ide_merge_requests.yml2
-rw-r--r--config/redis.cache.yml.example4
-rw-r--r--config/redis.queues.yml.example4
-rw-r--r--config/redis.shared_state.yml.example4
-rw-r--r--config/resque.yml.example4
-rw-r--r--config/unicorn.rb.example4
-rw-r--r--db/migrate/20210409084242_create_index_on_notes_for_cherry_picked_merge_requests.rb18
-rw-r--r--db/post_migrate/20210330091751_remove_records_without_group_from_webhooks_table.rb30
-rw-r--r--db/schema_migrations/202103300917511
-rw-r--r--db/schema_migrations/202104090842421
-rw-r--r--db/structure.sql2
-rw-r--r--doc/api/jobs.md3
-rw-r--r--doc/ci/yaml/README.md33
-rw-r--r--doc/development/merge_request_performance_guidelines.md21
-rw-r--r--doc/development/usage_ping/dictionary.md2
-rw-r--r--doc/user/project/settings/import_export.md4
-rw-r--r--locale/gitlab.pot26
-rw-r--r--spec/frontend/issuable_show/mock_data.js1
-rw-r--r--spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_a_spec.js.snap360
-rw-r--r--spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_b_spec.js.snap4
-rw-r--r--spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_section_card_spec.js.snap63
-rw-r--r--spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_a_spec.js30
-rw-r--r--spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_section_card_spec.js26
-rw-r--r--spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_section_link_spec.js49
-rw-r--r--spec/helpers/ci/pipeline_editor_helper_spec.rb32
-rw-r--r--spec/helpers/projects/ci/pipeline_editor_helper_spec.rb31
-rw-r--r--spec/lib/api/helpers/caching_spec.rb1
-rw-r--r--spec/lib/api/helpers/packages_manager_clients_helpers_spec.rb3
-rw-r--r--spec/lib/gitlab/github_import/importer/pull_request_merged_by_importer_spec.rb1
-rw-r--r--spec/lib/gitlab/github_import/importer/pull_request_review_importer_spec.rb1
-rw-r--r--spec/lib/gitlab/github_import/milestone_finder_spec.rb1
-rw-r--r--spec/lib/gitlab/import_export/design_repo_saver_spec.rb1
-rw-r--r--spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb1
-rw-r--r--spec/lib/gitlab/import_export/project/export_task_spec.rb1
-rw-r--r--spec/lib/gitlab/import_export/project/tree_saver_spec.rb1
-rw-r--r--spec/lib/gitlab/import_export/repo_saver_spec.rb1
-rw-r--r--spec/lib/gitlab/import_export/snippet_repo_saver_spec.rb1
-rw-r--r--spec/lib/gitlab/import_export/snippets_repo_saver_spec.rb1
-rw-r--r--spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb1
-rw-r--r--spec/migrations/remove_records_without_group_from_webhooks_table_spec.rb27
-rw-r--r--spec/models/ci/pipeline_spec.rb29
-rw-r--r--spec/services/ci/abort_pipelines_service_spec.rb16
93 files changed, 1269 insertions, 295 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 54e444e6ec0..423a62b159b 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -113,4 +113,7 @@ include:
- local: .gitlab/ci/dast.gitlab-ci.yml
- local: .gitlab/ci/workhorse.gitlab-ci.yml
- local: .gitlab/ci/graphql.gitlab-ci.yml
- - remote: 'https://gitlab.com/gitlab-org/frontend/untamper-my-lockfile/-/raw/main/.gitlab-ci-template.yml'
+ # switch the remote include to a local include until this is resolved:
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/327299
+ # - remote: 'https://gitlab.com/gitlab-org/frontend/untamper-my-lockfile/-/raw/main/.gitlab-ci-template.yml'
+ - local: .gitlab/ci/untamper-my-lockfile.yml
diff --git a/.gitlab/ci/untamper-my-lockfile.yml b/.gitlab/ci/untamper-my-lockfile.yml
new file mode 100644
index 00000000000..54ba160f1bd
--- /dev/null
+++ b/.gitlab/ci/untamper-my-lockfile.yml
@@ -0,0 +1,26 @@
+untamper-my-lockfile:
+ image: registry.gitlab.com/gitlab-org/frontend/untamper-my-lockfile:main
+ stage: test
+ needs: []
+ before_script: []
+ after_script: []
+ cache: {}
+ retry: 1
+ script:
+ - untamper-my-lockfile --lockfile yarn.lock
+ rules:
+ # Create a pipeline if the branch is named 'add-untamper-my-lockfile' in
+ # order to have an integration check added in the MR that introduces it
+ - if: $CI_COMMIT_REF_NAME == "add-untamper-my-lockfile"
+ # Create a pipeline if there are changes in yarn.lock _and_ we are in a
+ # merge request _or_ branch pipeline.
+ #
+ # This ensures that the pipeline isn't run in scheduled jobs for example
+ #
+ # Also our best effort to support both branch and MR pipelines. In certain
+ # projects this might trigger _two_ pipelines. These projects can be fixed
+ # by adding proper workflow:rules
+ # https://docs.gitlab.com/ee/ci/yaml/#workflowrules
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event" || $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH
+ changes:
+ - yarn.lock
diff --git a/.gitlab/merge_request_templates/Quarantine End to End Test.md b/.gitlab/merge_request_templates/Quarantine End to End Test.md
index cf0a89284ae..5794a62df96 100644
--- a/.gitlab/merge_request_templates/Quarantine End to End Test.md
+++ b/.gitlab/merge_request_templates/Quarantine End to End Test.md
@@ -3,7 +3,7 @@
<!--
Please describe why the end-to-end test is being quarantined/ de-quarantined.
-Please note that the aim of quarantining a test is not to get back a green pipeline, but rather to reduce
+Please note that the aim of quarantining a test is not to get back a green pipeline, but rather to reduce
the noise (due to constantly failing tests, flaky tests, and so on) so that new failures are not missed.
-->
@@ -24,15 +24,15 @@ the noise (due to constantly failing tests, flaky tests, and so on) so that new
- [ ] Note if the test should be [quarantined for a specific environment](https://docs.gitlab.com/ee/development/testing_guide/end_to_end/environment_selection.html#quarantining-a-test-for-a-specific-environment).
- [ ] Dequarantine test check-list
- [ ] Follow the [Dequarantining Tests guide](https://about.gitlab.com/handbook/engineering/quality/guidelines/debugging-qa-test-failures/#dequarantining-tests).
- - [ ] Confirm the test consistently passes on the target GitLab environment(s).
- - [ ] (Optionally) [Trigger a manual GitLab-QA pipeline](https://about.gitlab.com/handbook/engineering/quality/guidelines/tips-and-tricks/#running-gitlab-qa-pipeline-against-a-specific-gitlab-release) against a specific GitLab environment using the `RELEASE` variable from the `package-and-qa` job of the current Merge Request.
-- [ ] To ensure a faster turnaround, ask in the `#quality` Slack channel for someone to review and merge the merge request, rather than assigning it directly.
+ - [ ] Confirm the test consistently passes on the target GitLab environment(s).
+ - [ ] (Optionally) [Trigger a manual GitLab-QA pipeline](https://about.gitlab.com/handbook/engineering/quality/guidelines/tips-and-tricks/#running-gitlab-qa-pipeline-against-a-specific-gitlab-release) against a specific GitLab environment using the `RELEASE` variable from the `package-and-qa` job of the current merge request.
+- [ ] To ensure a faster turnaround, ask in the `#quality` Slack channel for someone to review and merge the merge request, rather than assigning it directly.
<!-- Base labels. -->
-/label ~"Quality" ~"QA" ~"feature" ~"feature::maintenance"
+/label ~"Quality" ~"QA" ~"feature" ~"feature::maintenance"
<!-- Labels to pick into auto-deploy. -->
-/label ~"Pick into auto-deploy" ~"priority::1" ~"severity::1"
+/label ~"Pick into auto-deploy" ~"priority::1" ~"severity::1"
<!--
Choose the stage that appears in the test path, e.g. ~"devops::create" for
diff --git a/.rubocop_manual_todo.yml b/.rubocop_manual_todo.yml
index 99082386826..8091d4f2e52 100644
--- a/.rubocop_manual_todo.yml
+++ b/.rubocop_manual_todo.yml
@@ -455,9 +455,6 @@ RSpec/EmptyLineAfterFinalLetItBe:
- ee/spec/features/issues/bulk_assignment_epic_spec.rb
- ee/spec/features/issues/user_uses_quick_actions_spec.rb
- ee/spec/features/markdown/metrics_spec.rb
- - ee/spec/features/projects/issues/user_creates_issue_spec.rb
- - ee/spec/features/projects/iterations/iterations_list_spec.rb
- - ee/spec/features/projects/licenses/maintainer_views_policies_spec.rb
- ee/spec/features/registrations/group_invites_during_signup_flow_spec.rb
- ee/spec/features/subscriptions_spec.rb
- ee/spec/graphql/ee/mutations/concerns/mutations/resolves_issuable_spec.rb
@@ -763,8 +760,6 @@ RSpec/EmptyLineAfterFinalLetItBe:
- spec/lib/api/entities/design_management/design_spec.rb
- spec/lib/api/entities/merge_request_changes_spec.rb
- spec/lib/api/entities/release_spec.rb
- - spec/lib/api/helpers/caching_spec.rb
- - spec/lib/api/helpers/packages_manager_clients_helpers_spec.rb
- spec/lib/bulk_imports/groups/loaders/group_loader_spec.rb
- spec/lib/extracts_path_spec.rb
- spec/lib/extracts_ref_spec.rb
@@ -806,22 +801,11 @@ RSpec/EmptyLineAfterFinalLetItBe:
- spec/lib/gitlab/git_access_project_spec.rb
- spec/lib/gitlab/git_access_wiki_spec.rb
- spec/lib/gitlab/gitaly_client/operation_service_spec.rb
- - spec/lib/gitlab/github_import/importer/pull_request_merged_by_importer_spec.rb
- - spec/lib/gitlab/github_import/importer/pull_request_review_importer_spec.rb
- - spec/lib/gitlab/github_import/milestone_finder_spec.rb
- spec/lib/gitlab/gl_repository/repo_type_spec.rb
- spec/lib/gitlab/group_search_results_spec.rb
- spec/lib/gitlab/hook_data/issue_builder_spec.rb
- spec/lib/gitlab/hook_data/merge_request_builder_spec.rb
- spec/lib/gitlab/hook_data/release_builder_spec.rb
- - spec/lib/gitlab/import_export/design_repo_saver_spec.rb
- - spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb
- - spec/lib/gitlab/import_export/project/export_task_spec.rb
- - spec/lib/gitlab/import_export/project/tree_saver_spec.rb
- - spec/lib/gitlab/import_export/repo_saver_spec.rb
- - spec/lib/gitlab/import_export/snippet_repo_saver_spec.rb
- - spec/lib/gitlab/import_export/snippets_repo_saver_spec.rb
- - spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb
- spec/lib/gitlab/jira_import/base_importer_spec.rb
- spec/lib/gitlab/jira_import/handle_labels_service_spec.rb
- spec/lib/gitlab/jira_import_spec.rb
diff --git a/Gemfile b/Gemfile
index 0aeda5cb286..1ca67840692 100644
--- a/Gemfile
+++ b/Gemfile
@@ -59,7 +59,7 @@ gem 'akismet', '~> 3.0'
gem 'invisible_captcha', '~> 1.1.0'
# Two-factor authentication
-gem 'devise-two-factor', '~> 3.1.0'
+gem 'devise-two-factor', '~> 4.0.0'
gem 'rqrcode-rails3', '~> 0.1.7'
gem 'attr_encrypted', '~> 3.1.0'
gem 'u2f', '~> 0.2.1'
diff --git a/Gemfile.lock b/Gemfile.lock
index 682e8432b55..724412fa8ed 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -264,12 +264,12 @@ GEM
railties (>= 4.1.0)
responders
warden (~> 1.2.3)
- devise-two-factor (3.1.0)
- activesupport (< 6.1)
+ devise-two-factor (4.0.0)
+ activesupport (< 6.2)
attr_encrypted (>= 1.3, < 4, != 2)
devise (~> 4.0)
- railties (< 6.1)
- rotp (~> 2.0)
+ railties (< 6.2)
+ rotp (~> 6.0)
diff-lcs (1.4.4)
diff_match_patch (0.1.0)
diffy (3.3.0)
@@ -1044,7 +1044,7 @@ GEM
nokogiri
rexml (3.2.4)
rinku (2.0.0)
- rotp (2.1.2)
+ rotp (6.2.0)
rouge (3.26.0)
rqrcode (0.7.0)
chunky_png
@@ -1385,7 +1385,7 @@ DEPENDENCIES
derailed_benchmarks
device_detector
devise (~> 4.7.2)
- devise-two-factor (~> 3.1.0)
+ devise-two-factor (~> 4.0.0)
diff_match_patch (~> 0.1.0)
diffy (~> 3.3)
discordrb-webhooks (~> 3.4)
diff --git a/app/assets/images/learn_gitlab/section_deploy.svg b/app/assets/images/learn_gitlab/section_deploy.svg
new file mode 100644
index 00000000000..187956a66db
--- /dev/null
+++ b/app/assets/images/learn_gitlab/section_deploy.svg
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="35px" height="34px" viewBox="0 0 35 34" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <!-- Generator: Sketch 64 (93537) - https://sketch.com -->
+ <title>Group</title>
+ <desc>Created with Sketch.</desc>
+ <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+ <g id="Artboard" transform="translate(-463.000000, -393.000000)">
+ <g id="Group" transform="translate(463.000000, 393.000000)">
+ <path d="M19.3557,25.2338 C17.7369,25.9233 16.1619,26.1062 14.5861,25.6013 C13.996,26.033 13.2711,26.2395 12.5422,26.1834 C11.8132,26.1273 11.1284,25.8124 10.6114,25.2955 L8.75506,23.4392 C8.19927,22.8833 7.87849,22.1351 7.8591,21.3493 C7.83972,20.5635 8.12323,19.8003 8.65094,19.2177 C8.34425,17.8947 8.46763,16.5564 8.93356,15.1901 L6.183,14.1287 C5.81926,13.9884 5.49427,13.7633 5.23503,13.472 C4.9758,13.1808 4.7898,12.832 4.69251,12.4544 C4.59521,12.0769 4.58942,11.6816 4.67562,11.3013 C4.76182,10.9211 4.93753,10.5669 5.18813,10.2682 L8.79006,5.9759 C9.11841,5.5846 9.56087,5.3057 10.0555,5.1782 C10.5502,5.0508 11.0724,5.0811 11.5489,5.265 L15.0686,6.6234 C15.4064,6.2747 15.7529,5.9234 16.1073,5.5691 C19.6177,2.05856 24.1782,0.20312 29.7892,0.00275 C29.9524,-0.00304 30.1159,0.00032 30.2787,0.01281 C32.6881,0.19656 34.4919,2.29918 34.3077,4.7085 C33.8986,10.0569 31.957,14.4687 28.4824,17.9429 C28.2408,18.1846 27.9986,18.4257 27.7557,18.6661 L29.1763,22.3463 C29.3602,22.8229 29.3905,23.345 29.263,23.8397 C29.1355,24.3344 28.8566,24.7768 28.4653,25.1052 L24.1734,28.7071 C23.8748,28.9578 23.5206,29.1336 23.1403,29.2198 C22.76,29.3061 22.3646,29.3003 21.987,29.203 C21.6094,29.1057 21.2605,28.9197 20.9692,28.6604 C20.678,28.4011 20.4528,28.0761 20.3125,27.7122 L19.3557,25.2338 Z M9.32819,13.455 L13.8808,8.0291 L10.8962,6.8772 C10.7601,6.8247 10.611,6.816 10.4697,6.8524 C10.3284,6.8888 10.2021,6.9685 10.1082,7.0802 L6.50631,11.3725 C6.43473,11.4578 6.38455,11.559 6.35993,11.6677 C6.33532,11.7763 6.33699,11.8893 6.3648,11.9971 C6.39261,12.105 6.44576,12.2046 6.51983,12.2878 C6.59391,12.371 6.68676,12.4353 6.79069,12.4754 L9.32819,13.455 Z M20.9858,24.5675 L21.9654,27.105 C22.0055,27.2089 22.0699,27.3017 22.1531,27.3757 C22.2363,27.4498 22.336,27.5029 22.4438,27.5306 C22.5517,27.5584 22.6646,27.56 22.7732,27.5354 C22.8818,27.5107 22.983,27.4605 23.0683,27.3889 L27.3602,23.7874 C27.4721,23.6936 27.5518,23.5672 27.5883,23.4259 C27.6248,23.2845 27.6162,23.1353 27.5636,22.9991 L26.4117,20.0144 L20.9858,24.5675 Z M12.3714,22.1057 C16.2,25.9347 19.3999,24.55 27.2442,16.7056 C30.4161,13.5337 32.1845,9.5162 32.5621,4.5751 C32.5903,4.2067 32.5404,3.83648 32.4156,3.4887 C32.2909,3.14091 32.0942,2.82338 31.8383,2.55685 C31.5825,2.29033 31.2732,2.08082 30.9308,1.94203 C30.5884,1.80323 30.2205,1.73829 29.8513,1.75143 C24.6687,1.9365 20.5312,3.62 17.3449,6.8063 C9.89431,14.2569 8.41381,18.1481 12.3714,22.1057 Z" id="Shape" fill="#6E49CB"></path>
+ <path d="M22.9861,11.6834 C23.148,11.8489 23.341,11.9806 23.5541,12.071 C23.7672,12.1613 23.9962,12.2085 24.2276,12.2098236 C24.4591,12.211 24.6885,12.1664 24.9026,12.0784 C25.1166,11.9904 25.3111,11.8608 25.4748,11.6971 C25.6384,11.5334 25.768,11.3389 25.856,11.1248 C25.9439,10.9107 25.9885,10.6813 25.9872276,10.4499 C25.9859,10.2184 25.9387,9.9895 25.8483,9.7764 C25.7579,9.5633 25.6262,9.3703 25.4606,9.2085 C25.1325,8.8803 24.6873,8.6959 24.2232,8.6959 C23.759,8.6959 23.3139,8.8803 22.9857,9.2085 C22.6575,9.5367 22.4731,9.9818 22.4731,10.446 C22.4731,10.9101 22.6575,11.3552 22.9857,11.6834 L22.9861,11.6834 Z M21.748,12.9211 C21.423,12.5961 21.1651,12.2102 20.9892,11.7855 C20.8133,11.3608 20.7228,10.9056 20.7228,10.446 C20.7228,9.9863 20.8133,9.5311 20.9892,9.1064 C21.1651,8.6817 21.423,8.2958 21.748,7.9708 C22.0731,7.6458 22.4589,7.3879 22.8836,7.212 C23.3083,7.0361 23.7635,6.9456 24.2232,6.9456 C24.6829,6.9456 25.138,7.0361 25.5627,7.212 C25.9874,7.3879 26.3733,7.6458 26.6983,7.9708 C27.3482,8.6285 27.7113,9.5166 27.708615,10.4412 C27.7058,11.3658 27.3373,12.2517 26.6836,12.9055 C26.0298,13.5593 25.1439,13.9278 24.2194,13.9307161 C23.2948,13.9335 22.4067,13.5704 21.7489,12.9207 L21.748,12.9211 Z" id="Shape" fill="#C2B7E6" fill-rule="nonzero"></path>
+ <path d="M6.58996,23.1303 C6.754,23.2943 6.84615,23.5169 6.84615,23.7489 C6.84615,23.9809 6.754,24.2034 6.58996,24.3675 L1.64009,29.3165 C1.5594,29.4001 1.46287,29.4668 1.35614,29.5127 C1.2494,29.5586 1.13459,29.5828 1.01841,29.5838391 C0.902228,29.5849 0.787001,29.5628 0.679451,29.5188 C0.571902,29.4749 0.474183,29.4099 0.391998,29.3278 C0.309813,29.2457 0.244808,29.148 0.200774,29.0405 C0.15674,28.933 0.13456,28.8177 0.135497628,28.7016 C0.136497,28.5854 0.160594,28.4706 0.206414,28.3638 C0.252233,28.257 0.318858,28.1604 0.4024,28.0797 L5.35228,23.1298 C5.43353,23.0485 5.53001,22.984 5.63619,22.9401 C5.74237,22.8961 5.85618,22.8734 5.97112,22.8734 C6.08606,22.8734 6.19987,22.8961 6.30605,22.9401 C6.41223,22.984 6.50871,23.0485 6.58996,23.1298 L6.58996,23.1303 Z M10.9208,27.4611 C11.0848,27.6252 11.177,27.8477 11.177,28.0797 C11.177,28.3117 11.0848,28.5342 10.9208,28.6983 L7.20859,32.4105 C7.12735,32.4918 7.0309,32.5562 6.92474,32.6002 C6.81859,32.6442 6.70481,32.6669 6.5899,32.6669 C6.47499,32.6669 6.3612,32.6443 6.25503,32.6004 C6.14886,32.5564 6.05239,32.492 5.97112,32.4107 C5.88985,32.3295 5.82538,32.233 5.78139,32.1269 C5.7374,32.0207 5.71471999,31.9069 5.71471999,31.792 C5.71471999,31.6771 5.73731,31.5633 5.78127,31.4572 C5.82522,31.351 5.88966,31.2545 5.9709,31.1733 L9.68353,27.4611 C9.84761,27.297 10.0701,27.2049 10.3022,27.2049 C10.5342,27.2049 10.7567,27.297 10.9208,27.4611 L10.9208,27.4611 Z" id="Shape" fill="#E0DBF2"></path>
+ <path d="M8.75534,25.2954 C8.91937,25.4595 9.01152,25.682 9.01152,25.914 C9.01152,26.1461 8.91937,26.3686 8.75534,26.5327 L1.94959,33.3389 C1.78546,33.503 1.56286,33.5952 1.33074,33.5952 C1.09863,33.5952 0.876027,33.503 0.7119,33.3389 C0.547772,33.1747 0.455566,32.9521 0.455566,32.72 C0.455566,32.4879 0.547772,32.2653 0.7119,32.1012 L7.51809,25.2959 C7.68217,25.1318 7.90469,25.0397 8.13671,25.0397 C8.36873,25.0397 8.59125,25.1318 8.75534,25.2959 L8.75534,25.2954 Z" id="Path" fill="#C2B7E6"></path>
+ </g>
+ </g>
+ </g>
+</svg> \ No newline at end of file
diff --git a/app/assets/images/learn_gitlab/section_plan.svg b/app/assets/images/learn_gitlab/section_plan.svg
new file mode 100644
index 00000000000..2348e837e5f
--- /dev/null
+++ b/app/assets/images/learn_gitlab/section_plan.svg
@@ -0,0 +1 @@
+<svg width="40" height="40" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M3.343 6c.82 0 1.516.145 1.968.34.198.085.315.165.375.218v31.441a1.45 1.45 0 01-.375.218c-.452.195-1.148.34-1.968.34-.82 0-1.516-.145-1.968-.34A1.45 1.45 0 011 37.999V6.558c.06-.053.177-.133.375-.218C1.827 6.145 2.523 6 3.343 6z" fill="#EFEDF8" stroke="#6E49CB" stroke-width="2"/><path fill-rule="evenodd" clip-rule="evenodd" d="M6.686 6.41l21.724 6.692c2.085.642 2.122 1.774.095 2.523L6.686 23.69V6.412z" fill="#6E49CB"/></svg> \ No newline at end of file
diff --git a/app/assets/images/learn_gitlab/section_workspace.svg b/app/assets/images/learn_gitlab/section_workspace.svg
new file mode 100644
index 00000000000..5cb7fd36ddd
--- /dev/null
+++ b/app/assets/images/learn_gitlab/section_workspace.svg
@@ -0,0 +1 @@
+<svg width="40" height="40" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M14.544 6.44C14.816 5.58 15.581 5 16.442 5h1.116c.861 0 1.626.58 1.898 1.44l1.05 3.32c.744.238 1.456.55 2.13.93l2.974-1.566c.77-.405 1.7-.247 2.309.394l.79.832c.608.64.76 1.62.374 2.43l-1.486 3.131c.359.71.656 1.46.882 2.243l3.153 1.106c.817.287 1.368 1.091 1.368 1.998v1.176c0 .906-.55 1.71-1.368 1.998l-3.153 1.106a12.936 12.936 0 01-.882 2.242l1.486 3.131c.385.81.234 1.79-.374 2.43l-.79.832c-.609.641-1.539.8-2.309.395l-2.973-1.566c-.675.379-1.387.692-2.13.93l-1.051 3.32c-.272.86-1.037 1.44-1.898 1.44h-1.116c-.861 0-1.626-.58-1.898-1.44l-1.05-3.32a11.604 11.604 0 01-2.13-.93L8.39 34.569c-.77.406-1.7.247-2.309-.395l-.79-.831a2.189 2.189 0 01-.374-2.43l1.487-3.131c-.36-.71-.657-1.46-.883-2.243l-3.153-1.106C1.55 24.145 1 23.34 1 22.434v-1.176c0-.906.55-1.711 1.368-1.998l3.153-1.106c.226-.783.523-1.533.883-2.243l-1.487-3.13a2.19 2.19 0 01.374-2.431l.79-.832c.609-.64 1.539-.8 2.309-.394l2.973 1.565a11.599 11.599 0 012.13-.93l1.051-3.32zM17 30.269c4.418 0 8-3.771 8-8.423s-3.582-8.423-8-8.423-8 3.771-8 8.423 3.582 8.423 8 8.423z" fill="#EFEDF8" stroke="#6E49CB" stroke-width="2"/><path d="M17 27.11c2.762 0 5-2.357 5-5.264 0-2.908-2.238-5.265-5-5.265-2.76 0-5 2.357-5 5.265 0 2.907 2.24 5.264 5 5.264z" stroke="#6E49CB" stroke-linecap="round"/></svg> \ No newline at end of file
diff --git a/app/assets/javascripts/issuable_show/components/issuable_body.vue b/app/assets/javascripts/issuable_show/components/issuable_body.vue
index fe102e942c9..05dc1650379 100644
--- a/app/assets/javascripts/issuable_show/components/issuable_body.vue
+++ b/app/assets/javascripts/issuable_show/components/issuable_body.vue
@@ -42,6 +42,10 @@ export default {
type: Boolean,
required: true,
},
+ enableZenMode: {
+ type: Boolean,
+ required: true,
+ },
enableTaskList: {
type: Boolean,
required: false,
@@ -144,6 +148,7 @@ export default {
:issuable="issuable"
:enable-autocomplete="enableAutocomplete"
:enable-autosave="enableAutosave"
+ :enable-zen-mode="enableZenMode"
:show-field-title="showFieldTitle"
:description-preview-path="descriptionPreviewPath"
:description-help-path="descriptionHelpPath"
diff --git a/app/assets/javascripts/issuable_show/components/issuable_edit_form.vue b/app/assets/javascripts/issuable_show/components/issuable_edit_form.vue
index 6d139541524..33dca3e9332 100644
--- a/app/assets/javascripts/issuable_show/components/issuable_edit_form.vue
+++ b/app/assets/javascripts/issuable_show/components/issuable_edit_form.vue
@@ -4,6 +4,7 @@ import $ from 'jquery';
import Autosave from '~/autosave';
import MarkdownField from '~/vue_shared/components/markdown/field.vue';
+import ZenMode from '~/zen_mode';
import eventHub from '../event_hub';
@@ -27,6 +28,10 @@ export default {
type: Boolean,
required: true,
},
+ enableZenMode: {
+ type: Boolean,
+ required: true,
+ },
showFieldTitle: {
type: Boolean,
required: true,
@@ -62,6 +67,9 @@ export default {
},
mounted() {
if (this.enableAutosave) this.initAutosave();
+
+ // eslint-disable-next-line no-new
+ if (this.enableZenMode) new ZenMode();
},
beforeDestroy() {
eventHub.$off('update.issuable', this.resetAutosave);
diff --git a/app/assets/javascripts/issuable_show/components/issuable_show_root.vue b/app/assets/javascripts/issuable_show/components/issuable_show_root.vue
index b514a6b01d8..ca057094868 100644
--- a/app/assets/javascripts/issuable_show/components/issuable_show_root.vue
+++ b/app/assets/javascripts/issuable_show/components/issuable_show_root.vue
@@ -42,6 +42,11 @@ export default {
required: false,
default: true,
},
+ enableZenMode: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
enableTaskList: {
type: Boolean,
required: false,
@@ -120,6 +125,7 @@ export default {
:enable-edit="enableEdit"
:enable-autocomplete="enableAutocomplete"
:enable-autosave="enableAutosave"
+ :enable-zen-mode="enableZenMode"
:enable-task-list="enableTaskList"
:edit-form-visible="editFormVisible"
:show-field-title="showFieldTitle"
diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_a.vue b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_a.vue
index 32ca623ca45..ef9e13f7ccf 100644
--- a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_a.vue
+++ b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_a.vue
@@ -1,11 +1,17 @@
<script>
-import { GlLink } from '@gitlab/ui';
-import { ACTION_LABELS } from '../constants';
+import { GlProgressBar, GlSprintf } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import { ACTION_LABELS, ACTION_SECTIONS } from '../constants';
+import LearnGitlabSectionCard from './learn_gitlab_section_card.vue';
export default {
- components: { GlLink },
+ components: { GlProgressBar, GlSprintf, LearnGitlabSectionCard },
i18n: {
- ACTION_LABELS,
+ title: s__('LearnGitLab|Learn GitLab'),
+ description: s__(
+ 'LearnGitLab|Ready to get started with GitLab? Follow these steps to set up your workspace, plan and commit changes, and deploy your project.',
+ ),
+ percentageCompleted: s__(`LearnGitLab|%{percentage}%{percentSymbol} completed`),
},
props: {
actions: {
@@ -13,15 +19,49 @@ export default {
type: Object,
},
},
+ maxValue: Object.keys(ACTION_LABELS).length,
+ sections: Object.keys(ACTION_SECTIONS),
+ computed: {
+ progressValue() {
+ return Object.values(this.actions).filter((a) => a.completed).length;
+ },
+ progressPercentage() {
+ return Math.round((this.progressValue / this.$options.maxValue) * 100);
+ },
+ },
+ methods: {
+ actionsFor(section) {
+ const actions = Object.fromEntries(
+ Object.entries(this.actions).filter(
+ ([action]) => ACTION_LABELS[action].section === section,
+ ),
+ );
+ return actions;
+ },
+ },
};
</script>
<template>
- <ul>
- <li v-for="(value, action) in actions" :key="action">
- <span v-if="value.completed">{{ $options.i18n.ACTION_LABELS[action].title }}</span>
- <span v-else>
- <gl-link :href="value.url">{{ $options.i18n.ACTION_LABELS[action].title }}</gl-link>
- </span>
- </li>
- </ul>
+ <div>
+ <div class="row">
+ <div class="gl-mb-7 gl-ml-5">
+ <h1 class="gl-font-size-h1">{{ $options.i18n.title }}</h1>
+ <p class="gl-text-gray-700 gl-mb-0">{{ $options.i18n.description }}</p>
+ </div>
+ </div>
+ <div class="gl-mb-3">
+ <p class="gl-text-gray-500 gl-mb-2" data-testid="completion-percentage">
+ <gl-sprintf :message="$options.i18n.percentageCompleted">
+ <template #percentage>{{ progressPercentage }}</template>
+ <template #percentSymbol>%</template>
+ </gl-sprintf>
+ </p>
+ <gl-progress-bar :value="progressValue" :max="$options.maxValue" />
+ </div>
+ <div class="row row-cols-1 row-cols-md-3 gl-mt-5">
+ <div v-for="section in $options.sections" :key="section" class="col gl-mb-6">
+ <learn-gitlab-section-card :section="section" :actions="actionsFor(section)" />
+ </div>
+ </div>
+ </div>
</template>
diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_b.vue b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_b.vue
index 230054ff76e..33248082bcd 100644
--- a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_b.vue
+++ b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_b.vue
@@ -1,5 +1,6 @@
<script>
import { GlProgressBar, GlSprintf } from '@gitlab/ui';
+import { pick } from 'lodash';
import { s__ } from '~/locale';
import { ACTION_LABELS } from '../constants';
import LearnGitlabInfoCard from './learn_gitlab_info_card.vue';
@@ -42,7 +43,7 @@ export default {
infoProps(action) {
return {
...this.actions[action],
- ...ACTION_LABELS[action],
+ ...pick(ACTION_LABELS[action], ['title', 'actionLabel', 'description', 'trialRequired']),
};
},
progressValue() {
diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_card.vue b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_card.vue
new file mode 100644
index 00000000000..db694a66afd
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_card.vue
@@ -0,0 +1,52 @@
+<script>
+import { GlCard } from '@gitlab/ui';
+import { imagePath } from '~/lib/utils/common_utils';
+import { ACTION_LABELS, ACTION_SECTIONS } from '../constants';
+
+import LearnGitlabSectionLink from './learn_gitlab_section_link.vue';
+
+export default {
+ name: 'LearnGitlabSectionCard',
+ components: { GlCard, LearnGitlabSectionLink },
+ i18n: {
+ ...ACTION_SECTIONS,
+ },
+ props: {
+ section: {
+ required: true,
+ type: String,
+ },
+ actions: {
+ required: true,
+ type: Object,
+ },
+ },
+ computed: {
+ sortedActions() {
+ return Object.entries(this.actions).sort(
+ (a1, a2) => ACTION_LABELS[a1[0]].position - ACTION_LABELS[a2[0]].position,
+ );
+ },
+ },
+ methods: {
+ svg(section) {
+ return imagePath(`learn_gitlab/section_${section}.svg`);
+ },
+ },
+};
+</script>
+<template>
+ <gl-card class="gl-pt-0 learn-gitlab-section-card">
+ <div class="learn-gitlab-section-card-header">
+ <img :src="svg(section)" />
+ <h2 class="gl-font-lg gl-mb-3">{{ $options.i18n[section].title }}</h2>
+ <p class="gl-text-gray-700 gl-mb-6">{{ $options.i18n[section].description }}</p>
+ </div>
+ <learn-gitlab-section-link
+ v-for="[action, value] in sortedActions"
+ :key="action"
+ :action="action"
+ :value="value"
+ />
+ </gl-card>
+</template>
diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue
new file mode 100644
index 00000000000..6f51c7372fd
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue
@@ -0,0 +1,43 @@
+<script>
+import { GlLink, GlIcon } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import { ACTION_LABELS } from '../constants';
+
+export default {
+ name: 'LearnGitlabSectionLink',
+ components: { GlLink, GlIcon },
+ i18n: {
+ ACTION_LABELS,
+ trialOnly: s__('LearnGitlab|Trial only'),
+ },
+ props: {
+ action: {
+ required: true,
+ type: String,
+ },
+ value: {
+ required: true,
+ type: Object,
+ },
+ },
+ computed: {
+ trialOnly() {
+ return ACTION_LABELS[this.action].trialRequired;
+ },
+ },
+};
+</script>
+<template>
+ <div class="gl-mb-4">
+ <span v-if="value.completed" class="gl-text-green-500">
+ <gl-icon name="check-circle-filled" :size="16" data-testid="completed-icon" />
+ {{ $options.i18n.ACTION_LABELS[action].title }}
+ </span>
+ <span v-else>
+ <gl-link :href="value.url">{{ $options.i18n.ACTION_LABELS[action].title }}</gl-link>
+ </span>
+ <span v-if="trialOnly" class="gl-font-style-italic gl-text-gray-500" data-testid="trial-only">
+ - {{ $options.i18n.trialOnly }}
+ </span>
+ </div>
+</template>
diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/constants/index.js b/app/assets/javascripts/pages/projects/learn_gitlab/constants/index.js
index 80f04b0cf44..ba456131327 100644
--- a/app/assets/javascripts/pages/projects/learn_gitlab/constants/index.js
+++ b/app/assets/javascripts/pages/projects/learn_gitlab/constants/index.js
@@ -5,6 +5,8 @@ export const ACTION_LABELS = {
title: s__('LearnGitLab|Create or import a repository'),
actionLabel: s__('LearnGitLab|Create or import a repository'),
description: s__('LearnGitLab|Create or import your first repository into your new project.'),
+ section: 'workspace',
+ position: 1,
},
userAdded: {
title: s__('LearnGitLab|Invite your colleagues'),
@@ -12,16 +14,22 @@ export const ACTION_LABELS = {
description: s__(
'LearnGitLab|GitLab works best as a team. Invite your colleague to enjoy all features.',
),
+ section: 'workspace',
+ position: 0,
},
pipelineCreated: {
title: s__('LearnGitLab|Set up CI/CD'),
actionLabel: s__('LearnGitLab|Set-up CI/CD'),
description: s__('LearnGitLab|Save time by automating your integration and deployment tasks.'),
+ section: 'workspace',
+ position: 2,
},
trialStarted: {
title: s__('LearnGitLab|Start a free Ultimate trial'),
actionLabel: s__('LearnGitLab|Try GitLab Ultimate for free'),
description: s__('LearnGitLab|Try all GitLab features for 30 days, no credit card required.'),
+ section: 'workspace',
+ position: 3,
},
codeOwnersEnabled: {
title: s__('LearnGitLab|Add code owners'),
@@ -30,21 +38,50 @@ export const ACTION_LABELS = {
'LearnGitLab|Prevent unexpected changes to important assets by assigning ownership of files and paths.',
),
trialRequired: true,
+ section: 'workspace',
+ position: 4,
},
requiredMrApprovalsEnabled: {
title: s__('LearnGitLab|Add merge request approval'),
actionLabel: s__('LearnGitLab|Enable require merge approvals'),
description: s__('LearnGitLab|Route code reviews to the right reviewers, every time.'),
trialRequired: true,
+ section: 'workspace',
+ position: 5,
},
mergeRequestCreated: {
title: s__('LearnGitLab|Submit a merge request'),
actionLabel: s__('LearnGitLab|Submit a merge request (MR)'),
description: s__('LearnGitLab|Review and edit proposed changes to source code.'),
+ section: 'plan',
+ position: 1,
},
securityScanEnabled: {
- title: s__('LearnGitLab|Run a security scan'),
- actionLabel: s__('LearnGitLab|Run a Security scan'),
+ title: s__('LearnGitLab|Run a Security scan using CI/CD'),
+ actionLabel: s__('LearnGitLab|Run a Security scan using CI/CD'),
description: s__('LearnGitLab|Scan your code to uncover vulnerabilities before deploying.'),
+ section: 'deploy',
+ position: 1,
+ },
+};
+
+export const ACTION_SECTIONS = {
+ workspace: {
+ title: s__('LearnGitLab|Set up your workspace'),
+ description: s__(
+ "LearnGitLab|Complete these tasks first so you can enjoy GitLab's features to their fullest:",
+ ),
+ },
+ plan: {
+ title: s__('LearnGitLab|Plan and execute'),
+ description: s__(
+ 'LearnGitLab|Create a workflow for your new workspace, and learn how GitLab features work together:',
+ ),
+ },
+ deploy: {
+ title: s__('LearnGitLab|Deploy'),
+ description: s__(
+ 'LearnGitLab|Use your new GitLab workflow to deploy your application, monitor its health, and keep it secure:',
+ ),
},
};
diff --git a/app/assets/stylesheets/application_dark.scss b/app/assets/stylesheets/application_dark.scss
index e55141e15df..90aab7ce342 100644
--- a/app/assets/stylesheets/application_dark.scss
+++ b/app/assets/stylesheets/application_dark.scss
@@ -1,3 +1,60 @@
@import './themes/dark';
@import './application';
+
+@import './themes/theme_helper';
+
+body.gl-dark {
+ @include gitlab-theme(
+ $gray-900,
+ $gray-400,
+ $gray-500,
+ $gray-800,
+ $gray-900,
+ $white
+ );
+
+ .logo-text svg {
+ fill: var(--gl-text-color);
+ }
+
+ .navbar-gitlab {
+ background-color: var(--gray-50);
+ box-shadow: 0 1px 0 0 var(--gray-100);
+
+ .navbar-sub-nav,
+ .navbar-nav {
+ li {
+ > a:hover,
+ > a:focus,
+ > button:hover,
+ > button:focus {
+ color: var(--gl-text-color);
+ background-color: var(--gray-200);
+ }
+ }
+
+ li.active,
+ li.dropdown.show {
+ > a,
+ > button {
+ color: var(--gl-text-color);
+ background-color: var(--gray-200);
+ }
+ }
+ }
+
+ .search {
+ form {
+ background-color: var(--gray-100);
+ box-shadow: inset 0 0 0 1px var(--border-color);
+
+ &:active,
+ &:hover {
+ background-color: var(--gray-100);
+ box-shadow: inset 0 0 0 1px var(--blue-200);
+ }
+ }
+ }
+ }
+}
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index fdb56a128c7..432be7d0b3f 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -442,22 +442,22 @@
font-weight: $gl-font-weight-normal;
margin-left: -6px;
font-size: 11px;
- color: $white;
+ color: var(--gray-950, $white);
padding: 0 5px;
line-height: 12px;
border-radius: 7px;
box-shadow: 0 1px 0 rgba($gl-header-color, 0.2);
&.green-badge {
- background-color: $green-400;
+ background-color: var(--green-400, $green-400);
}
&.merge-requests-count {
- background-color: $orange-400;
+ background-color: var(--orange-400, $orange-400);
}
&.todos-count {
- background-color: $blue-400;
+ background-color: var(--blue-400, $blue-400);
}
}
@@ -511,7 +511,7 @@
.header-user {
&.show .dropdown-menu {
margin-top: 4px;
- color: $gl-text-color;
+ color: var(--gl-text-color, $gl-text-color);
left: auto;
max-height: $dropdown-max-height-lg;
@@ -580,7 +580,7 @@
.no-emoji-placeholder,
.clear-user-status {
svg {
- fill: $gl-text-color-secondary;
+ fill: var(--gray-500, $gray-500);
}
}
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index ce747464ec6..4db1a75a21b 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -590,7 +590,7 @@ $gl-btn-xs-line-height: 13px;
/*
* Badges
*/
-$badge-bg: rgba(0, 0, 0, 0.07);
+$badge-bg: rgba($black, 0.07);
/*
* Pagination
diff --git a/app/assets/stylesheets/lazy_bundles/select2_overrides.scss b/app/assets/stylesheets/lazy_bundles/select2_overrides.scss
index 0d40159f6de..272f94176d0 100644
--- a/app/assets/stylesheets/lazy_bundles/select2_overrides.scss
+++ b/app/assets/stylesheets/lazy_bundles/select2_overrides.scss
@@ -12,9 +12,9 @@
.select2-container,
.select2-container.select2-drop-above {
.select2-choice {
- background: $white;
- color: $gl-text-color;
- border-color: $border-color;
+ background: var(--white, $white);
+ color: var(--gl-text-color, $gl-text-color);
+ border-color: var(--border-color, $border-color);
height: 34px;
padding: $gl-vert-padding $gl-input-padding;
font-size: $gl-font-size;
@@ -27,6 +27,10 @@
/* stylelint-disable-next-line function-url-quotes */
background: url(asset_path('chevron-down.png')) no-repeat 2px 8px;
+ .gl-dark & {
+ filter: invert(0.9);
+ }
+
b {
display: none;
}
@@ -37,8 +41,8 @@
}
&:hover {
- border-color: $gray-darkest;
- color: $gl-text-color;
+ border-color: var(--gray-200, $gray-200);
+ color: var(--gl-text-color, $gl-text-color);
}
}
@@ -49,8 +53,8 @@
// .select2-focusser element instead.
&.select2-container-active:not(.select2-dropdown-open) {
.select2-choice {
- color: $input-focus-color;
- background-color: $input-focus-bg;
+ color: var(--gray-700, $gray-700);
+ background-color: var(--white, $white);
border-color: $input-focus-border-color;
outline: 0;
}
@@ -85,19 +89,19 @@
.select2-choices,
.select2-choice {
- border-color: $red-500;
+ border-color: var(--red-500, $red-500);
}
}
}
.select2-drop,
.select2-drop.select2-drop-above {
- background: $white;
+ background: var(--white, $white);
box-shadow: 0 2px 4px $dropdown-shadow-color;
border-radius: $gl-border-radius-base;
- border: 1px solid $border-color;
+ border: 1px solid var(--border-color, $border-color);
min-width: 175px;
- color: $gl-text-color;
+ color: var(--gl-text-color, $gl-text-color);
z-index: 999;
.modal-open & {
@@ -114,7 +118,7 @@
}
.select2-drop.select2-drop-above.select2-drop-active {
- border-top: 1px solid $border-color;
+ border-top: 1px solid var(--border-color, $border-color);
margin-top: -6px;
}
@@ -128,7 +132,7 @@
.select2-dropdown-open,
.select2-dropdown-open.select2-drop-above {
.select2-choice {
- border-color: $gray-darkest;
+ border-color: var(--border-color, $border-color);
outline: 0;
}
}
@@ -136,7 +140,7 @@
.select2-container-multi {
.select2-choices {
border-radius: $border-radius-default;
- border-color: $border-color;
+ border-color: var(--border-color, $border-color);
background: none;
.select2-search-field input {
@@ -149,10 +153,10 @@
.select2-search-choice {
margin: 5px 0 0 8px;
box-shadow: none;
- border-color: $border-color;
- color: $gl-text-color;
+ border-color: var(--border-color, $border-color);
+ color: var(--gl-text-color, $gl-text-color);
line-height: 15px;
- background-color: $gray-light;
+ background-color: var(--gray-50, $gray-50);
background-image: none;
padding: 3px 18px 3px 5px;
@@ -163,7 +167,7 @@
}
&.select2-search-choice-focus {
- border-color: $gl-text-color;
+ border-color: var(--gl-text-color, $gl-text-color);
}
}
}
@@ -188,22 +192,22 @@
input {
padding: $grid-size;
background: transparent image-url('select2.png');
- color: $gl-text-color;
+ color: var(--gl-text-color, $gl-text-color);
background-clip: content-box;
background-origin: content-box;
background-repeat: no-repeat;
background-position: right 0 bottom 0 !important;
- border: 1px solid $border-color;
+ border: 1px solid var(--border-color, $border-color);
border-radius: $border-radius-default;
line-height: 16px;
transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
&:focus {
- border-color: $blue-300;
+ border-color: var(--blue-300, $blue-300);
}
&.select2-active {
- background-color: $white;
+ background-color: var(--white, $white);
background-image: image-url('select2-spinner.gif') !important;
background-origin: content-box;
background-repeat: no-repeat;
@@ -236,10 +240,10 @@
.select2-highlighted {
background: transparent;
- color: $gl-text-color;
+ color: var(--gl-text-color, $gl-text-color);
.select2-result-label {
- background: $gray-darker;
+ background: var(--gray-50, $gray-50);
}
}
@@ -249,14 +253,14 @@
li.select2-result-with-children > .select2-result-label {
font-weight: $gl-font-weight-bold;
- color: $gl-text-color;
+ color: var(--gl-text-color, $gl-text-color);
}
}
.select2-highlighted {
.group-result {
.group-path {
- color: $gray-700;
+ color: var(--gray-700, $gray-700);
}
}
}
diff --git a/app/assets/stylesheets/page_bundles/build.scss b/app/assets/stylesheets/page_bundles/build.scss
index be709ff9d09..b91850f1775 100644
--- a/app/assets/stylesheets/page_bundles/build.scss
+++ b/app/assets/stylesheets/page_bundles/build.scss
@@ -8,9 +8,9 @@
.archived-job {
top: $header-height;
border-radius: 2px 2px 0 0;
- color: $orange-600;
- background-color: $orange-50;
- border: 1px solid $border-gray-normal;
+ color: var(--orange-600, $orange-600);
+ background-color: var(--orange-50, $orange-50);
+ border: 1px solid var(--border-color, $border-color);
padding: 3px 12px;
margin: auto;
align-items: center;
@@ -88,19 +88,15 @@
.header-content {
a {
- color: $gl-text-color;
+ color: var(--gl-text-color, $gl-text-color);
&:hover {
- color: $blue-600;
+ color: var(--blue-600, $blue-600);
text-decoration: none;
}
}
}
- code {
- color: $code-color;
- }
-
.avatar {
float: none;
margin-right: 2px;
@@ -148,12 +144,12 @@
.trigger-build-variable {
font-weight: $gl-font-weight-normal;
- color: $code-color;
+ color: var(--gray-950, $gray-950);
}
.trigger-build-value {
padding: 2px 4px;
- color: $black;
+ color: var(--black, $black);
}
.trigger-variables-table-cell {
@@ -173,7 +169,7 @@
cursor: pointer;
&:hover {
- color: $gl-text-color;
+ color: var(--gl-text-color, $gl-text-color);
}
}
@@ -211,7 +207,7 @@
}
&.retried {
- background-color: $gray-lightest;
+ background-color: var(--gray-10, $gray-10);
}
&:hover {
diff --git a/app/assets/stylesheets/page_bundles/learn_gitlab.scss b/app/assets/stylesheets/page_bundles/learn_gitlab.scss
index 189aefb330b..10a4a210d41 100644
--- a/app/assets/stylesheets/page_bundles/learn_gitlab.scss
+++ b/app/assets/stylesheets/page_bundles/learn_gitlab.scss
@@ -1,3 +1,11 @@
.learn-gitlab-info-card-content {
height: 200px;
}
+
+.learn-gitlab-section-card {
+ height: 400px;
+}
+
+.learn-gitlab-section-card-header {
+ height: 165px;
+}
diff --git a/app/assets/stylesheets/themes/theme_light.scss b/app/assets/stylesheets/themes/theme_light.scss
index 228bff94f5d..b41377475c5 100644
--- a/app/assets/stylesheets/themes/theme_light.scss
+++ b/app/assets/stylesheets/themes/theme_light.scss
@@ -81,50 +81,4 @@ body {
color: $gray-900;
}
}
-
- &.gl-dark {
- .logo-text svg {
- fill: var(--gl-text-color);
- }
-
- .navbar-gitlab {
- background-color: var(--gray-50);
- box-shadow: 0 1px 0 0 var(--gray-100);
-
- .navbar-sub-nav,
- .navbar-nav {
- li {
- > a:hover,
- > a:focus,
- > button:hover,
- > button:focus {
- color: var(--gl-text-color);
- background-color: var(--gray-200);
- }
- }
-
- li.active,
- li.dropdown.show {
- > a,
- > button {
- color: var(--gl-text-color);
- background-color: var(--gray-200);
- }
- }
- }
-
- .search {
- form {
- background-color: var(--gray-100);
- box-shadow: inset 0 0 0 1px var(--border-color);
-
- &:active,
- &:hover {
- background-color: var(--gray-100);
- box-shadow: inset 0 0 0 1px var(--blue-200);
- }
- }
- }
- }
- }
}
diff --git a/app/helpers/ci/pipeline_editor_helper.rb b/app/helpers/ci/pipeline_editor_helper.rb
index a71b0f4a83a..ceb18d90c92 100644
--- a/app/helpers/ci/pipeline_editor_helper.rb
+++ b/app/helpers/ci/pipeline_editor_helper.rb
@@ -7,5 +7,23 @@ module Ci
def can_view_pipeline_editor?(project)
can_collaborate_with_project?(project)
end
+
+ def js_pipeline_editor_data(project)
+ {
+ "ci-config-path": project.ci_config_path_or_default,
+ "commit-sha" => project.commit ? project.commit.sha : '',
+ "default-branch" => project.default_branch,
+ "empty-state-illustration-path" => image_path('illustrations/empty-state/empty-dag-md.svg'),
+ "initial-branch-name": params[:branch_name],
+ "lint-help-page-path" => help_page_path('ci/lint', anchor: 'validate-basic-logic-and-syntax'),
+ "new-merge-request-path" => namespace_project_new_merge_request_path,
+ "project-path" => project.path,
+ "project-full-path" => project.full_path,
+ "project-namespace" => project.namespace.full_path,
+ "yml-help-page-path" => help_page_path('ci/yaml/README')
+ }
+ end
end
end
+
+Ci::PipelineEditorHelper.prepend_if_ee('EE::Ci::PipelineEditorHelper')
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index 0fe29f09140..0e55841f5fa 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -394,26 +394,13 @@ module Ci
# given we simply get the latest pipelines for the commits, regardless
# of what refs the pipelines belong to.
def self.latest_pipeline_per_commit(commits, ref = nil)
- p1 = arel_table
- p2 = arel_table.alias
+ sql = select('DISTINCT ON (sha) *')
+ .where(sha: commits)
+ .order(:sha, id: :desc)
- # This LEFT JOIN will filter out all but the newest row for every
- # combination of (project_id, sha) or (project_id, sha, ref) if a ref is
- # given.
- cond = p1[:sha].eq(p2[:sha])
- .and(p1[:project_id].eq(p2[:project_id]))
- .and(p1[:id].lt(p2[:id]))
+ sql = sql.where(ref: ref) if ref
- cond = cond.and(p1[:ref].eq(p2[:ref])) if ref
- join = p1.join(p2, Arel::Nodes::OuterJoin).on(cond)
-
- relation = where(sha: commits)
- .where(p2[:id].eq(nil))
- .joins(join.join_sources)
-
- relation = relation.where(ref: ref) if ref
-
- relation.each_with_object({}) do |pipeline, hash|
+ sql.each_with_object({}) do |pipeline, hash|
hash[pipeline.sha] = pipeline
end
end
diff --git a/app/services/ci/abort_pipelines_service.rb b/app/services/ci/abort_pipelines_service.rb
index dae56577f51..9f427243abd 100644
--- a/app/services/ci/abort_pipelines_service.rb
+++ b/app/services/ci/abort_pipelines_service.rb
@@ -5,26 +5,29 @@ module Ci
# Danger: Cancels in bulk without callbacks
# Only for pipeline abandonment scenarios (examples: project delete, user block)
def execute(pipelines)
- bulk_abort!(pipelines.cancelable, status: :canceled)
+ @time = Time.current
+
+ bulk_abort!(pipelines.cancelable, { status: :canceled })
ServiceResponse.success(message: 'Pipelines canceled')
end
private
- def bulk_abort!(pipelines, status:)
+ def bulk_abort!(pipelines, attributes)
pipelines.each_batch(of: 100) do |pipeline_batch|
- update_status_for(Ci::Stage, pipeline_batch, status)
- update_status_for(CommitStatus, pipeline_batch, status)
- pipeline_batch.update_all(status: status, finished_at: Time.current)
+ update_status_for(Ci::Stage, pipeline_batch, attributes)
+ update_status_for(CommitStatus, pipeline_batch, attributes.merge(finished_at: @time))
+
+ pipeline_batch.update_all(attributes.merge(finished_at: @time))
end
end
- def update_status_for(klass, pipelines, status)
+ def update_status_for(klass, pipelines, attributes)
klass.in_pipelines(pipelines)
.cancelable
.in_batches(of: 150) # rubocop:disable Cop/InBatches
- .update_all(status: status)
+ .update_all(attributes)
end
end
end
diff --git a/app/views/admin/application_settings/_registry.html.haml b/app/views/admin/application_settings/_registry.html.haml
index fc03a6dd10c..78d4e8c8cc3 100644
--- a/app/views/admin/application_settings/_registry.html.haml
+++ b/app/views/admin/application_settings/_registry.html.haml
@@ -3,7 +3,7 @@
%fieldset
.form-group
- = f.label :container_registry_token_expire_delay, 'Authorization token duration (minutes)', class: 'label-bold'
+ = f.label :container_registry_token_expire_delay, _('Authorization token duration (minutes)'), class: 'label-bold'
= f.number_field :container_registry_token_expire_delay, class: 'form-control gl-form-input'
.form-group
.form-check
@@ -31,4 +31,4 @@
.form-text.text-muted
= _("The maximum number of tags that a single worker accepts for cleanup. If the number of tags goes above this limit, the list of tags to delete is truncated to this number. To remove this limit, set it to 0.")
- = f.submit 'Save changes', class: "gl-button btn btn-confirm"
+ = f.submit _('Save changes'), class: "gl-button btn btn-confirm"
diff --git a/app/views/devise/sessions/_new_ldap.html.haml b/app/views/devise/sessions/_new_ldap.html.haml
index 19fcabb1a2e..f599a652b71 100644
--- a/app/views/devise/sessions/_new_ldap.html.haml
+++ b/app/views/devise/sessions/_new_ldap.html.haml
@@ -5,15 +5,15 @@
= form_tag(omniauth_callback_path(:user, server['provider_name']), id: 'new_ldap_user', class: "gl-show-field-errors") do
.form-group
= label_tag :username, "#{server['label']} Username"
- = text_field_tag :username, nil, { class: "form-control gl-form-input top", title: "This field is required.", autofocus: "autofocus", data: { qa_selector: 'username_field' }, required: true }
+ = text_field_tag :username, nil, { class: "form-control gl-form-input top", title: _("This field is required."), autofocus: "autofocus", data: { qa_selector: 'username_field' }, required: true }
.form-group
= label_tag :password
- = password_field_tag :password, nil, { class: "form-control gl-form-input bottom", title: "This field is required.", data: { qa_selector: 'password_field' }, required: true }
+ = password_field_tag :password, nil, { class: "form-control gl-form-input bottom", title: _("This field is required."), data: { qa_selector: 'password_field' }, required: true }
- if !hide_remember_me && devise_mapping.rememberable?
.remember-me
%label{ for: "remember_me" }
= check_box_tag :remember_me, '1', false, id: 'remember_me'
- %span Remember me
+ %span= _('Remember me')
.submit-container.move-submit-down
= submit_tag submit_message, class: "gl-button btn btn-confirm", data: { qa_selector: 'sign_in_button' }
diff --git a/app/views/profiles/chat_names/_chat_name.html.haml b/app/views/profiles/chat_names/_chat_name.html.haml
index 6805824cebc..ca895972b71 100644
--- a/app/views/profiles/chat_names/_chat_name.html.haml
+++ b/app/views/profiles/chat_names/_chat_name.html.haml
@@ -6,7 +6,7 @@
- if can?(current_user, :read_project, project)
= link_to project.full_name, project_path(project)
- else
- .light N/A
+ .light= _('N/A')
%td
%strong
- if can?(current_user, :admin_project, project)
diff --git a/app/views/projects/ci/pipeline_editor/show.html.haml b/app/views/projects/ci/pipeline_editor/show.html.haml
index 2204d564697..eb588e150f7 100644
--- a/app/views/projects/ci/pipeline_editor/show.html.haml
+++ b/app/views/projects/ci/pipeline_editor/show.html.haml
@@ -1,15 +1,3 @@
- page_title s_('Pipelines|Pipeline Editor')
-#js-pipeline-editor{ data: { "ci-config-path": @project.ci_config_path_or_default,
- "commit-sha" => @project.commit ? @project.commit.sha : '',
- "default-branch" => @project.default_branch,
- "empty-state-illustration-path" => image_path('illustrations/empty-state/empty-dag-md.svg'),
- "initial-branch-name": params[:branch_name],
- "lint-help-page-path" => help_page_path('ci/lint', anchor: 'validate-basic-logic-and-syntax'),
- "new-merge-request-path" => namespace_project_new_merge_request_path,
- "project-path" => @project.path,
- "project-full-path" => @project.full_path,
- "project-namespace" => @project.namespace.full_path,
- "yml-help-page-path" => help_page_path('ci/yaml/README'),
- "api-fuzzing-configuration-path" => project_security_configuration_api_fuzzing_path(@project),
-} }
+#js-pipeline-editor{ data: js_pipeline_editor_data(@project) }
diff --git a/app/views/projects/triggers/_index.html.haml b/app/views/projects/triggers/_index.html.haml
index c7cb051e40d..85ecfe7a982 100644
--- a/app/views/projects/triggers/_index.html.haml
+++ b/app/views/projects/triggers/_index.html.haml
@@ -2,9 +2,9 @@
.col-lg-12
.card
.card-header
- = s_("Manage your project's triggers")
+ = _("Manage your project's triggers")
.card-body
- = render "projects/triggers/form", btn_text: "Add trigger"
+ = render 'projects/triggers/form', btn_text: _('Add trigger')
%hr
- if Feature.enabled?(:ci_pipeline_triggers_settings_vue_ui, @project)
#js-ci-pipeline-triggers-list.triggers-list{ data: { triggers: @triggers_json } }
@@ -15,32 +15,32 @@
%thead
%th
%strong
- = s_("Token")
+ = _('Token')
%th
%strong
- = s_("Description")
+ = _('Description')
%th
%strong
- = s_("Owner")
+ = _('Owner')
%th
%strong
- = s_("Last used")
+ = _('Last used')
%th
= render partial: 'projects/triggers/trigger', collection: @triggers, as: :trigger
- else
%p.settings-message.text-center.gl-mb-3{ data: { testid: 'no_triggers_content' } }
- = s_("No triggers exist yet. Use the form above to create one.")
+ = _('No triggers exist yet. Use the form above to create one.')
.card-footer
%p
- = s_("These examples show how to trigger this project's pipeline for a branch or tag.")
+ = _("These examples show how to trigger this project's pipeline for a branch or tag.")
%p.light
- = s_("Triggers|In each example, replace %{code_start}TOKEN%{code_end} with the trigger token you generated and replace %{code_start}REF_NAME%{code_end} with the branch or tag name.").html_safe % { code_start: "<code>".html_safe, code_end: "</code>".html_safe }
+ = _('In each example, replace %{code_start}TOKEN%{code_end} with the trigger token you generated and replace %{code_start}REF_NAME%{code_end} with the branch or tag name.').html_safe % { code_start: '<code>'.html_safe, code_end: '</code>'.html_safe }
%h5.gl-mt-3
- = s_("Use cURL")
+ = _('Use cURL')
%pre
:plain
@@ -49,26 +49,26 @@
-F ref=REF_NAME \
#{builds_trigger_url(@project.id)}
%h5.gl-mt-3
- = s_("Use .gitlab-ci.yml")
+ = _('Use .gitlab-ci.yml')
%pre
:plain
script:
- "curl -X POST -F token=TOKEN -F ref=REF_NAME #{builds_trigger_url(@project.id)}"
%h5.gl-mt-3
- = s_("Use webhook")
+ = _('Use webhook')
%pre
:plain
#{builds_trigger_url(@project.id, ref: 'REF_NAME')}?token=TOKEN
%h5.gl-mt-3
- = s_("Pass job variables")
+ = _('Pass job variables')
%p.light
- = s_("Triggers|To pass variables to the triggered pipeline, add %{code_start}variables[VARIABLE]=VALUE%{code_end} to the API request.").html_safe % { code_start: "<code>".html_safe, code_end: "</code>".html_safe }
+ = _('To pass variables to the triggered pipeline, add %{code_start}variables[VARIABLE]=VALUE%{code_end} to the API request.').html_safe % { code_start: '<code>'.html_safe, code_end: '</code>'.html_safe }
%p.light
- = s_("cURL:")
+ = _('cURL:')
%pre
:plain
@@ -78,7 +78,7 @@
-F "variables[RUN_NIGHTLY_BUILD]=true" \
#{builds_trigger_url(@project.id)}
%p.light
- = s_("Webhook:")
+ = _('Webhook:')
%pre.gl-mb-0
:plain
diff --git a/changelogs/unreleased/202423-remove-records-without-group-from-webhooks.yml b/changelogs/unreleased/202423-remove-records-without-group-from-webhooks.yml
new file mode 100644
index 00000000000..dff08ca6494
--- /dev/null
+++ b/changelogs/unreleased/202423-remove-records-without-group-from-webhooks.yml
@@ -0,0 +1,5 @@
+---
+title: Remove records without group from webhooks table
+merge_request: 57863
+author:
+type: other
diff --git a/changelogs/unreleased/324796-update-deprecated-glicon-size-and-remove-use-deprecated-sizes.yml b/changelogs/unreleased/324796-update-deprecated-glicon-size-and-remove-use-deprecated-sizes.yml
new file mode 100644
index 00000000000..c46328b6fe7
--- /dev/null
+++ b/changelogs/unreleased/324796-update-deprecated-glicon-size-and-remove-use-deprecated-sizes.yml
@@ -0,0 +1,5 @@
+---
+title: Update GlIcon size in environments.vue
+merge_request: 58208
+author: Md. Pial Ahamed (@root.pial)
+type: changed
diff --git a/changelogs/unreleased/Externalise-strings-in-_registry-html-haml.yml b/changelogs/unreleased/Externalise-strings-in-_registry-html-haml.yml
new file mode 100644
index 00000000000..eff8004de31
--- /dev/null
+++ b/changelogs/unreleased/Externalise-strings-in-_registry-html-haml.yml
@@ -0,0 +1,5 @@
+---
+title: Externalise strings in _registry.html.haml
+merge_request: 58051
+author: nuwe1
+type: other
diff --git a/changelogs/unreleased/Externalise-strings-in-chat_names-_chat_name-html-haml.yml b/changelogs/unreleased/Externalise-strings-in-chat_names-_chat_name-html-haml.yml
new file mode 100644
index 00000000000..6c75f17563d
--- /dev/null
+++ b/changelogs/unreleased/Externalise-strings-in-chat_names-_chat_name-html-haml.yml
@@ -0,0 +1,5 @@
+---
+title: Externalize strings in chat_names/_chat_name.html.haml
+merge_request: 58444
+author: nuwe1
+type: other
diff --git a/changelogs/unreleased/Externalize-strings-in-ssessions_new_ldap-html-haml.yml b/changelogs/unreleased/Externalize-strings-in-ssessions_new_ldap-html-haml.yml
new file mode 100644
index 00000000000..89bd340d9f1
--- /dev/null
+++ b/changelogs/unreleased/Externalize-strings-in-ssessions_new_ldap-html-haml.yml
@@ -0,0 +1,5 @@
+---
+title: Externalize strings in sessions/_new_ldap.html.haml
+merge_request: 58267
+author: nuwe1
+type: other
diff --git a/changelogs/unreleased/fix-commit-status-with-child-pipeline.yml b/changelogs/unreleased/fix-commit-status-with-child-pipeline.yml
new file mode 100644
index 00000000000..eacbcd8bc0f
--- /dev/null
+++ b/changelogs/unreleased/fix-commit-status-with-child-pipeline.yml
@@ -0,0 +1,5 @@
+---
+title: Filter out pipelines that were excluded in the relation scope in Ci::Pipeline#latest_pipeline_per_commit
+merge_request: 55657
+author: Cong Chen @gentcys
+type: fixed
diff --git a/changelogs/unreleased/fix-gb-avoid-inflating-memory-when-aborting-pipelines.yml b/changelogs/unreleased/fix-gb-avoid-inflating-memory-when-aborting-pipelines.yml
new file mode 100644
index 00000000000..ab723b380c6
--- /dev/null
+++ b/changelogs/unreleased/fix-gb-avoid-inflating-memory-when-aborting-pipelines.yml
@@ -0,0 +1,5 @@
+---
+title: Avoid inflating Redis memory when aborting pipelines
+merge_request: 59018
+author:
+type: fixed
diff --git a/changelogs/unreleased/id-bump-devise-two-factor.yml b/changelogs/unreleased/id-bump-devise-two-factor.yml
new file mode 100644
index 00000000000..6a75991aaa4
--- /dev/null
+++ b/changelogs/unreleased/id-bump-devise-two-factor.yml
@@ -0,0 +1,5 @@
+---
+title: Bump devise-two-factor version
+merge_request: 58929
+author:
+type: other
diff --git a/changelogs/unreleased/issue-325836-fix-empty-line-after-let-it-be-api-helpers.yml b/changelogs/unreleased/issue-325836-fix-empty-line-after-let-it-be-api-helpers.yml
new file mode 100644
index 00000000000..68566e26cc8
--- /dev/null
+++ b/changelogs/unreleased/issue-325836-fix-empty-line-after-let-it-be-api-helpers.yml
@@ -0,0 +1,5 @@
+---
+title: Fix EmptyLineAfterFinalLetItBe Rubocop offenses for api helpers
+merge_request: 58194
+author: Huzaifa Iftikhar @huzaifaiftikhar
+type: fixed
diff --git a/changelogs/unreleased/issue-325836-fix-empty-line-after-let-it-be-gitlab-github-import.yml b/changelogs/unreleased/issue-325836-fix-empty-line-after-let-it-be-gitlab-github-import.yml
new file mode 100644
index 00000000000..fb0ece8309f
--- /dev/null
+++ b/changelogs/unreleased/issue-325836-fix-empty-line-after-let-it-be-gitlab-github-import.yml
@@ -0,0 +1,5 @@
+---
+title: Fix EmptyLineAfterFinalLetItBe offenses spec/lib/gitlab/github_import
+merge_request: 58256
+author: Huzaifa Iftikhar @huzaifaiftikhar
+type: fixed
diff --git a/changelogs/unreleased/issue-325836-fix-empty-line-after-let-it-be-gitlab-imoport-export.yml b/changelogs/unreleased/issue-325836-fix-empty-line-after-let-it-be-gitlab-imoport-export.yml
new file mode 100644
index 00000000000..fde96539c7b
--- /dev/null
+++ b/changelogs/unreleased/issue-325836-fix-empty-line-after-let-it-be-gitlab-imoport-export.yml
@@ -0,0 +1,5 @@
+---
+title: Fix EmptyLineAfterFinalLetItBe offenses spec/lib/gitlab/import_export
+merge_request: 58264
+author: Huzaifa Iftikhar @huzaifaiftikhar
+type: fixed
diff --git a/changelogs/unreleased/jonstonchan-fix-triggers-externalization.yml b/changelogs/unreleased/jonstonchan-fix-triggers-externalization.yml
new file mode 100644
index 00000000000..56f6127478b
--- /dev/null
+++ b/changelogs/unreleased/jonstonchan-fix-triggers-externalization.yml
@@ -0,0 +1,5 @@
+---
+title: Fix triggers page externalization
+merge_request: 57637
+author: Jonston Chan @JonstonChan
+type: other
diff --git a/changelogs/unreleased/optimize-query-for-cherry-picked-merge-requests.yml b/changelogs/unreleased/optimize-query-for-cherry-picked-merge-requests.yml
new file mode 100644
index 00000000000..a9921a886f6
--- /dev/null
+++ b/changelogs/unreleased/optimize-query-for-cherry-picked-merge-requests.yml
@@ -0,0 +1,5 @@
+---
+title: Optimize query for cherry picked merge requests
+merge_request: 58967
+author:
+type: performance
diff --git a/changelogs/unreleased/psi-dark-build.yml b/changelogs/unreleased/psi-dark-build.yml
new file mode 100644
index 00000000000..aece4a82cd8
--- /dev/null
+++ b/changelogs/unreleased/psi-dark-build.yml
@@ -0,0 +1,5 @@
+---
+title: Fix dark mode colors of retried jobs in job details page
+merge_request: 58855
+author:
+type: fixed
diff --git a/changelogs/unreleased/psi-dark-navbar.yml b/changelogs/unreleased/psi-dark-navbar.yml
new file mode 100644
index 00000000000..e20a9d0b818
--- /dev/null
+++ b/changelogs/unreleased/psi-dark-navbar.yml
@@ -0,0 +1,5 @@
+---
+title: Dark mode nav improvements
+merge_request: 58891
+author:
+type: fixed
diff --git a/changelogs/unreleased/psi-dark-select2.yml b/changelogs/unreleased/psi-dark-select2.yml
new file mode 100644
index 00000000000..90f9dc7edbe
--- /dev/null
+++ b/changelogs/unreleased/psi-dark-select2.yml
@@ -0,0 +1,5 @@
+---
+title: Fix select2 dropdowns in dark mode
+merge_request: 58862
+author:
+type: fixed
diff --git a/config/feature_flags/development/async_add_build_failure_todo.yml b/config/feature_flags/development/async_add_build_failure_todo.yml
index 6bb1a84ed82..3c1e056a50e 100644
--- a/config/feature_flags/development/async_add_build_failure_todo.yml
+++ b/config/feature_flags/development/async_add_build_failure_todo.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/326726
milestone: '13.11'
type: development
group: group::continuous integration
-default_enabled: false
+default_enabled: true
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index c451ce6b872..da1a15302da 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -6,7 +6,7 @@
# This file should not receive new settings. All configuration options #
# * are being moved to ApplicationSetting model! #
# If a setting requires an application restart say so in that screen. #
-# If you change this file in a Merge Request, please also create #
+# If you change this file in a merge request, please also create #
# a MR on https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests. #
# For more details see https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/settings/gitlab.yml.md #
########################################################################
diff --git a/config/initializers/smtp_settings.rb.sample b/config/initializers/smtp_settings.rb.sample
index bd37080b1c8..babc0a81938 100644
--- a/config/initializers/smtp_settings.rb.sample
+++ b/config/initializers/smtp_settings.rb.sample
@@ -5,7 +5,7 @@
#
# For full list of options and their values see http://api.rubyonrails.org/classes/ActionMailer/Base.html
#
-# If you change this file in a Merge Request, please also create a Merge Request on https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests
+# If you change this file in a merge request, please also create a merge request on https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests
if Rails.env.production?
Rails.application.config.action_mailer.delivery_method = :smtp
diff --git a/config/metrics/counts_all/20210216180246_web_ide_merge_requests.yml b/config/metrics/counts_all/20210216180246_web_ide_merge_requests.yml
index 2df821ee8ad..d8ab29b3ef5 100644
--- a/config/metrics/counts_all/20210216180246_web_ide_merge_requests.yml
+++ b/config/metrics/counts_all/20210216180246_web_ide_merge_requests.yml
@@ -1,6 +1,6 @@
---
key_path: counts.web_ide_merge_requests
-description: Count of Merge Requests created from Web IDE
+description: Count of merge requests created from Web IDE
product_section: dev
product_stage: create
product_group: group::editor
diff --git a/config/redis.cache.yml.example b/config/redis.cache.yml.example
index fb92c205ce1..44d9f7e8632 100644
--- a/config/redis.cache.yml.example
+++ b/config/redis.cache.yml.example
@@ -1,5 +1,5 @@
-# If you change this file in a Merge Request, please also create
-# a Merge Request on https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests
+# If you change this file in a merge request, please also create
+# a merge request on https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests
#
development:
url: redis://localhost:6379/10
diff --git a/config/redis.queues.yml.example b/config/redis.queues.yml.example
index dd6c10e0e06..4194b44cb88 100644
--- a/config/redis.queues.yml.example
+++ b/config/redis.queues.yml.example
@@ -1,5 +1,5 @@
-# If you change this file in a Merge Request, please also create
-# a Merge Request on https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests
+# If you change this file in a merge request, please also create
+# a merge request on https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests
#
development:
url: redis://localhost:6379/11
diff --git a/config/redis.shared_state.yml.example b/config/redis.shared_state.yml.example
index 98f6f330bc7..b3e0c7a8fa9 100644
--- a/config/redis.shared_state.yml.example
+++ b/config/redis.shared_state.yml.example
@@ -1,5 +1,5 @@
-# If you change this file in a Merge Request, please also create
-# a Merge Request on https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests
+# If you change this file in a merge request, please also create
+# a merge request on https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests
#
development:
url: redis://localhost:6379/12
diff --git a/config/resque.yml.example b/config/resque.yml.example
index 0f629a5229c..656cd57a739 100644
--- a/config/resque.yml.example
+++ b/config/resque.yml.example
@@ -1,5 +1,5 @@
-# If you change this file in a Merge Request, please also create
-# a Merge Request on https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests
+# If you change this file in a merge request, please also create
+# a merge request on https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests
#
development:
url: redis://localhost:6379
diff --git a/config/unicorn.rb.example b/config/unicorn.rb.example
index 0e475249868..c930e2ff761 100644
--- a/config/unicorn.rb.example
+++ b/config/unicorn.rb.example
@@ -8,8 +8,8 @@
# See http://unicorn.bogomips.org/Unicorn/Configurator.html for complete
# documentation.
-# Note: If you change this file in a Merge Request, please also create a
-# Merge Request on https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests
+# Note: If you change this file in a merge request, please also create a
+# merge request on https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests
# Relative URL support
# WARNING: We recommend using an FQDN to host GitLab in a root path instead
diff --git a/db/migrate/20210409084242_create_index_on_notes_for_cherry_picked_merge_requests.rb b/db/migrate/20210409084242_create_index_on_notes_for_cherry_picked_merge_requests.rb
new file mode 100644
index 00000000000..2bcdf4c8982
--- /dev/null
+++ b/db/migrate/20210409084242_create_index_on_notes_for_cherry_picked_merge_requests.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class CreateIndexOnNotesForCherryPickedMergeRequests < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ NAME = 'index_notes_for_cherry_picked_merge_requests'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :notes, [:project_id, :commit_id], where: "((noteable_type)::text = 'MergeRequest'::text)", name: NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :notes, name: NAME
+ end
+end
diff --git a/db/post_migrate/20210330091751_remove_records_without_group_from_webhooks_table.rb b/db/post_migrate/20210330091751_remove_records_without_group_from_webhooks_table.rb
new file mode 100644
index 00000000000..c384aa25ac4
--- /dev/null
+++ b/db/post_migrate/20210330091751_remove_records_without_group_from_webhooks_table.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+class RemoveRecordsWithoutGroupFromWebhooksTable < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ class WebHook < ActiveRecord::Base
+ include EachBatch
+
+ self.table_name = 'web_hooks'
+ end
+
+ class Group < ActiveRecord::Base
+ self.inheritance_column = :_type_disabled
+ self.table_name = 'namespaces'
+ end
+
+ def up
+ subquery = Group.select(1).where(Group.arel_table[:id].eq(WebHook.arel_table[:group_id]))
+
+ WebHook.each_batch(of: 500, column: :id) do |relation|
+ relation.where(type: 'GroupHook').where.not('EXISTS (?)', subquery).delete_all
+ end
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/schema_migrations/20210330091751 b/db/schema_migrations/20210330091751
new file mode 100644
index 00000000000..0536252e980
--- /dev/null
+++ b/db/schema_migrations/20210330091751
@@ -0,0 +1 @@
+3a195b9671846409cf6665b13caad9713541d9cdd95c9f246c22b7db225ab02c \ No newline at end of file
diff --git a/db/schema_migrations/20210409084242 b/db/schema_migrations/20210409084242
new file mode 100644
index 00000000000..2d932018355
--- /dev/null
+++ b/db/schema_migrations/20210409084242
@@ -0,0 +1 @@
+6bd35117ca922fc0d9cb8cbd9b0e6d5d9216457182d5679e705c1f03eef05921 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index a553b47ff84..94779cafdc3 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -23207,6 +23207,8 @@ CREATE INDEX index_non_requested_project_members_on_source_id_and_type ON member
CREATE UNIQUE INDEX index_note_diff_files_on_diff_note_id ON note_diff_files USING btree (diff_note_id);
+CREATE INDEX index_notes_for_cherry_picked_merge_requests ON notes USING btree (project_id, commit_id) WHERE ((noteable_type)::text = 'MergeRequest'::text);
+
CREATE INDEX index_notes_on_author_id_and_created_at_and_id ON notes USING btree (author_id, created_at, id);
CREATE INDEX index_notes_on_commit_id ON notes USING btree (commit_id);
diff --git a/doc/api/jobs.md b/doc/api/jobs.md
index fbcdc3f106c..a19dbecb430 100644
--- a/doc/api/jobs.md
+++ b/doc/api/jobs.md
@@ -295,7 +295,8 @@ In GitLab 13.3 and later, this endpoint [returns data for any pipeline](pipeline
including [child pipelines](../ci/parent_child_pipelines.md).
In GitLab 13.5 and later, this endpoint does not return retried jobs in the response
-by default.
+by default. Additionally, jobs are sorted by ID in ascending order (oldest first).
+In earlier GitLab versions, jobs are sorted by ID in descending order (newest first).
In GitLab 13.9 and later, this endpoint can include retried jobs in the response
with `include_retried` set to `true`.
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 4873385d808..17f52cea50b 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -250,8 +250,41 @@ workflow:
- if: $CI_COMMIT_REF_NAME =~ /feature/
variables:
IS_A_FEATURE: "true" # Define a new variable.
+ - when: always # Run the pipeline in other cases
+
+job1:
+ variables:
+ DEPLOY_VARIABLE: "job1-default-deploy"
+ rules:
+ - if: $CI_COMMIT_REF_NAME =~ /master/
+ variables: # Override DEPLOY_VARIABLE defined
+ DEPLOY_VARIABLE: "job1-deploy-production" # at the job level.
+ - when: on_success # Run the job in other cases
+ script:
+ - echo "Run script with $DEPLOY_VARIABLE as an argument"
+ - echo "Run another script if $IS_A_FEATURE exists"
+
+job2:
+ script:
+ - echo "Run script with $DEPLOY_VARIABLE as an argument"
+ - echo "Run another script if $IS_A_FEATURE exists"
```
+When the branch is `master`:
+
+- job1's `DEPLOY_VARIABLE` is `job1-deploy-production`.
+- job2's `DEPLOY_VARIABLE` is `deploy-production`.
+
+When the branch is `feature`:
+
+- job1's `DEPLOY_VARIABLE` is `job1-default-deploy`, and `IS_A_FEATURE` is `true`.
+- job2's `DEPLOY_VARIABLE` is `default-deploy`, and `IS_A_FEATURE` is `true`.
+
+When the branch is something else:
+
+- job1's `DEPLOY_VARIABLE` is `job1-default-deploy`.
+- job2's `DEPLOY_VARIABLE` is `default-deploy`.
+
##### Enable or disable workflow:rules:variables **(CORE ONLY)**
rules:variables is under development and not ready for production use.
diff --git a/doc/development/merge_request_performance_guidelines.md b/doc/development/merge_request_performance_guidelines.md
index 772ce1d6b59..0f696d39092 100644
--- a/doc/development/merge_request_performance_guidelines.md
+++ b/doc/development/merge_request_performance_guidelines.md
@@ -158,6 +158,27 @@ objects_to_update.update_all(some_field: some_value)
This uses ActiveRecord's `update_all` method to update all rows in a single
query. This in turn makes it much harder for this code to overload a database.
+## Use read replicas when possible
+
+In a DB cluster we have many read replicas and one primary. A classic use of scaling the DB is to have read-only actions be performed by the replicas. We use [load balancing](../administration/database_load_balancing.md) to distribute this load. This allows for the replicas to grow as the pressure on the DB grows.
+
+By default, queries use read-only replicas, but due to [primary sticking](../administration/database_load_balancing.md#primary-sticking), GitLab sticks to using the primary for a certain period of time and reverts back to secondaries after they have either caught up or after 30 seconds, which can lead to a considerable amount of unnecessary load on the primary. In this [merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56849) we introduced the `without_sticky_writes` block to prevent switching to the primary. This [merge request example](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57328) provides a good use case for when queries can stick to the primary and how to prevent this by using `without_sticky_writes`.
+
+Internally, our database load balancer classifies the queries based on their main statement (`select`, `update`, `delete`, etc.). When in doubt, it redirects the queries to the primary database. Hence, there are some common cases the load balancer sends the queries to the primary unnecessarily:
+
+- Custom queries (via `exec_query`, `execute_statement`, `execute`, etc.)
+- Read-only transactions
+- In-flight connection configuration set
+- Sidekiq background jobs
+
+Worse, after the above queries are executed, GitLab [sticks to the primary](../administration/database_load_balancing.md#primary-sticking). In [this merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56476), we introduced `use_replica_if_possible` to make the inside queries prefer to use the replicas. That MR is also an example how we redirected a costly, time-consuming query to the replicas.
+
+## Use CTEs wisely
+
+Read about [complex queries on the relation object](iterating_tables_in_batches.md#complex-queries-on-the-relation-object) for considerations on how to use CTEs. We have found in some situations that CTEs can become problematic in use (similar to the n+1 problem above). In particular, hierarchical recursive CTE queries such as the CTE in [AuthorizedProjectsWorker](https://gitlab.com/gitlab-org/gitlab/-/issues/325688) are very difficult to optimize and don't scale. We should avoid them when implementing new features that require any kind of hierarchical structure.
+
+However, in many simpler cases, such as this [example](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/43242#note_61416277), CTEs can be quite effective as an optimization fence.
+
## Cached Queries
**Summary:** a merge request **should not** execute duplicated cached queries.
diff --git a/doc/development/usage_ping/dictionary.md b/doc/development/usage_ping/dictionary.md
index 67466a607cf..4709c18fcbe 100644
--- a/doc/development/usage_ping/dictionary.md
+++ b/doc/development/usage_ping/dictionary.md
@@ -5986,7 +5986,7 @@ Tiers: `free`, `premium`, `ultimate`
### `counts.web_ide_merge_requests`
-Count of Merge Requests created from Web IDE
+Count of merge requests created from Web IDE
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_all/20210216180246_web_ide_merge_requests.yml)
diff --git a/doc/user/project/settings/import_export.md b/doc/user/project/settings/import_export.md
index 7b5a0cbb377..6fa1b0aa368 100644
--- a/doc/user/project/settings/import_export.md
+++ b/doc/user/project/settings/import_export.md
@@ -39,8 +39,8 @@ Note the following:
The Importing GitLab version must be greater than or equal to the Exporting GitLab version.
- Imports will fail unless the import and export GitLab instances are
compatible as described in the [Version history](#version-history).
-- Exports are stored in a temporary [shared directory](../../../development/shared_files.md)
- and are deleted every 24 hours by a specific worker.
+- Exports are generated in your configured `shared_path`, a temporary [shared directory](../../../development/shared_files.md)
+ and are moved to your configured `uploads_directory`. Every 24 hours, a specific worker deletes these export files.
- Group members are exported as project members, as long as the user has
maintainer or administrator access to the group where the exported project lives.
- Project members with owner access will be imported as maintainers.
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 2c173ea73a8..aa62ceb14f8 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -2019,6 +2019,9 @@ msgstr ""
msgid "Add to tree"
msgstr ""
+msgid "Add trigger"
+msgstr ""
+
msgid "Add user(s) to the group:"
msgstr ""
@@ -4480,6 +4483,9 @@ msgstr ""
msgid "Authorization required"
msgstr ""
+msgid "Authorization token duration (minutes)"
+msgstr ""
+
msgid "Authorization was granted by entering your username and password in the application."
msgstr ""
@@ -16152,6 +16158,9 @@ msgstr ""
msgid "In case of pull mirroring, your user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
+msgid "In each example, replace %{code_start}TOKEN%{code_end} with the trigger token you generated and replace %{code_start}REF_NAME%{code_end} with the branch or tag name."
+msgstr ""
+
msgid "In progress"
msgstr ""
@@ -18424,10 +18433,7 @@ msgstr ""
msgid "LearnGitLab|Route code reviews to the right reviewers, every time."
msgstr ""
-msgid "LearnGitLab|Run a Security scan"
-msgstr ""
-
-msgid "LearnGitLab|Run a security scan"
+msgid "LearnGitLab|Run a Security scan using CI/CD"
msgstr ""
msgid "LearnGitLab|Save time by automating your integration and deployment tasks."
@@ -18463,6 +18469,9 @@ msgstr ""
msgid "LearnGitLab|Use your new GitLab workflow to deploy your application, monitor its health, and keep it secure:"
msgstr ""
+msgid "LearnGitlab|Trial only"
+msgstr ""
+
msgid "Leave"
msgstr ""
@@ -32381,6 +32390,9 @@ msgstr ""
msgid "To open Jaeger from GitLab to view tracing from the %{link} page, add a URL to your Jaeger server."
msgstr ""
+msgid "To pass variables to the triggered pipeline, add %{code_start}variables[VARIABLE]=VALUE%{code_end} to the API request."
+msgstr ""
+
msgid "To personalize your GitLab experience, we'd like to know a bit more about you. We won't share this information with anyone."
msgstr ""
@@ -32767,12 +32779,6 @@ msgstr ""
msgid "Triggerer"
msgstr ""
-msgid "Triggers|In each example, replace %{code_start}TOKEN%{code_end} with the trigger token you generated and replace %{code_start}REF_NAME%{code_end} with the branch or tag name."
-msgstr ""
-
-msgid "Triggers|To pass variables to the triggered pipeline, add %{code_start}variables[VARIABLE]=VALUE%{code_end} to the API request."
-msgstr ""
-
msgid "Troubleshoot and monitor your application with tracing"
msgstr ""
diff --git a/spec/frontend/issuable_show/mock_data.js b/spec/frontend/issuable_show/mock_data.js
index 9ecff705617..986d32b4982 100644
--- a/spec/frontend/issuable_show/mock_data.js
+++ b/spec/frontend/issuable_show/mock_data.js
@@ -32,6 +32,7 @@ export const mockIssuableShowProps = {
editFormVisible: false,
enableAutocomplete: true,
enableAutosave: true,
+ enableZenMode: true,
enableTaskList: true,
enableEdit: true,
showFieldTitle: false,
diff --git a/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_a_spec.js.snap b/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_a_spec.js.snap
index 1c1327e7a4e..cecaa3fc365 100644
--- a/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_a_spec.js.snap
+++ b/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_a_spec.js.snap
@@ -1,70 +1,308 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`Learn GitLab Design A should render the loading state 1`] = `
-<ul>
- <li>
- <span>
- Create or import a repository
- </span>
- </li>
- <li>
- <span>
- Invite your colleagues
- </span>
- </li>
- <li>
- <span>
- <gl-link-stub
- href="http://example.com/"
+exports[`Learn GitLab Design A renders correctly 1`] = `
+<div>
+ <div
+ class="row"
+ >
+ <div
+ class="gl-mb-7 gl-ml-5"
+ >
+ <h1
+ class="gl-font-size-h1"
>
- Set up CI/CD
- </gl-link-stub>
- </span>
- </li>
- <li>
- <span>
- <gl-link-stub
- href="http://example.com/"
+ Learn GitLab
+ </h1>
+
+ <p
+ class="gl-text-gray-700 gl-mb-0"
>
- Start a free Ultimate trial
- </gl-link-stub>
- </span>
- </li>
- <li>
- <span>
- <gl-link-stub
- href="http://example.com/"
+ Ready to get started with GitLab? Follow these steps to set up your workspace, plan and commit changes, and deploy your project.
+ </p>
+ </div>
+ </div>
+
+ <div
+ class="gl-mb-3"
+ >
+ <p
+ class="gl-text-gray-500 gl-mb-2"
+ data-testid="completion-percentage"
+ >
+ 25% completed
+ </p>
+
+ <div
+ class="progress"
+ max="8"
+ value="2"
+ >
+ <div
+ aria-valuemax="8"
+ aria-valuemin="0"
+ aria-valuenow="2"
+ class="progress-bar"
+ role="progressbar"
+ style="width: 25%;"
>
- Add code owners
- </gl-link-stub>
- </span>
- </li>
- <li>
- <span>
- <gl-link-stub
- href="http://example.com/"
+ <!---->
+ </div>
+ </div>
+ </div>
+
+ <div
+ class="row row-cols-1 row-cols-md-3 gl-mt-5"
+ >
+ <div
+ class="col gl-mb-6"
+ >
+ <div
+ class="gl-card gl-pt-0 learn-gitlab-section-card"
>
- Add merge request approval
- </gl-link-stub>
- </span>
- </li>
- <li>
- <span>
- <gl-link-stub
- href="http://example.com/"
+ <!---->
+
+ <div
+ class="gl-card-body"
+ >
+ <div
+ class="learn-gitlab-section-card-header"
+ >
+ <img
+ src="/assets/learn_gitlab/section_workspace.svg"
+ />
+
+ <h2
+ class="gl-font-lg gl-mb-3"
+ >
+ Set up your workspace
+ </h2>
+
+ <p
+ class="gl-text-gray-700 gl-mb-6"
+ >
+ Complete these tasks first so you can enjoy GitLab's features to their fullest:
+ </p>
+ </div>
+
+ <div
+ class="gl-mb-4"
+ >
+ <span
+ class="gl-text-green-500"
+ >
+ <svg
+ aria-hidden="true"
+ class="gl-icon s16"
+ data-testid="completed-icon"
+ >
+ <use
+ href="#check-circle-filled"
+ />
+ </svg>
+
+ Invite your colleagues
+
+ </span>
+
+ <!---->
+ </div>
+ <div
+ class="gl-mb-4"
+ >
+ <span
+ class="gl-text-green-500"
+ >
+ <svg
+ aria-hidden="true"
+ class="gl-icon s16"
+ data-testid="completed-icon"
+ >
+ <use
+ href="#check-circle-filled"
+ />
+ </svg>
+
+ Create or import a repository
+
+ </span>
+
+ <!---->
+ </div>
+ <div
+ class="gl-mb-4"
+ >
+ <span>
+ <a
+ class="gl-link"
+ href="http://example.com/"
+ >
+ Set up CI/CD
+ </a>
+ </span>
+
+ <!---->
+ </div>
+ <div
+ class="gl-mb-4"
+ >
+ <span>
+ <a
+ class="gl-link"
+ href="http://example.com/"
+ >
+ Start a free Ultimate trial
+ </a>
+ </span>
+
+ <!---->
+ </div>
+ <div
+ class="gl-mb-4"
+ >
+ <span>
+ <a
+ class="gl-link"
+ href="http://example.com/"
+ >
+ Add code owners
+ </a>
+ </span>
+
+ <span
+ class="gl-font-style-italic gl-text-gray-500"
+ data-testid="trial-only"
+ >
+
+ - Trial only
+
+ </span>
+ </div>
+ <div
+ class="gl-mb-4"
+ >
+ <span>
+ <a
+ class="gl-link"
+ href="http://example.com/"
+ >
+ Add merge request approval
+ </a>
+ </span>
+
+ <span
+ class="gl-font-style-italic gl-text-gray-500"
+ data-testid="trial-only"
+ >
+
+ - Trial only
+
+ </span>
+ </div>
+ </div>
+
+ <!---->
+ </div>
+ </div>
+ <div
+ class="col gl-mb-6"
+ >
+ <div
+ class="gl-card gl-pt-0 learn-gitlab-section-card"
>
- Submit a merge request
- </gl-link-stub>
- </span>
- </li>
- <li>
- <span>
- <gl-link-stub
- href="http://example.com/"
+ <!---->
+
+ <div
+ class="gl-card-body"
+ >
+ <div
+ class="learn-gitlab-section-card-header"
+ >
+ <img
+ src="/assets/learn_gitlab/section_plan.svg"
+ />
+
+ <h2
+ class="gl-font-lg gl-mb-3"
+ >
+ Plan and execute
+ </h2>
+
+ <p
+ class="gl-text-gray-700 gl-mb-6"
+ >
+ Create a workflow for your new workspace, and learn how GitLab features work together:
+ </p>
+ </div>
+
+ <div
+ class="gl-mb-4"
+ >
+ <span>
+ <a
+ class="gl-link"
+ href="http://example.com/"
+ >
+ Submit a merge request
+ </a>
+ </span>
+
+ <!---->
+ </div>
+ </div>
+
+ <!---->
+ </div>
+ </div>
+ <div
+ class="col gl-mb-6"
+ >
+ <div
+ class="gl-card gl-pt-0 learn-gitlab-section-card"
>
- Run a security scan
- </gl-link-stub>
- </span>
- </li>
-</ul>
+ <!---->
+
+ <div
+ class="gl-card-body"
+ >
+ <div
+ class="learn-gitlab-section-card-header"
+ >
+ <img
+ src="/assets/learn_gitlab/section_deploy.svg"
+ />
+
+ <h2
+ class="gl-font-lg gl-mb-3"
+ >
+ Deploy
+ </h2>
+
+ <p
+ class="gl-text-gray-700 gl-mb-6"
+ >
+ Use your new GitLab workflow to deploy your application, monitor its health, and keep it secure:
+ </p>
+ </div>
+
+ <div
+ class="gl-mb-4"
+ >
+ <span>
+ <a
+ class="gl-link"
+ href="http://example.com/"
+ >
+ Run a Security scan using CI/CD
+ </a>
+ </span>
+
+ <!---->
+ </div>
+ </div>
+
+ <!---->
+ </div>
+ </div>
+ </div>
+</div>
`;
diff --git a/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_b_spec.js.snap b/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_b_spec.js.snap
index dd899b93302..a78544fb14c 100644
--- a/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_b_spec.js.snap
+++ b/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_b_spec.js.snap
@@ -491,7 +491,7 @@ exports[`Learn GitLab Design B renders correctly 1`] = `
/>
<h6>
- Run a security scan
+ Run a Security scan using CI/CD
</h6>
<p
@@ -506,7 +506,7 @@ exports[`Learn GitLab Design B renders correctly 1`] = `
rel="noopener noreferrer"
target="_blank"
>
- Run a Security scan
+ Run a Security scan using CI/CD
</a>
</div>
</div>
diff --git a/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_section_card_spec.js.snap b/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_section_card_spec.js.snap
new file mode 100644
index 00000000000..831c027cd66
--- /dev/null
+++ b/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_section_card_spec.js.snap
@@ -0,0 +1,63 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Learn GitLab Section Card renders correctly 1`] = `
+<gl-card-stub
+ bodyclass=""
+ class="gl-pt-0 learn-gitlab-section-card"
+ footerclass=""
+ headerclass=""
+>
+ <div
+ class="learn-gitlab-section-card-header"
+ >
+ <img
+ src="/assets/learn_gitlab/section_workspace.svg"
+ />
+
+ <h2
+ class="gl-font-lg gl-mb-3"
+ >
+ Set up your workspace
+ </h2>
+
+ <p
+ class="gl-text-gray-700 gl-mb-6"
+ >
+ Complete these tasks first so you can enjoy GitLab's features to their fullest:
+ </p>
+ </div>
+
+ <learn-gitlab-section-link-stub
+ action="userAdded"
+ value="[object Object]"
+ />
+ <learn-gitlab-section-link-stub
+ action="gitWrite"
+ value="[object Object]"
+ />
+ <learn-gitlab-section-link-stub
+ action="mergeRequestCreated"
+ value="[object Object]"
+ />
+ <learn-gitlab-section-link-stub
+ action="securityScanEnabled"
+ value="[object Object]"
+ />
+ <learn-gitlab-section-link-stub
+ action="pipelineCreated"
+ value="[object Object]"
+ />
+ <learn-gitlab-section-link-stub
+ action="trialStarted"
+ value="[object Object]"
+ />
+ <learn-gitlab-section-link-stub
+ action="codeOwnersEnabled"
+ value="[object Object]"
+ />
+ <learn-gitlab-section-link-stub
+ action="requiredMrApprovalsEnabled"
+ value="[object Object]"
+ />
+</gl-card-stub>
+`;
diff --git a/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_a_spec.js b/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_a_spec.js
index 2154358de51..b226c046627 100644
--- a/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_a_spec.js
+++ b/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_a_spec.js
@@ -1,22 +1,38 @@
-import { shallowMount } from '@vue/test-utils';
+import { GlProgressBar } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
import LearnGitlabA from '~/pages/projects/learn_gitlab/components/learn_gitlab_a.vue';
import { testActions } from './mock_data';
describe('Learn GitLab Design A', () => {
let wrapper;
+ const createWrapper = () => {
+ wrapper = mount(LearnGitlabA, { propsData: { actions: testActions } });
+ };
+
+ beforeEach(() => {
+ createWrapper();
+ });
+
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
- const createWrapper = () => {
- wrapper = shallowMount(LearnGitlabA, { propsData: { actions: testActions } });
- };
+ it('renders correctly', () => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
- it('should render the loading state', () => {
- createWrapper();
+ it('renders the progress percentage', () => {
+ const text = wrapper.find('[data-testid="completion-percentage"]').text();
- expect(wrapper.element).toMatchSnapshot();
+ expect(text).toEqual('25% completed');
+ });
+
+ it('renders the progress bar with correct values', () => {
+ const progressBar = wrapper.find(GlProgressBar);
+
+ expect(progressBar.attributes('value')).toBe('2');
+ expect(progressBar.attributes('max')).toBe('8');
});
});
diff --git a/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_section_card_spec.js b/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_section_card_spec.js
new file mode 100644
index 00000000000..de6aca08235
--- /dev/null
+++ b/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_section_card_spec.js
@@ -0,0 +1,26 @@
+import { shallowMount } from '@vue/test-utils';
+import LearnGitlabSectionCard from '~/pages/projects/learn_gitlab/components/learn_gitlab_section_card.vue';
+import { testActions } from './mock_data';
+
+const defaultSection = 'workspace';
+
+describe('Learn GitLab Section Card', () => {
+ let wrapper;
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ const createWrapper = () => {
+ wrapper = shallowMount(LearnGitlabSectionCard, {
+ propsData: { section: defaultSection, actions: testActions },
+ });
+ };
+
+ it('renders correctly', () => {
+ createWrapper({ completed: false });
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+});
diff --git a/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_section_link_spec.js b/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_section_link_spec.js
new file mode 100644
index 00000000000..882d233a239
--- /dev/null
+++ b/spec/frontend/pages/projects/learn_gitlab/components/learn_gitlab_section_link_spec.js
@@ -0,0 +1,49 @@
+import { shallowMount } from '@vue/test-utils';
+import LearnGitlabSectionLink from '~/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue';
+
+const defaultAction = 'gitWrite';
+const defaultProps = {
+ title: 'Create Repository',
+ description: 'Some description',
+ url: 'https://example.com',
+ completed: false,
+};
+
+describe('Learn GitLab Section Link', () => {
+ let wrapper;
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ const createWrapper = (action = defaultAction, props = {}) => {
+ wrapper = shallowMount(LearnGitlabSectionLink, {
+ propsData: { action, value: { ...defaultProps, ...props } },
+ });
+ };
+
+ it('renders no icon when not completed', () => {
+ createWrapper(undefined, { completed: false });
+
+ expect(wrapper.find('[data-testid="completed-icon"]').exists()).toBe(false);
+ });
+
+ it('renders the completion icon when completed', () => {
+ createWrapper(undefined, { completed: true });
+
+ expect(wrapper.find('[data-testid="completed-icon"]').exists()).toBe(true);
+ });
+
+ it('renders no trial only when it is not required', () => {
+ createWrapper();
+
+ expect(wrapper.find('[data-testid="trial-only"]').exists()).toBe(false);
+ });
+
+ it('renders trial only when trial is required', () => {
+ createWrapper('codeOwnersEnabled');
+
+ expect(wrapper.find('[data-testid="trial-only"]').exists()).toBe(true);
+ });
+});
diff --git a/spec/helpers/ci/pipeline_editor_helper_spec.rb b/spec/helpers/ci/pipeline_editor_helper_spec.rb
index 7686983eb0f..a08517d0c57 100644
--- a/spec/helpers/ci/pipeline_editor_helper_spec.rb
+++ b/spec/helpers/ci/pipeline_editor_helper_spec.rb
@@ -20,4 +20,36 @@ RSpec.describe Ci::PipelineEditorHelper do
expect(subject).to be false
end
end
+
+ describe '#js_pipeline_editor_data' do
+ let(:project) { create(:project, :repository) }
+
+ before do
+ allow(helper)
+ .to receive(:namespace_project_new_merge_request_path)
+ .and_return('/mock/project/-/merge_requests/new')
+
+ allow(helper)
+ .to receive(:image_path)
+ .and_return('foo')
+ end
+
+ subject(:pipeline_editor_data) { helper.js_pipeline_editor_data(project) }
+
+ it 'returns pipeline editor data' do
+ expect(pipeline_editor_data).to eq({
+ "ci-config-path": project.ci_config_path_or_default,
+ "commit-sha" => project.commit.sha,
+ "default-branch" => project.default_branch,
+ "empty-state-illustration-path" => 'foo',
+ "initial-branch-name": nil,
+ "lint-help-page-path" => help_page_path('ci/lint', anchor: 'validate-basic-logic-and-syntax'),
+ "new-merge-request-path" => '/mock/project/-/merge_requests/new',
+ "project-path" => project.path,
+ "project-full-path" => project.full_path,
+ "project-namespace" => project.namespace.full_path,
+ "yml-help-page-path" => help_page_path('ci/yaml/README')
+ })
+ end
+ end
end
diff --git a/spec/helpers/projects/ci/pipeline_editor_helper_spec.rb b/spec/helpers/projects/ci/pipeline_editor_helper_spec.rb
new file mode 100644
index 00000000000..882b6548d64
--- /dev/null
+++ b/spec/helpers/projects/ci/pipeline_editor_helper_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ::Ci::PipelineEditorHelper do
+ let_it_be(:project) { create(:project, :public, :repository) }
+
+ describe '#js_pipeline_editor_data' do
+ before do
+ allow(helper).to receive(:namespace_project_new_merge_request_path).and_return('/mock/project/-/merge_requests/new')
+ end
+
+ subject { helper.js_pipeline_editor_data(project) }
+
+ it {
+ is_expected.to match({
+ "ci-config-path": project.ci_config_path_or_default,
+ "commit-sha" => project.commit.sha,
+ "default-branch" => project.default_branch,
+ "empty-state-illustration-path" => match_asset_path("/assets/illustrations/empty-state/empty-dag-md.svg"),
+ "initial-branch-name": nil,
+ "lint-help-page-path" => help_page_path('ci/lint', anchor: 'validate-basic-logic-and-syntax'),
+ "new-merge-request-path" => '/mock/project/-/merge_requests/new',
+ "project-path" => project.path,
+ "project-full-path" => project.full_path,
+ "project-namespace" => project.namespace.full_path,
+ "yml-help-page-path" => help_page_path('ci/yaml/README')
+ })
+ }
+ end
+end
diff --git a/spec/lib/api/helpers/caching_spec.rb b/spec/lib/api/helpers/caching_spec.rb
index 271f25b0de9..a8cd061e123 100644
--- a/spec/lib/api/helpers/caching_spec.rb
+++ b/spec/lib/api/helpers/caching_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe API::Helpers::Caching do
describe "#present_cached" do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
+
let(:presenter) { API::Entities::Todo }
let(:kwargs) do
diff --git a/spec/lib/api/helpers/packages_manager_clients_helpers_spec.rb b/spec/lib/api/helpers/packages_manager_clients_helpers_spec.rb
index 3c40859da21..e4c5002aa68 100644
--- a/spec/lib/api/helpers/packages_manager_clients_helpers_spec.rb
+++ b/spec/lib/api/helpers/packages_manager_clients_helpers_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe API::Helpers::PackagesManagerClientsHelpers do
let_it_be(:personal_access_token) { create(:personal_access_token) }
let_it_be(:username) { personal_access_token.user.username }
let_it_be(:helper) { Class.new.include(described_class).new }
+
let(:password) { personal_access_token.token }
let(:env) do
@@ -50,6 +51,7 @@ RSpec.describe API::Helpers::PackagesManagerClientsHelpers do
describe '#find_job_from_http_basic_auth' do
let_it_be(:user) { personal_access_token.user }
+
let(:job) { create(:ci_build, user: user, status: :running) }
let(:password) { job.token }
@@ -74,6 +76,7 @@ RSpec.describe API::Helpers::PackagesManagerClientsHelpers do
describe '#find_deploy_token_from_http_basic_auth' do
let_it_be(:deploy_token) { create(:deploy_token) }
+
let(:token) { deploy_token.token }
let(:username) { deploy_token.username }
let(:password) { token }
diff --git a/spec/lib/gitlab/github_import/importer/pull_request_merged_by_importer_spec.rb b/spec/lib/gitlab/github_import/importer/pull_request_merged_by_importer_spec.rb
index e42b6d89c30..01d9edf0ba1 100644
--- a/spec/lib/gitlab/github_import/importer/pull_request_merged_by_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/pull_request_merged_by_importer_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe Gitlab::GithubImport::Importer::PullRequestMergedByImporter, :clean_gitlab_redis_cache do
let_it_be(:merge_request) { create(:merged_merge_request) }
+
let(:project) { merge_request.project }
let(:merged_at) { Time.new(2017, 1, 1, 12, 00).utc }
let(:client_double) { double(user: double(id: 999, login: 'merger', email: 'merger@email.com')) }
diff --git a/spec/lib/gitlab/github_import/importer/pull_request_review_importer_spec.rb b/spec/lib/gitlab/github_import/importer/pull_request_review_importer_spec.rb
index 290f3f51202..5002e0384f3 100644
--- a/spec/lib/gitlab/github_import/importer/pull_request_review_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/pull_request_review_importer_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestReviewImporter, :clean
using RSpec::Parameterized::TableSyntax
let_it_be(:merge_request) { create(:merge_request) }
+
let(:project) { merge_request.project }
let(:client_double) { double(user: double(id: 999, login: 'author', email: 'author@email.com')) }
let(:submitted_at) { Time.new(2017, 1, 1, 12, 00).utc }
diff --git a/spec/lib/gitlab/github_import/milestone_finder_spec.rb b/spec/lib/gitlab/github_import/milestone_finder_spec.rb
index 5da45b1897f..fe8652eb5a2 100644
--- a/spec/lib/gitlab/github_import/milestone_finder_spec.rb
+++ b/spec/lib/gitlab/github_import/milestone_finder_spec.rb
@@ -5,6 +5,7 @@ require 'spec_helper'
RSpec.describe Gitlab::GithubImport::MilestoneFinder, :clean_gitlab_redis_cache do
let_it_be(:project) { create(:project) }
let_it_be(:milestone) { create(:milestone, project: project) }
+
let(:finder) { described_class.new(project) }
describe '#id_for' do
diff --git a/spec/lib/gitlab/import_export/design_repo_saver_spec.rb b/spec/lib/gitlab/import_export/design_repo_saver_spec.rb
index 5501e3dee5a..fd3539ab99c 100644
--- a/spec/lib/gitlab/import_export/design_repo_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/design_repo_saver_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe Gitlab::ImportExport::DesignRepoSaver do
describe 'bundle a design Git repo' do
let_it_be(:user) { create(:user) }
let_it_be(:design) { create(:design, :with_file, versions_count: 1) }
+
let!(:project) { create(:project, :design_repo) }
let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
let(:shared) { project.import_export_shared }
diff --git a/spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb b/spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb
index d084b9d7f7e..29b192de809 100644
--- a/spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb
+++ b/spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb
@@ -12,6 +12,7 @@ RSpec.describe Gitlab::ImportExport::FastHashSerializer do
let_it_be(:user) { create(:user) }
let_it_be(:project) { setup_project }
+
let(:shared) { project.import_export_shared }
let(:reader) { Gitlab::ImportExport::Reader.new(shared: shared) }
let(:tree) { reader.project_tree }
diff --git a/spec/lib/gitlab/import_export/project/export_task_spec.rb b/spec/lib/gitlab/import_export/project/export_task_spec.rb
index 1048379a5d6..7fcd2187a90 100644
--- a/spec/lib/gitlab/import_export/project/export_task_spec.rb
+++ b/spec/lib/gitlab/import_export/project/export_task_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe Gitlab::ImportExport::Project::ExportTask do
let_it_be(:username) { 'root' }
let(:namespace_path) { username }
let_it_be(:user) { create(:user, username: username) }
+
let(:measurement_enabled) { false }
let(:file_path) { 'spec/fixtures/gitlab/import_export/test_project_export.tar.gz' }
let(:project) { create(:project, creator: user, namespace: user.namespace) }
diff --git a/spec/lib/gitlab/import_export/project/tree_saver_spec.rb b/spec/lib/gitlab/import_export/project/tree_saver_spec.rb
index 50494433c5d..fd6c66a10a7 100644
--- a/spec/lib/gitlab/import_export/project/tree_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/project/tree_saver_spec.rb
@@ -267,6 +267,7 @@ RSpec.describe Gitlab::ImportExport::Project::TreeSaver do
describe '#saves project tree' do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
+
let(:project) { setup_project }
let(:full_path) do
if ndjson_enabled
diff --git a/spec/lib/gitlab/import_export/repo_saver_spec.rb b/spec/lib/gitlab/import_export/repo_saver_spec.rb
index 52001e778d6..73e0e0a08b9 100644
--- a/spec/lib/gitlab/import_export/repo_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/repo_saver_spec.rb
@@ -5,6 +5,7 @@ require 'spec_helper'
RSpec.describe Gitlab::ImportExport::RepoSaver do
describe 'bundle a project Git repo' do
let_it_be(:user) { create(:user) }
+
let!(:project) { create(:project, :repository) }
let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
let(:shared) { project.import_export_shared }
diff --git a/spec/lib/gitlab/import_export/snippet_repo_saver_spec.rb b/spec/lib/gitlab/import_export/snippet_repo_saver_spec.rb
index 323ed9a746e..9f3e8d2fa86 100644
--- a/spec/lib/gitlab/import_export/snippet_repo_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/snippet_repo_saver_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe Gitlab::ImportExport::SnippetRepoSaver do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, namespace: user.namespace) }
let_it_be(:snippet) { create(:project_snippet, :repository, project: project, author: user) }
+
let(:shared) { project.import_export_shared }
let(:bundler) { described_class.new(project: project, shared: shared, repository: snippet.repository) }
let(:bundle_path) { ::Gitlab::ImportExport.snippets_repo_bundle_path(shared.export_path) }
diff --git a/spec/lib/gitlab/import_export/snippets_repo_saver_spec.rb b/spec/lib/gitlab/import_export/snippets_repo_saver_spec.rb
index 8507c46ec83..aa284c60e73 100644
--- a/spec/lib/gitlab/import_export/snippets_repo_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/snippets_repo_saver_spec.rb
@@ -5,6 +5,7 @@ require 'spec_helper'
RSpec.describe Gitlab::ImportExport::SnippetsRepoSaver do
describe 'bundle a project Git repo' do
let_it_be(:user) { create(:user) }
+
let!(:project) { create(:project) }
let(:shared) { project.import_export_shared }
let(:bundler) { described_class.new(current_user: user, project: project, shared: shared) }
diff --git a/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb b/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb
index 540f90e7804..c936d2bc27d 100644
--- a/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe Gitlab::ImportExport::WikiRepoSaver do
describe 'bundle a wiki Git repo' do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :wiki_repo) }
+
let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
let(:shared) { project.import_export_shared }
let(:wiki_bundler) { described_class.new(exportable: project, shared: shared) }
diff --git a/spec/migrations/remove_records_without_group_from_webhooks_table_spec.rb b/spec/migrations/remove_records_without_group_from_webhooks_table_spec.rb
new file mode 100644
index 00000000000..a28ca12a10d
--- /dev/null
+++ b/spec/migrations/remove_records_without_group_from_webhooks_table_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!
+require Rails.root.join('db', 'migrate', '20210325092215_add_not_valid_foreign_key_to_group_hooks.rb')
+
+RSpec.describe RemoveRecordsWithoutGroupFromWebhooksTable, schema: 20210330091751 do
+ let(:web_hooks) { table(:web_hooks) }
+ let(:groups) { table(:namespaces) }
+
+ before do
+ group = groups.create!(name: 'gitlab', path: 'gitlab-org')
+ web_hooks.create!(group_id: group.id, type: 'GroupHook')
+ web_hooks.create!(group_id: nil)
+
+ AddNotValidForeignKeyToGroupHooks.new.down
+ web_hooks.create!(group_id: non_existing_record_id, type: 'GroupHook')
+ AddNotValidForeignKeyToGroupHooks.new.up
+ end
+
+ it 'removes group hooks where the referenced group does not exist', :aggregate_failures do
+ expect { RemoveRecordsWithoutGroupFromWebhooksTable.new.up }.to change { web_hooks.count }.by(-1)
+ expect(web_hooks.where.not(group_id: groups.select(:id)).count).to eq(0)
+ expect(web_hooks.where.not(group_id: nil).count).to eq(1)
+ end
+end
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 736b2ad4b99..958fe8d9455 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -2282,6 +2282,35 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
)
end
end
+
+ context 'when method is scoped' do
+ let!(:commit_123_ref_master_parent_pipeline) do
+ create(
+ :ci_pipeline,
+ sha: '123',
+ ref: 'master',
+ project: project
+ )
+ end
+
+ let!(:commit_123_ref_master_child_pipeline) do
+ create(
+ :ci_pipeline,
+ sha: '123',
+ ref: 'master',
+ project: project,
+ child_of: commit_123_ref_master_parent_pipeline
+ )
+ end
+
+ it 'returns the latest pipeline after applying the scope' do
+ result = described_class.ci_sources.latest_pipeline_per_commit(%w[123], 'master')
+
+ expect(result).to match(
+ '123' => commit_123_ref_master_parent_pipeline
+ )
+ end
+ end
end
describe '.latest_successful_ids_per_project' do
diff --git a/spec/services/ci/abort_pipelines_service_spec.rb b/spec/services/ci/abort_pipelines_service_spec.rb
index 21c95606b51..b0f98e1266d 100644
--- a/spec/services/ci/abort_pipelines_service_spec.rb
+++ b/spec/services/ci/abort_pipelines_service_spec.rb
@@ -45,6 +45,22 @@ RSpec.describe Ci::AbortPipelinesService do
expect { described_class.new.execute(project_pipelines) }.not_to exceed_query_limit(control_count)
end
+
+ context 'with live build logs' do
+ before do
+ create(:ci_build_trace_chunk, build: cancelable_build)
+ end
+
+ it 'makes canceled builds with stale trace visible' do
+ expect(Ci::Build.with_stale_live_trace.count).to eq 0
+
+ travel_to(2.days.ago) do
+ described_class.new.execute(project.all_pipelines)
+ end
+
+ expect(Ci::Build.with_stale_live_trace.count).to eq 1
+ end
+ end
end
context 'with user pipelines' do