diff --git a/.gitlab/issue_templates/Feature Flag Roll Out.md b/.gitlab/issue_templates/Feature Flag Roll Out.md index fe263b932ae..ea3bd07f228 100644 --- a/.gitlab/issue_templates/Feature Flag Roll Out.md +++ b/.gitlab/issue_templates/Feature Flag Roll Out.md @@ -37,7 +37,7 @@ If applicable, any groups/projects that are happy to have this feature turned on - [ ] Enable on GitLab.com for individual groups/projects listed above and verify behaviour (`/chatops run feature set --project=gitlab-org/gitlab feature_name true`) - [ ] Coordinate a time to enable the flag with the SRE oncall and release managers - In `#production` mention `@sre-oncall` and `@release-managers`. Once an SRE on call and Release Manager on call confirm, you can proceed with the rollout -- [ ] Announce on the issue an estimated time this will be enabled on GitLab.com +- [ ] Announce on the issue an estimated time this will be enabled on GitLab.com. **Note**: Once a feature rollout has started, it is not necessary to inform `@sre-oncall`/`@release-managers` at each stage of the gradual rollout. - [ ] Enable on GitLab.com by running chatops command in `#production` (`/chatops run feature set feature_name true`) - [ ] Cross post chatops Slack command to `#support_gitlab-com` ([more guidance when this is necessary in the dev docs](https://docs.gitlab.com/ee/development/feature_flags/controls.html#where-to-run-commands)) and in your team channel - [ ] Announce on the issue that the flag has been enabled diff --git a/.gitlab/merge_request_templates/Quarantine End to End Test.md b/.gitlab/merge_request_templates/Quarantine End to End Test.md new file mode 100644 index 00000000000..cf0a89284ae --- /dev/null +++ b/.gitlab/merge_request_templates/Quarantine End to End Test.md @@ -0,0 +1,44 @@ +## What does this MR do? + + + + +### E2E Test Failure issue(s) + + + + +### Check-list + +- [ ] General code guidelines check-list + - [ ] [Code review guidelines](https://docs.gitlab.com/ee/development/code_review.html) + - [ ] [Style guides](https://docs.gitlab.com/ee/development/contributing/style_guides.html) +- [ ] Quarantine test check-list + - [ ] Follow the [Quarantining Tests guide](https://about.gitlab.com/handbook/engineering/quality/guidelines/debugging-qa-test-failures/#quarantining-tests). + - [ ] Confirm the test has a [`quarantine:` tag with the specified quarantine type](https://about.gitlab.com/handbook/engineering/quality/guidelines/debugging-qa-test-failures/#quarantined-test-types). + - [ ] 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. + + +/label ~"Quality" ~"QA" ~"feature" ~"feature::maintenance" + + +/label ~"Pick into auto-deploy" ~"priority::1" ~"severity::1" + + +/label ~devops:: + + +/milestone % diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 6916fad7b04..b9d0aed82e8 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -eb6ecf6f96946849761c1fcdcaf0bda15fc000f9 +a88ceb12912277ab1e07ca325792df40550e6bcc diff --git a/app/assets/javascripts/behaviors/markdown/render_mermaid.js b/app/assets/javascripts/behaviors/markdown/render_mermaid.js index 0cb13815c7e..5b5148a850b 100644 --- a/app/assets/javascripts/behaviors/markdown/render_mermaid.js +++ b/app/assets/javascripts/behaviors/markdown/render_mermaid.js @@ -1,6 +1,7 @@ import $ from 'jquery'; import { once } from 'lodash'; import { deprecatedCreateFlash as flash } from '~/flash'; +import { darkModeEnabled } from '~/lib/utils/color_utils'; import { __, sprintf } from '~/locale'; // Renders diagrams and flowcharts from text using Mermaid in any element with the @@ -27,37 +28,34 @@ let renderedMermaidBlocks = 0; let mermaidModule = {}; +export function initMermaid(mermaid) { + let theme = 'neutral'; + + if (darkModeEnabled()) { + theme = 'dark'; + } + + mermaid.initialize({ + // mermaid core options + mermaid: { + startOnLoad: false, + }, + // mermaidAPI options + theme, + flowchart: { + useMaxWidth: true, + htmlLabels: false, + }, + securityLevel: 'strict', + }); + + return mermaid; +} + function importMermaidModule() { return import(/* webpackChunkName: 'mermaid' */ 'mermaid') .then((mermaid) => { - let theme = 'neutral'; - const ideDarkThemes = ['dark', 'solarized-dark', 'monokai']; - - if ( - ideDarkThemes.includes(window.gon?.user_color_scheme) && - // if on the Web IDE page - document.querySelector('.ide') - ) { - theme = 'dark'; - } - - mermaid.initialize({ - // mermaid core options - mermaid: { - startOnLoad: false, - }, - // mermaidAPI options - theme, - flowchart: { - useMaxWidth: true, - htmlLabels: false, - }, - securityLevel: 'strict', - }); - - mermaidModule = mermaid; - - return mermaid; + mermaidModule = initMermaid(mermaid); }) .catch((err) => { flash(sprintf(__("Can't load mermaid module: %{err}"), { err })); diff --git a/app/assets/javascripts/lib/utils/color_utils.js b/app/assets/javascripts/lib/utils/color_utils.js index ff176f11867..da2c10076b1 100644 --- a/app/assets/javascripts/lib/utils/color_utils.js +++ b/app/assets/javascripts/lib/utils/color_utils.js @@ -43,3 +43,15 @@ export const validateHexColor = (color = '') => { return /^#([0-9A-F]{3}){1,2}$/i.test(color); }; + +export function darkModeEnabled() { + const ideDarkThemes = ['dark', 'solarized-dark', 'monokai']; + + // eslint-disable-next-line @gitlab/require-i18n-strings + const isWebIde = document.body.dataset.page.startsWith('ide:'); + + if (isWebIde) { + return ideDarkThemes.includes(window.gon?.user_color_scheme); + } + return document.body.classList.contains('gl-dark'); +} diff --git a/app/finders/alert_management/http_integrations_finder.rb b/app/finders/alert_management/http_integrations_finder.rb index 9f511be0ace..5d4c9b6fbe3 100644 --- a/app/finders/alert_management/http_integrations_finder.rb +++ b/app/finders/alert_management/http_integrations_finder.rb @@ -27,7 +27,7 @@ module AlertManagement first_id = project.alert_management_http_integrations .ordered_by_id .select(:id) - .at_most(1) + .limit(1) @collection = collection.id_in(first_id) end diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index 93776503dd6..42e4844cc8d 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -135,6 +135,8 @@ module CommitsHelper end def cherry_pick_projects_data(project) + return [] unless Feature.enabled?(:pick_into_project, project, default_enabled: :yaml) + target_projects(project).map do |project| { id: project.id.to_s, diff --git a/app/models/application_record.rb b/app/models/application_record.rb index 44d1b6cf907..c9ae185583d 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -42,10 +42,6 @@ class ApplicationRecord < ActiveRecord::Base false end - def self.at_most(count) - limit(count) - end - def self.safe_find_or_create_by!(*args, &block) safe_find_or_create_by(*args, &block).tap do |record| raise ActiveRecord::RecordNotFound unless record.present? diff --git a/app/services/merge_requests/retarget_chain_service.rb b/app/services/merge_requests/retarget_chain_service.rb index f24d67243c9..e8101e447d2 100644 --- a/app/services/merge_requests/retarget_chain_service.rb +++ b/app/services/merge_requests/retarget_chain_service.rb @@ -17,7 +17,7 @@ module MergeRequests .opened .by_target_branch(merge_request.source_branch) .preload_source_project - .at_most(MAX_RETARGET_MERGE_REQUESTS) + .limit(MAX_RETARGET_MERGE_REQUESTS) other_merge_requests.find_each do |other_merge_request| # Update only MRs on projects that we have access to diff --git a/app/views/projects/imports/new.html.haml b/app/views/projects/imports/new.html.haml index 3064b8bf873..e2d8791b5d2 100644 --- a/app/views/projects/imports/new.html.haml +++ b/app/views/projects/imports/new.html.haml @@ -16,4 +16,4 @@ = render "shared/import_form", f: f .form-actions - = f.submit 'Start import', class: "gl-button btn btn-success" + = f.submit 'Start import', class: "gl-button btn btn-confirm" diff --git a/changelogs/unreleased/btn-confirm-project-imports.yml b/changelogs/unreleased/btn-confirm-project-imports.yml new file mode 100644 index 00000000000..2c0b792f6a1 --- /dev/null +++ b/changelogs/unreleased/btn-confirm-project-imports.yml @@ -0,0 +1,5 @@ +--- +title: Move from btn-success to btn-confirm in imports directory +merge_request: 56336 +author: Yogi (@yo) +type: changed diff --git a/changelogs/unreleased/psi-dark-mermaid.yml b/changelogs/unreleased/psi-dark-mermaid.yml new file mode 100644 index 00000000000..49739dc1e0d --- /dev/null +++ b/changelogs/unreleased/psi-dark-mermaid.yml @@ -0,0 +1,5 @@ +--- +title: Fix mermaid diagrams in dark mode +merge_request: 56183 +author: +type: fixed diff --git a/doc/development/fe_guide/vue3_migration.md b/doc/development/fe_guide/vue3_migration.md index ee25e97ab6e..d06e93da0f3 100644 --- a/doc/development/fe_guide/vue3_migration.md +++ b/doc/development/fe_guide/vue3_migration.md @@ -6,6 +6,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w # Migration to Vue 3 +Preparations for a Vue 3 migration are tracked in epic [&3174](https://gitlab.com/groups/gitlab-org/-/epics/3174) + In order to prepare for the eventual migration to Vue 3.x, we should be wary about adding the following features to the codebase: ## Vue filters diff --git a/doc/development/usage_ping/dictionary.md b/doc/development/usage_ping/dictionary.md index 47d6a39d625..2ce3a8be04c 100644 --- a/doc/development/usage_ping/dictionary.md +++ b/doc/development/usage_ping/dictionary.md @@ -9836,6 +9836,78 @@ Status: `implemented` Tiers: `premium`, `ultimate` +### `redis_hll_counters.epics_usage.g_project_management_users_setting_epic_start_date_as_fixed_monthly` + +Counts of MAU setting epic start date as fixed + +[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210315055624_g_project_management_users_setting_epic_start_date_as_fixed_monthly.yml) + +Group: `group:product planning` + +Status: `implemented` + +Tiers: `premium`, `ultimate` + +### `redis_hll_counters.epics_usage.g_project_management_users_setting_epic_start_date_as_fixed_weekly` + +Counts of WAU setting epic start date as fixed + +[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210315054905_g_project_management_users_setting_epic_start_date_as_fixed_weekly.yml) + +Group: `group:product planning` + +Status: `implemented` + +Tiers: `premium`, `ultimate` + +### `redis_hll_counters.epics_usage.g_project_management_users_setting_epic_start_date_as_inherited_monthly` + +Counts of MAU setting epic start date as inherited + +[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210315055439_g_project_management_users_setting_epic_start_date_as_inherited_monthly.yml) + +Group: `group:product planning` + +Status: `implemented` + +Tiers: `premium`, `ultimate` + +### `redis_hll_counters.epics_usage.g_project_management_users_setting_epic_start_date_as_inherited_weekly` + +Counts of WAU setting epic start date as inherited + +[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210315055342_g_project_management_users_setting_epic_start_date_as_inherited_weekly.yml) + +Group: `group:product planning` + +Status: `implemented` + +Tiers: `premium`, `ultimate` + +### `redis_hll_counters.epics_usage.g_project_management_users_updating_epic_notes_monthly` + +Counts of MAU updating epic notes + +[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_28d/20210314234202_g_project_management_users_updating_epic_notes_monthly.yml) + +Group: `group:product planning` + +Status: `implemented` + +Tiers: `premium`, `ultimate` + +### `redis_hll_counters.epics_usage.g_project_management_users_updating_epic_notes_weekly` + +Counts of WAU updating epic notes + +[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_7d/20210314234041_g_project_management_users_updating_epic_notes_weekly.yml) + +Group: `group:product planning` + +Status: `implemented` + +Tiers: `premium`, `ultimate` + ### `redis_hll_counters.ide_edit.g_edit_by_sfe_monthly` Missing description diff --git a/lefthook.yml b/lefthook.yml index 8c03a51a4c8..daab6e7f4a0 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -32,7 +32,7 @@ pre-push: tags: backend style files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD glob: '*.rb' - run: bundle exec rubocop --parallel --force-exclusion {files} + run: REVEAL_RUBOCOP_TODO=0 bundle exec rubocop --parallel --force-exclusion {files} vale: # Requires Vale: https://docs.gitlab.com/ee/development/documentation/#install-linters tags: documentation style files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD diff --git a/lib/gitlab/updated_notes_paginator.rb b/lib/gitlab/updated_notes_paginator.rb index 3d3d0e5bf9e..511d6dccf7c 100644 --- a/lib/gitlab/updated_notes_paginator.rb +++ b/lib/gitlab/updated_notes_paginator.rb @@ -38,7 +38,7 @@ module Gitlab def fetch_page(relation) relation = relation.by_updated_at - notes = relation.at_most(LIMIT + 1).to_a + notes = relation.limit(LIMIT + 1).to_a return [notes, false] unless notes.size > LIMIT diff --git a/lib/gitlab/usage_data_counters/known_events/epic_events.yml b/lib/gitlab/usage_data_counters/known_events/epic_events.yml index 4b1b12bb58c..7cd2a72d8ca 100644 --- a/lib/gitlab/usage_data_counters/known_events/epic_events.yml +++ b/lib/gitlab/usage_data_counters/known_events/epic_events.yml @@ -9,8 +9,26 @@ aggregation: daily feature_flag: track_epics_activity +- name: g_project_management_users_updating_epic_notes + category: epics_usage + redis_slot: project_management + aggregation: daily + feature_flag: track_epics_activity + - name: g_project_management_users_destroying_epic_notes category: epics_usage redis_slot: project_management aggregation: daily feature_flag: track_epics_activity + +- name: g_project_management_users_setting_epic_start_date_as_fixed + category: epics_usage + redis_slot: project_management + aggregation: daily + feature_flag: track_epics_activity + +- name: g_project_management_users_setting_epic_start_date_as_inherited + category: epics_usage + redis_slot: project_management + aggregation: daily + feature_flag: track_epics_activity diff --git a/spec/frontend/behaviors/markdown/render_mermaid_spec.js b/spec/frontend/behaviors/markdown/render_mermaid_spec.js new file mode 100644 index 00000000000..51a345cab0e --- /dev/null +++ b/spec/frontend/behaviors/markdown/render_mermaid_spec.js @@ -0,0 +1,25 @@ +import { initMermaid } from '~/behaviors/markdown/render_mermaid'; +import * as ColorUtils from '~/lib/utils/color_utils'; + +describe('Render mermaid diagrams for Gitlab Flavoured Markdown', () => { + it.each` + darkMode | expectedTheme + ${false} | ${'neutral'} + ${true} | ${'dark'} + `('is $darkMode $expectedTheme', async ({ darkMode, expectedTheme }) => { + jest.spyOn(ColorUtils, 'darkModeEnabled').mockImplementation(() => darkMode); + + const mermaid = { + initialize: jest.fn(), + }; + + await initMermaid(mermaid); + + expect(mermaid.initialize).toHaveBeenCalledTimes(1); + expect(mermaid.initialize).toHaveBeenCalledWith( + expect.objectContaining({ + theme: expectedTheme, + }), + ); + }); +}); diff --git a/spec/frontend/lib/utils/color_utils_spec.js b/spec/frontend/lib/utils/color_utils_spec.js index 8c846abd77f..c6b88b2957c 100644 --- a/spec/frontend/lib/utils/color_utils_spec.js +++ b/spec/frontend/lib/utils/color_utils_spec.js @@ -1,4 +1,9 @@ -import { textColorForBackground, hexToRgb, validateHexColor } from '~/lib/utils/color_utils'; +import { + textColorForBackground, + hexToRgb, + validateHexColor, + darkModeEnabled, +} from '~/lib/utils/color_utils'; describe('Color utils', () => { describe('Converting hex code to rgb', () => { @@ -47,4 +52,24 @@ describe('Color utils', () => { expect(validateHexColor(color)).toEqual(output); }); }); + + describe('darkModeEnabled', () => { + it.each` + page | bodyClass | ideTheme | expected + ${'ide:index'} | ${'gl-dark'} | ${'monokai-light'} | ${false} + ${'ide:index'} | ${'ui-light'} | ${'monokai'} | ${true} + ${'groups:issues:index'} | ${'ui-light'} | ${'monokai'} | ${false} + ${'groups:issues:index'} | ${'gl-dark'} | ${'monokai-light'} | ${true} + `( + 'is $expected on $page with $bodyClass body class and $ideTheme IDE theme', + async ({ page, bodyClass, ideTheme, expected }) => { + document.body.outerHTML = ``; + window.gon = { + user_color_scheme: ideTheme, + }; + + expect(darkModeEnabled()).toBe(expected); + }, + ); + }); }); diff --git a/spec/helpers/commits_helper_spec.rb b/spec/helpers/commits_helper_spec.rb index 397751b07af..2a8e2e04947 100644 --- a/spec/helpers/commits_helper_spec.rb +++ b/spec/helpers/commits_helper_spec.rb @@ -257,5 +257,15 @@ RSpec.describe CommitsHelper do { id: forked_project.id.to_s, name: forked_project.full_path, refsUrl: refs_project_path(forked_project) } ]) end + + context 'pick_into_project is disabled' do + before do + stub_feature_flags(pick_into_project: false) + end + + it 'does not calculate target projects' do + expect(helper.cherry_pick_projects_data(project)).to eq([]) + end + end end end diff --git a/spec/models/application_record_spec.rb b/spec/models/application_record_spec.rb index 6a0f2290b4c..107f707ccd9 100644 --- a/spec/models/application_record_spec.rb +++ b/spec/models/application_record_spec.rb @@ -93,13 +93,6 @@ RSpec.describe ApplicationRecord do end end - describe '.at_most' do - it 'limits the number of records returned' do - create_list(:user, 3) - expect(User.at_most(2).count).to eq(2) - end - end - describe '.where_exists' do it 'produces a WHERE EXISTS query' do user = create(:user)