diff --git a/app/assets/javascripts/create_merge_request_dropdown.js b/app/assets/javascripts/create_merge_request_dropdown.js index 35176c19f69..dcc98f86410 100644 --- a/app/assets/javascripts/create_merge_request_dropdown.js +++ b/app/assets/javascripts/create_merge_request_dropdown.js @@ -1,4 +1,3 @@ -/* eslint-disable no-new */ import { debounce } from 'lodash'; import { init as initConfidentialMergeRequest, @@ -8,7 +7,7 @@ import { import confidentialMergeRequestState from './confidential_merge_request/state'; import DropLab from './droplab/drop_lab'; import ISetter from './droplab/plugins/input_setter'; -import { deprecatedCreateFlash as Flash } from './flash'; +import createFlash from './flash'; import axios from './lib/utils/axios_utils'; import { __, sprintf } from './locale'; @@ -132,7 +131,9 @@ export default class CreateMergeRequestDropdown { .catch(() => { this.unavailable(); this.disable(); - Flash(__('Failed to check related branches.')); + createFlash({ + message: __('Failed to check related branches.'), + }); }); } @@ -147,7 +148,11 @@ export default class CreateMergeRequestDropdown { this.branchCreated = true; window.location.href = data.url; }) - .catch(() => Flash(__('Failed to create a branch for this issue. Please try again.'))); + .catch(() => + createFlash({ + message: __('Failed to create a branch for this issue. Please try again.'), + }), + ); } createMergeRequest() { @@ -163,7 +168,11 @@ export default class CreateMergeRequestDropdown { this.mergeRequestCreated = true; window.location.href = data.url; }) - .catch(() => Flash(__('Failed to create Merge Request. Please try again.'))); + .catch(() => + createFlash({ + message: __('Failed to create Merge Request. Please try again.'), + }), + ); } disable() { @@ -256,7 +265,9 @@ export default class CreateMergeRequestDropdown { .catch(() => { this.unavailable(); this.disable(); - new Flash(__('Failed to get ref.')); + createFlash({ + message: __('Failed to get ref.'), + }); this.isGettingRef = false; diff --git a/app/assets/javascripts/filtered_search/dropdown_emoji.js b/app/assets/javascripts/filtered_search/dropdown_emoji.js index a22430833a3..91af3a6b812 100644 --- a/app/assets/javascripts/filtered_search/dropdown_emoji.js +++ b/app/assets/javascripts/filtered_search/dropdown_emoji.js @@ -1,7 +1,7 @@ import { __ } from '~/locale'; import Ajax from '../droplab/plugins/ajax'; import Filter from '../droplab/plugins/filter'; -import { deprecatedCreateFlash as Flash } from '../flash'; +import createFlash from '../flash'; import DropdownUtils from './dropdown_utils'; import FilteredSearchDropdown from './filtered_search_dropdown'; @@ -14,9 +14,9 @@ export default class DropdownEmoji extends FilteredSearchDropdown { method: 'setData', loadingTemplate: this.loadingTemplate, onError() { - /* eslint-disable no-new */ - new Flash(__('An error occurred fetching the dropdown data.')); - /* eslint-enable no-new */ + createFlash({ + message: __('An error occurred fetching the dropdown data.'), + }); }, }, Filter: { diff --git a/app/assets/javascripts/filtered_search/dropdown_non_user.js b/app/assets/javascripts/filtered_search/dropdown_non_user.js index 4df1120f169..93051b00756 100644 --- a/app/assets/javascripts/filtered_search/dropdown_non_user.js +++ b/app/assets/javascripts/filtered_search/dropdown_non_user.js @@ -1,7 +1,7 @@ import { __ } from '~/locale'; import Ajax from '../droplab/plugins/ajax'; import Filter from '../droplab/plugins/filter'; -import { deprecatedCreateFlash as Flash } from '../flash'; +import createFlash from '../flash'; import DropdownUtils from './dropdown_utils'; import FilteredSearchDropdown from './filtered_search_dropdown'; @@ -17,9 +17,9 @@ export default class DropdownNonUser extends FilteredSearchDropdown { loadingTemplate: this.loadingTemplate, preprocessing, onError() { - /* eslint-disable no-new */ - new Flash(__('An error occurred fetching the dropdown data.')); - /* eslint-enable no-new */ + createFlash({ + message: __('An error occurred fetching the dropdown data.'), + }); }, }, Filter: { diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js b/app/assets/javascripts/filtered_search/filtered_search_manager.js index 69d19074cd0..d0996c9200b 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_manager.js +++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js @@ -10,7 +10,7 @@ import { DOWN_KEY_CODE, } from '~/lib/utils/keycodes'; import { __ } from '~/locale'; -import { deprecatedCreateFlash as Flash } from '../flash'; +import createFlash from '../flash'; import { addClassIfElementExists } from '../lib/utils/dom_utils'; import { visitUrl } from '../lib/utils/url_utility'; import FilteredSearchContainer from './container'; @@ -92,8 +92,9 @@ export default class FilteredSearchManager { .fetch() .catch((error) => { if (error.name === 'RecentSearchesServiceError') return undefined; - // eslint-disable-next-line no-new - new Flash(__('An error occurred while parsing recent searches')); + createFlash({ + message: __('An error occurred while parsing recent searches'), + }); // Gracefully fail to empty array return []; }) diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index 8ed40f36103..076f9eac696 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -22,7 +22,7 @@ import syntaxHighlight from '~/syntax_highlight'; import Autosave from './autosave'; import loadAwardsHandler from './awards_handler'; import CommentTypeToggle from './comment_type_toggle'; -import { deprecatedCreateFlash as Flash } from './flash'; +import createFlash from './flash'; import { defaultAutocompleteConfig } from './gfm_auto_complete'; import GLForm from './gl_form'; import axios from './lib/utils/axios_utils'; @@ -399,7 +399,11 @@ export default class Notes { if (noteEntity.commands_changes && Object.keys(noteEntity.commands_changes).length > 0) { $notesList.find('.system-note.being-posted').remove(); } - this.addFlash(noteEntity.errors.commands_only, 'notice', this.parentTimeline.get(0)); + this.addFlash({ + message: noteEntity.errors.commands_only, + type: 'notice', + parent: this.parentTimeline.get(0), + }); this.refresh(); } return; @@ -620,20 +624,21 @@ export default class Notes { } else if ($form.hasClass('js-discussion-note-form')) { formParentTimeline = $form.closest('.discussion-notes').find('.notes'); } - return this.addFlash( - __( + return this.addFlash({ + message: __( 'Your comment could not be submitted! Please check your network connection and try again.', ), - 'alert', - formParentTimeline.get(0), - ); + type: 'alert', + parent: formParentTimeline.get(0), + }); } updateNoteError() { - // eslint-disable-next-line no-new - new Flash( - __('Your comment could not be updated! Please check your network connection and try again.'), - ); + createFlash({ + message: __( + 'Your comment could not be updated! Please check your network connection and try again.', + ), + }); } /** @@ -1289,7 +1294,7 @@ export default class Notes { } addFlash(...flashParams) { - this.flashContainer = new Flash(...flashParams); + this.flashContainer = createFlash(...flashParams); } clearFlash() { diff --git a/app/assets/javascripts/search_settings/constants.js b/app/assets/javascripts/search_settings/constants.js index 499e42854ed..9452d149122 100644 --- a/app/assets/javascripts/search_settings/constants.js +++ b/app/assets/javascripts/search_settings/constants.js @@ -5,7 +5,7 @@ export const EXCLUDED_NODES = ['OPTION']; export const HIDE_CLASS = 'gl-display-none'; // used to highlight the text that matches the * search term -export const HIGHLIGHT_CLASS = 'gl-bg-orange-50'; +export const HIGHLIGHT_CLASS = 'gl-bg-orange-100'; // How many seconds to wait until the user * stops typing export const TYPING_DELAY = 400; diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue index 62c5cd90035..d02c32112e9 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue @@ -15,10 +15,10 @@ import { isEmpty } from 'lodash'; import readyToMergeMixin from 'ee_else_ce/vue_merge_request_widget/mixins/ready_to_merge'; import readyToMergeQuery from 'ee_else_ce/vue_merge_request_widget/queries/states/ready_to_merge.query.graphql'; import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests'; +import createFlash from '~/flash'; import simplePoll from '~/lib/utils/simple_poll'; import { __ } from '~/locale'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; -import { deprecatedCreateFlash as Flash } from '../../../flash'; import MergeRequest from '../../../merge_request'; import { AUTO_MERGE_STRATEGIES, DANGER, INFO, WARNING } from '../../constants'; import eventHub from '../../event_hub'; @@ -351,7 +351,9 @@ export default { }) .catch(() => { this.isMakingRequest = false; - new Flash(__('Something went wrong. Please try again.')); // eslint-disable-line + createFlash({ + message: __('Something went wrong. Please try again.'), + }); }); }, handleMergeImmediatelyButtonClick() { @@ -402,7 +404,9 @@ export default { } }) .catch(() => { - new Flash(__('Something went wrong while merging this merge request. Please try again.')); // eslint-disable-line + createFlash({ + message: __('Something went wrong while merging this merge request. Please try again.'), + }); stopPolling(); }); }, @@ -432,7 +436,9 @@ export default { } }) .catch(() => { - new Flash(__('Something went wrong while deleting the source branch. Please try again.')); // eslint-disable-line + createFlash({ + message: __('Something went wrong while deleting the source branch. Please try again.'), + }); }); }, }, diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 52566248296..9ff76adee13 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -43,6 +43,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo push_frontend_feature_flag(:local_file_reviews, default_enabled: :yaml) push_frontend_feature_flag(:paginated_notes, @project, default_enabled: :yaml) push_frontend_feature_flag(:new_pipelines_table, @project, default_enabled: :yaml) + push_frontend_feature_flag(:confidential_notes, @project, default_enabled: :yaml) record_experiment_user(:invite_members_version_b) diff --git a/app/workers/remove_expired_members_worker.rb b/app/workers/remove_expired_members_worker.rb index 35844fdf297..fc2ec047e1c 100644 --- a/app/workers/remove_expired_members_worker.rb +++ b/app/workers/remove_expired_members_worker.rb @@ -2,20 +2,29 @@ class RemoveExpiredMembersWorker # rubocop:disable Scalability/IdempotentWorker include ApplicationWorker - include CronjobQueue # rubocop:disable Scalability/CronWorkerContext + include CronjobQueue feature_category :authentication_and_authorization worker_resource_boundary :cpu # rubocop: disable CodeReuse/ActiveRecord def perform - Member.expired.preload(:user).find_each do |member| - Members::DestroyService.new.execute(member, skip_authorization: true) + Member.expired.preload(:user, :source).find_each do |member| + context = { + user: member.user, + # The ApplicationContext will reject type-mismatches. So a GroupMemeber will only populate `namespace`. + # while a `ProjectMember` will populate `project + project: member.source, + namespace: member.source + } + with_context(context) do + Members::DestroyService.new.execute(member, skip_authorization: true) - expired_user = member.user + expired_user = member.user - if expired_user.project_bot? - Users::DestroyService.new(nil).execute(expired_user, skip_authorization: true) + if expired_user.project_bot? + Users::DestroyService.new(nil).execute(expired_user, skip_authorization: true) + end end rescue => ex logger.error("Expired Member ID=#{member.id} cannot be removed - #{ex}") diff --git a/changelogs/unreleased/dz-fix-ruby-alpine-template.yml b/changelogs/unreleased/dz-fix-ruby-alpine-template.yml new file mode 100644 index 00000000000..b3b4afe6d99 --- /dev/null +++ b/changelogs/unreleased/dz-fix-ruby-alpine-template.yml @@ -0,0 +1,5 @@ +--- +title: Fix ruby alpine CI template +merge_request: 57109 +author: +type: fixed diff --git a/changelogs/unreleased/jl-update-ru-weight-translation.yml b/changelogs/unreleased/jl-update-ru-weight-translation.yml new file mode 100644 index 00000000000..4b214c53efa --- /dev/null +++ b/changelogs/unreleased/jl-update-ru-weight-translation.yml @@ -0,0 +1,5 @@ +--- +title: Update weight transaltion for Russian locale +merge_request: 56986 +author: Gennady Kovalev (@belolap) +type: fixed diff --git a/changelogs/unreleased/push_confidential_notes_ff_to_fe.yml b/changelogs/unreleased/push_confidential_notes_ff_to_fe.yml new file mode 100644 index 00000000000..ff6ed4e3875 --- /dev/null +++ b/changelogs/unreleased/push_confidential_notes_ff_to_fe.yml @@ -0,0 +1,5 @@ +--- +title: Push confidential_notes feature flag to mr frontend +merge_request: 56798 +author: Lee Tickett @leetickett +type: fixed diff --git a/changelogs/unreleased/sh-global-use-distinct-object-hierarchy.yml b/changelogs/unreleased/sh-global-use-distinct-object-hierarchy.yml new file mode 100644 index 00000000000..d6d58f7448e --- /dev/null +++ b/changelogs/unreleased/sh-global-use-distinct-object-hierarchy.yml @@ -0,0 +1,5 @@ +--- +title: Enable DISTINCT optimization for ObjectHierarchy globally +merge_request: 57052 +author: +type: changed diff --git a/config/feature_flags/development/use_distinct_for_all_object_hierarchy.yml b/config/feature_flags/development/use_distinct_for_all_object_hierarchy.yml new file mode 100644 index 00000000000..9412e6af327 --- /dev/null +++ b/config/feature_flags/development/use_distinct_for_all_object_hierarchy.yml @@ -0,0 +1,8 @@ +--- +name: use_distinct_for_all_object_hierarchy +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57052 +rollout_issue_url: +milestone: '13.11' +type: development +group: group::database +default_enabled: false diff --git a/doc/administration/gitaly/praefect.md b/doc/administration/gitaly/praefect.md index 25ef2f9a850..b7a317717a0 100644 --- a/doc/administration/gitaly/praefect.md +++ b/doc/administration/gitaly/praefect.md @@ -274,6 +274,9 @@ with secure tokens as you complete the setup process. We note in the instructions below where these secrets are required. +NOTE: +Omnibus GitLab installations can use `gitlab-secrets.json`. + ### PostgreSQL NOTE: @@ -283,10 +286,11 @@ database on the same PostgreSQL server if using of GitLab and should not be replicated. These instructions help set up a single PostgreSQL database, which creates a single point of -failure. For greater fault tolerance, the following options are available: +failure. The following options are available: -- For non-Geo installations, use one of the fault-tolerant - [PostgreSQL setups](../postgresql/index.md). +- For non-Geo installations, either: + - Use one of the documented [PostgreSQL setups](../postgresql/index.md). + - Use your own third-party database setup, if fault tolerance is required. - For Geo instances, either: - Set up a separate [PostgreSQL instance](https://www.postgresql.org/docs/11/high-availability.html). - Use a cloud-managed PostgreSQL service. AWS @@ -802,14 +806,26 @@ documentation](configure_gitaly.md#configure-gitaly-servers). gitaly['auth_token'] = 'PRAEFECT_INTERNAL_TOKEN' ``` -1. Configure the GitLab Shell `secret_token`, and `internal_api_url` which are - needed for `git push` operations. +1. Configure the GitLab Shell secret token, which is needed for `git push` operations. Either: - If you have already configured [Gitaly on its own server](index.md) + - Method 1: + + 1. Copy `/etc/gitlab/gitlab-secrets.json` from the Gitaly client to same path on the Gitaly + servers and any other Gitaly clients. + 1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) on Gitaly servers. + + - Method 2: + + 1. Edit `/etc/gitlab/gitlab.rb`. + 1. Replace `GITLAB_SHELL_SECRET_TOKEN` with the real secret. + + ```ruby + gitlab_shell['secret_token'] = 'GITLAB_SHELL_SECRET_TOKEN' + ``` + +1. Configure and `internal_api_url`, which is also needed for `git push` operations: ```ruby - gitlab_shell['secret_token'] = 'GITLAB_SHELL_SECRET_TOKEN' - # Configure the gitlab-shell API callback URL. Without this, `git push` will # fail. This can be your front door GitLab URL or an internal load balancer. # Examples: 'https://gitlab.example.com', 'http://1.2.3.4' @@ -961,15 +977,23 @@ Particular attention should be shown to: }) ``` -1. Configure the `gitlab_shell['secret_token']` so that callbacks from Gitaly - nodes during a `git push` are properly authenticated by editing - `/etc/gitlab/gitlab.rb`: +1. Configure the GitLab Shell secret token so that callbacks from Gitaly nodes during a `git push` + are properly authenticated. Either: - You need to replace `GITLAB_SHELL_SECRET_TOKEN` with the real secret. + - Method 1: - ```ruby - gitlab_shell['secret_token'] = 'GITLAB_SHELL_SECRET_TOKEN' - ``` + 1. Copy `/etc/gitlab/gitlab-secrets.json` from the Gitaly client to same path on the Gitaly + servers and any other Gitaly clients. + 1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) on Gitaly servers. + + - Method 2: + + 1. Edit `/etc/gitlab/gitlab.rb`. + 1. Replace `GITLAB_SHELL_SECRET_TOKEN` with the real secret. + + ```ruby + gitlab_shell['secret_token'] = 'GITLAB_SHELL_SECRET_TOKEN' + ``` 1. Add Prometheus monitoring settings by editing `/etc/gitlab/gitlab.rb`. If Prometheus is enabled on a different node, make edits on that node instead. diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index 5c70671456c..22442ad8918 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -1069,8 +1069,8 @@ job: - when: on_success ``` -- If the pipeline is for a merge request, the job is **not** be added to the pipeline. -- If the pipeline is a scheduled pipeline, the job is **not** be added to the pipeline. +- If the pipeline is for a merge request, the job is **not** added to the pipeline. +- If the pipeline is a scheduled pipeline, the job is **not** added to the pipeline. - In **all other cases**, the job is added to the pipeline, with `when: on_success`. WARNING: diff --git a/doc/user/project/merge_requests/img/merge_request_tab_position_v12_6.png b/doc/user/project/merge_requests/img/merge_request_tab_position_v12_6.png deleted file mode 100644 index 9284e58f456..00000000000 Binary files a/doc/user/project/merge_requests/img/merge_request_tab_position_v12_6.png and /dev/null differ diff --git a/doc/user/project/merge_requests/img/merge_request_tab_position_v13_11.png b/doc/user/project/merge_requests/img/merge_request_tab_position_v13_11.png new file mode 100644 index 00000000000..8cc877b40b0 Binary files /dev/null and b/doc/user/project/merge_requests/img/merge_request_tab_position_v13_11.png differ diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md index 99e0193d496..1fed30dc589 100644 --- a/doc/user/project/merge_requests/index.md +++ b/doc/user/project/merge_requests/index.md @@ -7,12 +7,10 @@ type: index, reference # Merge requests **(FREE)** -Whenever you need to merge one branch into another branch with GitLab, you -must create a merge request (MR). +Merge requests (MRs) are the way you check source code changes into a branch. -Using merge requests, you can visualize and collaborate on proposed changes to -source code. Merge requests display information about the proposed code changes, -including: +When you open a merge request, you can visualize and collaborate on the code changes before merge. +Merge requests include: - A description of the request. - Code changes and inline code reviews. @@ -20,55 +18,50 @@ including: - A comment section for discussion threads. - The list of commits. -Based on your workflow, after review you can merge a merge request into its -target branch. - To get started, read the [introduction to merge requests](getting_started.md). -## Use cases +## Merge request workflows -A. Consider you're a software developer working in a team: +For a software developer working in a team: -1. You checkout a new branch, and submit your changes through a merge request -1. You gather feedback from your team -1. You work on the implementation optimizing code with [Code Quality reports](code_quality.md) -1. You verify your changes with [Unit test reports](../../../ci/unit_test_reports.md) in GitLab CI/CD -1. You avoid using dependencies whose license is not compatible with your project with [License Compliance reports](../../compliance/license_compliance/index.md) **(ULTIMATE)** -1. You request the [approval](merge_request_approvals.md) from your manager **(STARTER)** +1. You checkout a new branch, and submit your changes through a merge request. +1. You gather feedback from your team. +1. You work on the implementation optimizing code with [Code Quality reports](code_quality.md). +1. You verify your changes with [Unit test reports](../../../ci/unit_test_reports.md) in GitLab CI/CD. +1. You avoid using dependencies whose license is not compatible with your project with [License Compliance reports](../../compliance/license_compliance/index.md). +1. You request the [approval](merge_request_approvals.md) from your manager. 1. Your manager: - 1. Pushes a commit with their final review - 1. [Approves the merge request](merge_request_approvals.md) **(STARTER)** - 1. Sets it to [merge when pipeline succeeds](merge_when_pipeline_succeeds.md) -1. Your changes get deployed to production with [manual actions](../../../ci/yaml/README.md#whenmanual) for GitLab CI/CD -1. Your implementations were successfully shipped to your customer + 1. Pushes a commit with their final review. + 1. [Approves the merge request](merge_request_approvals.md). + 1. Sets it to [merge when pipeline succeeds](merge_when_pipeline_succeeds.md). +1. Your changes get deployed to production with [manual actions](../../../ci/yaml/README.md#whenmanual) for GitLab CI/CD. +1. Your implementations were successfully shipped to your customer. -B. Consider you're a web developer writing a webpage for your company's website: +For a web developer writing a webpage for your company's website: -1. You checkout a new branch, and submit a new page through a merge request -1. You gather feedback from your reviewers -1. Your changes are previewed with [Review Apps](../../../ci/review_apps/index.md) -1. You request your web designers for their implementation -1. You request the [approval](merge_request_approvals.md) from your manager **(STARTER)** -1. Once approved, your merge request is [squashed and merged](squash_and_merge.md), and [deployed to staging with GitLab Pages](https://about.gitlab.com/blog/2021/02/05/ci-deployment-and-environments/) -1. Your production team [cherry picks](cherry_pick_changes.md) the merge commit into production +1. You checkout a new branch and submit a new page through a merge request. +1. You gather feedback from your reviewers. +1. You preview your changes with [Review Apps](../../../ci/review_apps/index.md). +1. You request your web designers for their implementation. +1. You request the [approval](merge_request_approvals.md) from your manager. +1. Once approved, your merge request is [squashed and merged](squash_and_merge.md), and [deployed to staging with GitLab Pages](https://about.gitlab.com/blog/2021/02/05/ci-deployment-and-environments/). +1. Your production team [cherry picks](cherry_pick_changes.md) the merge commit into production. ## Merge request navigation tabs at the top > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/33813) in GitLab 12.6. This positioning is experimental. -So far, the navigation tabs present in merge requests to display **Discussion**, -**Commits**, **Pipelines**, and **Changes** were located after the merge request +In GitLab 12.5 and earlier, navigation tabs in merge requests (**Discussion**, +**Commits**, **Pipelines**, and **Changes**) were located after the merge request widget. -To facilitate this navigation without having to scroll up and down through the page -to find these tabs, based on user feedback, we're experimenting with a new positioning -of these tabs. They are now located at the top of the merge request, with a new -**Overview** tab, containing the description of the merge request followed by the -widget. Next to **Overview**, you can find **Pipelines**, **Commits**, and **Changes**. +To facilitate navigation without scrolling, and based on user feedback, the tabs are +now located at the top of the merge request tab. A new **Overview** tab was added, +and next to **Overview** are **Commits**, **Pipelines**, and **Changes**. -![Merge request tab positions](img/merge_request_tab_position_v12_6.png) +![Merge request tab positions](img/merge_request_tab_position_v13_11.png) -Please note this change is currently behind a feature flag which is enabled by default. For +This change is behind a feature flag that is enabled by default. For self-managed instances, it can be disabled through the Rails console by a GitLab administrator with the following command: @@ -76,23 +69,9 @@ administrator with the following command: Feature.disable(:mr_tabs_position) ``` -## Creating merge requests +## Related topics -Learn [how to create a merge request](creating_merge_requests.md). - -## Reviewing and managing merge requests - -See the features at your disposal to [review and manage merge requests](reviewing_and_managing_merge_requests.md). - -## Testing and reports in merge requests - -Learn about the options for [testing and reports](testing_and_reports_in_merge_requests.md) on the changes in a merge request. - -## Authorization for merge requests - -There are two main ways to have a merge request flow with GitLab: - -1. Working with [protected branches](../protected_branches.md) in a single repository -1. Working with forks of an authoritative project - -[Learn more about the authorization for merge requests.](authorization_for_merge_requests.md) +- [Create a merge request](creating_merge_requests.md) +- [Review and manage merge requests](reviewing_and_managing_merge_requests.md) +- [Authorization for merge requests](authorization_for_merge_requests.md) +- [Testing and reports](testing_and_reports_in_merge_requests.md) diff --git a/doc/user/project/web_ide/index.md b/doc/user/project/web_ide/index.md index 090b98e1a08..ac108fddea5 100644 --- a/doc/user/project/web_ide/index.md +++ b/doc/user/project/web_ide/index.md @@ -344,7 +344,7 @@ terminal: # This can be any image that has the necessary runtime environment for your project. image: node:10-alpine before_script: - - apt-get update + - apk update script: sleep 60 variables: RAILS_ENV: "test" diff --git a/lib/api/api.rb b/lib/api/api.rb index f83a36068dd..fda2d76160f 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -59,7 +59,7 @@ module API project: -> { @project }, namespace: -> { @group }, runner: -> { @current_runner || @runner }, - caller_id: route.origin, + caller_id: api_endpoint.endpoint_id, remote_ip: request.ip, feature_category: feature_category ) diff --git a/lib/api/helpers/common_helpers.rb b/lib/api/helpers/common_helpers.rb index a44fd4b0a5b..8940cf87f82 100644 --- a/lib/api/helpers/common_helpers.rb +++ b/lib/api/helpers/common_helpers.rb @@ -32,6 +32,10 @@ module API end end.compact.to_set end + + def endpoint_id + "#{request.request_method} #{route.origin}" + end end end end diff --git a/lib/api/internal/base.rb b/lib/api/internal/base.rb index 664b05ea010..7800a9c0248 100644 --- a/lib/api/internal/base.rb +++ b/lib/api/internal/base.rb @@ -15,7 +15,7 @@ module API Gitlab::ApplicationContext.push( user: -> { actor&.user }, project: -> { project }, - caller_id: route.origin, + caller_id: api_endpoint.endpoint_id, remote_ip: request.ip, feature_category: feature_category ) diff --git a/lib/gitlab/object_hierarchy.rb b/lib/gitlab/object_hierarchy.rb index b1a1045a1f0..dad629f5074 100644 --- a/lib/gitlab/object_hierarchy.rb +++ b/lib/gitlab/object_hierarchy.rb @@ -68,12 +68,14 @@ module Gitlab expose_depth = hierarchy_order.present? hierarchy_order ||= :asc - recursive_query = base_and_ancestors_cte(upto, hierarchy_order).apply_to(model.all).distinct - # if hierarchy_order is given, the calculated `depth` should be present in SELECT if expose_depth + recursive_query = base_and_ancestors_cte(upto, hierarchy_order).apply_to(model.all).distinct read_only(model.from(Arel::Nodes::As.new(recursive_query.arel, objects_table)).order(depth: hierarchy_order)) else + recursive_query = base_and_ancestors_cte(upto).apply_to(model.all) + recursive_query = recursive_query.reselect(*recursive_query.arel.projections, 'ROW_NUMBER() OVER () as depth').distinct + recursive_query = model.from(Arel::Nodes::As.new(recursive_query.arel, objects_table)) read_only(remove_depth_and_maintain_order(recursive_query, hierarchy_order: hierarchy_order)) end else @@ -93,11 +95,13 @@ module Gitlab def base_and_descendants(with_depth: false) if use_distinct? # Always calculate `depth`, remove it later if with_depth is false - base_cte = base_and_descendants_cte(with_depth: true).apply_to(model.all).distinct - if with_depth - read_only(model.from(Arel::Nodes::As.new(recursive_query.arel, objects_table)).order(depth: :asc)) + base_cte = base_and_descendants_cte(with_depth: true).apply_to(model.all).distinct + read_only(model.from(Arel::Nodes::As.new(base_cte.arel, objects_table)).order(depth: :asc)) else + base_cte = base_and_descendants_cte.apply_to(model.all) + base_cte = base_cte.reselect(*base_cte.arel.projections, 'ROW_NUMBER() OVER () as depth').distinct + base_cte = model.from(Arel::Nodes::As.new(base_cte.arel, objects_table)) read_only(remove_depth_and_maintain_order(base_cte, hierarchy_order: :asc)) end else @@ -161,7 +165,12 @@ module Gitlab # Use distinct on the Namespace queries to avoid bad planner behavior in PG11. def use_distinct? - (model <= Namespace) && options[:use_distinct] + return unless model <= Namespace + # Global use_distinct_for_all_object_hierarchy takes precedence over use_distinct_in_object_hierarchy + return true if Feature.enabled?(:use_distinct_for_all_object_hierarchy) + return options[:use_distinct] if options.key?(:use_distinct) + + false end # Remove the extra `depth` field using an INNER JOIN to avoid breaking UNION queries diff --git a/locale/ru/gitlab.po b/locale/ru/gitlab.po index 175eab5d53f..d81512a1b0e 100644 --- a/locale/ru/gitlab.po +++ b/locale/ru/gitlab.po @@ -523,7 +523,7 @@ msgid "%{completedCount} completed weight" msgstr "" msgid "%{completedWeight} of %{totalWeight} weight completed" -msgstr "Завершено %{completedWeight} из %{totalWeight} приоритета" +msgstr "Завершено %{completedWeight} из %{totalWeight} единиц веса" msgid "%{containerScanningLinkStart}Container Scanning%{containerScanningLinkEnd} and/or %{dependencyScanningLinkStart}Dependency Scanning%{dependencyScanningLinkEnd} must be enabled. %{securityBotLinkStart}GitLab-Security-Bot%{securityBotLinkEnd} will be the author of the auto-created merge request. %{moreInfoLinkStart}More information%{moreInfoLinkEnd}." msgstr "" @@ -859,7 +859,7 @@ msgid "%{openedIssues} open, %{closedIssues} closed" msgstr "%{openedIssues} открыто, %{closedIssues} закрыто" msgid "%{percentage}%% weight completed" -msgstr "%{percentage}%% приоритета завершено" +msgstr "%{percentage}%% веса завершено" msgid "%{percent}%% complete" msgstr "%{percent}%% выполнено" @@ -1068,13 +1068,13 @@ msgid "%{totalMemory} (%{freeSpacePercentage}%{percentSymbol} free)" msgstr "" msgid "%{totalWeight} total weight" -msgstr "общий приоритет %{totalWeight}" +msgstr "общий вес %{totalWeight}" msgid "%{total_warnings} warning(s) found:" msgstr "" msgid "%{total} open issue weight" -msgstr "приоритет открытого обсуждения %{total}" +msgstr "вес открытого обсуждения %{total}" msgid "%{total} warnings found: showing first %{warningsDisplayed}" msgstr "" @@ -1258,7 +1258,7 @@ msgstr[2] "- Пользователи" msgstr[3] "- Пользователи" msgid "- of - weight completed" -msgstr "- из - приоритета завершено" +msgstr "- из - единиц веса завершено" msgid "- show less" msgstr "- свернуть" @@ -3448,7 +3448,7 @@ msgid "An error occurred when updating the issue title" msgstr "" msgid "An error occurred when updating the issue weight" -msgstr "Произошла ошибка при обновлении приоритета обсуждения" +msgstr "Произошла ошибка при обновлении весa обсуждения" msgid "An error occurred while acknowledging the notification. Refresh the page and try again." msgstr "" @@ -5352,7 +5352,7 @@ msgid "Burndown charts are now fixed. This means that removing issues from a mil msgstr "Диаграммы сгорания задач стали фиксированными. Это означает, что если убрать обсуждения из этапа, ставшего просроченным, диаграмма не изменится. Прежний вариант диаграммы можно увидеть, нажав на кнопку %{strongStart}Старый вид диаграммы сгорания%{strongEnd}." msgid "BurndownChartLabel|Open issue weight" -msgstr "Открыть приоритет задачи" +msgstr "Bес открытых обсуждений" msgid "BurndownChartLabel|Open issues" msgstr "Открыть обсуждения" @@ -6346,13 +6346,13 @@ msgid "Clear templates search input" msgstr "Очистить шаблоны ввода данных для поиска" msgid "Clear weight" -msgstr "Очистить приоритет" +msgstr "Удалить вес" msgid "Cleared weight." -msgstr "Приоритет очищен." +msgstr "Вес удалён." msgid "Clears weight." -msgstr "Очищает приоритет." +msgstr "Удаляет вес." msgid "Click %{link_start}here%{link_end} to view the request." msgstr "" @@ -11728,7 +11728,7 @@ msgid "Enter the number of seconds, or other human-readable input, like \"1 hour msgstr "" msgid "Enter weights for storages for new repositories." -msgstr "" +msgstr "Введите веса хранилищ для новых репозиториев." msgid "Enter your password to approve" msgstr "Для продолжения введите свой пароль" @@ -12244,7 +12244,7 @@ msgid "Error occurred while updating the issue status" msgstr "Произошла ошибка при обновлении статуса обсуждения" msgid "Error occurred while updating the issue weight" -msgstr "Произошла ошибка при изменении приоритета задачи" +msgstr "Произошла ошибка при изменении весa обсуждения" msgid "Error occurred. A blocked user cannot be deactivated" msgstr "Произошла ошибка. Заблокированный пользователь не может быть деактивирован" @@ -17099,7 +17099,7 @@ msgid "Issue was closed by %{name} %{reason}" msgstr "Обсуждение было закрыто %{name} %{reason}" msgid "Issue weight" -msgstr "Приоритет обсуждения" +msgstr "Вес обсуждения" msgid "IssueAnalytics|Age" msgstr "" @@ -24622,10 +24622,10 @@ msgid "Promotions|Weight" msgstr "" msgid "Promotions|Weighting your issue" -msgstr "Обозначить приоритет обсуждения" +msgstr "Установка веса обсуждения" msgid "Promotions|When you have a lot of issues, it can be hard to get an overview. By adding a weight to your issues, you can get a better idea of the effort, cost, required time, or value of each, and so better manage them." -msgstr "При большом количестве обсуждений сложно оценить общую картину. Добавив приоритет к вашим обсуждениям, вы можете получить лучшее представление о затрачиваемых усилиях, времени, стоимости или значимости каждого из них и, таким образом, лучше ими управлять." +msgstr "При большом количестве обсуждений сложно оценить общую картину. Добавив вес к вашим обсуждениям, вы можете получить лучшее представление о затрачиваемых усилиях, времени, стоимости или значимости каждого из них и, таким образом, лучше ими управлять." msgid "Promotions|With Contribution Analytics you can have an overview for the activity of issues, merge requests, and push events of your organization and its members." msgstr "" @@ -27685,10 +27685,10 @@ msgid "Set verification limit and frequency." msgstr "" msgid "Set weight" -msgstr "Установить приоритет" +msgstr "Установить вес" msgid "Set weight to %{weight}." -msgstr "Установить приоритет на %{weight}." +msgstr "Установить вес в следующее количество единиц: %{weight}." msgid "Set what should be replicated by this secondary node." msgstr "" @@ -27748,7 +27748,7 @@ msgid "Sets time estimate to %{time_estimate}." msgstr "Задаёт оценку времени в %{time_estimate}." msgid "Sets weight to %{weight}." -msgstr "Устанавливает приоритет на %{weight}." +msgstr "Устанавливает вес в следующее количество единиц: %{weight}." msgid "Setting this to 0 means using the system default timeout value." msgstr "" @@ -27975,7 +27975,7 @@ msgid "Sidebar|Only numeral characters allowed" msgstr "" msgid "Sidebar|Weight" -msgstr "Приоритет" +msgstr "Вес" msgid "Sign in" msgstr "Вход" @@ -28458,7 +28458,7 @@ msgid "SortOptions|Least popular" msgstr "Наименее популярный" msgid "SortOptions|Less weight" -msgstr "Сначала с меньшим приоритетом" +msgstr "Сначала с меньшим весом" msgid "SortOptions|Manual" msgstr "Ручная" @@ -28473,7 +28473,7 @@ msgid "SortOptions|Milestone due soon" msgstr "Веха, наступающая раньше" msgid "SortOptions|More weight" -msgstr "Сначала с большим приоритетом" +msgstr "Сначала с большим весом" msgid "SortOptions|Most popular" msgstr "Наиболее популярный" @@ -28554,7 +28554,7 @@ msgid "SortOptions|Version" msgstr "По версии" msgid "SortOptions|Weight" -msgstr "Приоритет" +msgstr "Вес" msgid "Source" msgstr "Источник" @@ -31798,7 +31798,7 @@ msgid "Total users" msgstr "" msgid "Total weight" -msgstr "Итоговый приоритет" +msgstr "Общий вес" msgid "Total: %{total}" msgstr "Всего: %{total}" @@ -33976,10 +33976,10 @@ msgid "Weeks" msgstr "Недели" msgid "Weight" -msgstr "Приоритет" +msgstr "Вес" msgid "Weight %{weight}" -msgstr "Приоритет %{weight}" +msgstr "Вес %{weight}" msgid "Welcome back! Your account had been deactivated due to inactivity but is now reactivated." msgstr "Добро пожаловать! Ваша учётная запись была деактивирована из-за неактивности, но сейчас восстановлена." @@ -36507,7 +36507,7 @@ msgid "remove due date" msgstr "удалить дату завершения" msgid "remove weight" -msgstr "удалить приоритет" +msgstr "удалить вес" msgid "removed a Zoom call from this issue" msgstr "" diff --git a/spec/frontend/cycle_analytics/banner_spec.js b/spec/frontend/cycle_analytics/banner_spec.js index 0cae0298cee..ef7998c5ff5 100644 --- a/spec/frontend/cycle_analytics/banner_spec.js +++ b/spec/frontend/cycle_analytics/banner_spec.js @@ -1,45 +1,47 @@ -import Vue from 'vue'; -import mountComponent from 'helpers/vue_mount_component_helper'; -import banner from '~/cycle_analytics/components/banner.vue'; +import { shallowMount } from '@vue/test-utils'; +import Banner from '~/cycle_analytics/components/banner.vue'; describe('Value Stream Analytics banner', () => { - let vm; + let wrapper; + + const createComponent = () => { + wrapper = shallowMount(Banner, { + propsData: { + documentationLink: 'path', + }, + }); + }; beforeEach(() => { - const Component = Vue.extend(banner); - vm = mountComponent(Component, { - documentationLink: 'path', - }); + createComponent(); }); afterEach(() => { - vm.$destroy(); + wrapper.destroy(); }); it('should render value stream analytics information', () => { - expect(vm.$el.querySelector('h4').textContent.trim()).toEqual( - 'Introducing Value Stream Analytics', - ); + expect(wrapper.find('h4').text().trim()).toBe('Introducing Value Stream Analytics'); expect( - vm.$el - .querySelector('p') - .textContent.trim() + wrapper + .find('p') + .text() + .trim() .replace(/[\r\n]+/g, ' '), ).toContain( 'Value Stream Analytics gives an overview of how much time it takes to go from idea to production in your project.', ); - expect(vm.$el.querySelector('a').textContent.trim()).toEqual('Read more'); - - expect(vm.$el.querySelector('a').getAttribute('href')).toEqual('path'); + expect(wrapper.find('a').text().trim()).toBe('Read more'); + expect(wrapper.find('a').attributes('href')).toBe('path'); }); - it('should emit an event when close button is clicked', () => { - jest.spyOn(vm, '$emit').mockImplementation(() => {}); + it('should emit an event when close button is clicked', async () => { + jest.spyOn(wrapper.vm, '$emit').mockImplementation(() => {}); - vm.$el.querySelector('.js-ca-dismiss-button').click(); + await wrapper.find('.js-ca-dismiss-button').trigger('click'); - expect(vm.$emit).toHaveBeenCalled(); + expect(wrapper.vm.$emit).toHaveBeenCalled(); }); }); diff --git a/spec/lib/gitlab/object_hierarchy_spec.rb b/spec/lib/gitlab/object_hierarchy_spec.rb index 08e1a5ee0a3..98a194ac73c 100644 --- a/spec/lib/gitlab/object_hierarchy_spec.rb +++ b/spec/lib/gitlab/object_hierarchy_spec.rb @@ -187,6 +187,21 @@ RSpec.describe Gitlab::ObjectHierarchy do context 'when the use_distinct_in_object_hierarchy feature flag is enabled' do before do stub_feature_flags(use_distinct_in_object_hierarchy: true) + stub_feature_flags(use_distinct_for_all_object_hierarchy: false) + end + + it_behaves_like 'Gitlab::ObjectHierarchy test cases' + + it 'calls DISTINCT' do + expect(parent.self_and_descendants.to_sql).to include("DISTINCT") + expect(child2.self_and_ancestors.to_sql).to include("DISTINCT") + end + end + + context 'when the use_distinct_for_all_object_hierarchy feature flag is enabled' do + before do + stub_feature_flags(use_distinct_in_object_hierarchy: false) + stub_feature_flags(use_distinct_for_all_object_hierarchy: true) end it_behaves_like 'Gitlab::ObjectHierarchy test cases' @@ -200,6 +215,7 @@ RSpec.describe Gitlab::ObjectHierarchy do context 'when the use_distinct_in_object_hierarchy feature flag is disabled' do before do stub_feature_flags(use_distinct_in_object_hierarchy: false) + stub_feature_flags(use_distinct_for_all_object_hierarchy: false) end it_behaves_like 'Gitlab::ObjectHierarchy test cases' diff --git a/spec/requests/api/api_spec.rb b/spec/requests/api/api_spec.rb index 7e670724c11..b3e425630e5 100644 --- a/spec/requests/api/api_spec.rb +++ b/spec/requests/api/api_spec.rb @@ -107,7 +107,7 @@ RSpec.describe API::API do allow_any_instance_of(Gitlab::GrapeLogging::Loggers::ContextLogger).to receive(:parameters) do Gitlab::ApplicationContext.current.tap do |log_context| expect(log_context).to match('correlation_id' => an_instance_of(String), - 'meta.caller_id' => '/api/:version/projects/:id/issues', + 'meta.caller_id' => 'GET /api/:version/projects/:id/issues', 'meta.remote_ip' => an_instance_of(String), 'meta.project' => project.full_path, 'meta.root_namespace' => project.namespace.full_path, @@ -124,7 +124,7 @@ RSpec.describe API::API do allow_any_instance_of(Gitlab::GrapeLogging::Loggers::ContextLogger).to receive(:parameters) do Gitlab::ApplicationContext.current.tap do |log_context| expect(log_context).to match('correlation_id' => an_instance_of(String), - 'meta.caller_id' => '/api/:version/users', + 'meta.caller_id' => 'GET /api/:version/users', 'meta.remote_ip' => an_instance_of(String), 'meta.client_id' => an_instance_of(String), 'meta.feature_category' => 'users') @@ -141,7 +141,7 @@ RSpec.describe API::API do let(:component_map) do { "application" => "test", - "endpoint_id" => "/api/:version/users/:id" + "endpoint_id" => "GET /api/:version/users/:id" } end diff --git a/spec/requests/api/ci/runner/jobs_artifacts_spec.rb b/spec/requests/api/ci/runner/jobs_artifacts_spec.rb index 9369b6aa464..49ccdccb7c8 100644 --- a/spec/requests/api/ci/runner/jobs_artifacts_spec.rb +++ b/spec/requests/api/ci/runner/jobs_artifacts_spec.rb @@ -127,7 +127,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do authorize_artifacts_with_token_in_params end - it_behaves_like 'API::CI::Runner application context metadata', '/api/:version/jobs/:id/artifacts/authorize' do + it_behaves_like 'API::CI::Runner application context metadata', 'POST /api/:version/jobs/:id/artifacts/authorize' do let(:send_request) { subject } end @@ -262,7 +262,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do end describe 'POST /api/v4/jobs/:id/artifacts' do - it_behaves_like 'API::CI::Runner application context metadata', '/api/:version/jobs/:id/artifacts' do + it_behaves_like 'API::CI::Runner application context metadata', 'POST /api/:version/jobs/:id/artifacts' do let(:send_request) do upload_artifacts(file_upload, headers_with_token) end @@ -784,7 +784,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do describe 'GET /api/v4/jobs/:id/artifacts' do let(:token) { job.token } - it_behaves_like 'API::CI::Runner application context metadata', '/api/:version/jobs/:id/artifacts' do + it_behaves_like 'API::CI::Runner application context metadata', 'GET /api/:version/jobs/:id/artifacts' do let(:send_request) { download_artifact } end diff --git a/spec/requests/api/ci/runner/jobs_put_spec.rb b/spec/requests/api/ci/runner/jobs_put_spec.rb index b5d2c4608c5..324419af7e5 100644 --- a/spec/requests/api/ci/runner/jobs_put_spec.rb +++ b/spec/requests/api/ci/runner/jobs_put_spec.rb @@ -36,7 +36,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do job.run! end - it_behaves_like 'API::CI::Runner application context metadata', '/api/:version/jobs/:id' do + it_behaves_like 'API::CI::Runner application context metadata', 'PUT /api/:version/jobs/:id' do let(:send_request) { update_job(state: 'success') } end diff --git a/spec/requests/api/ci/runner/jobs_trace_spec.rb b/spec/requests/api/ci/runner/jobs_trace_spec.rb index 659cf055023..d566c3b5032 100644 --- a/spec/requests/api/ci/runner/jobs_trace_spec.rb +++ b/spec/requests/api/ci/runner/jobs_trace_spec.rb @@ -41,7 +41,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do initial_patch_the_trace end - it_behaves_like 'API::CI::Runner application context metadata', '/api/:version/jobs/:id/trace' do + it_behaves_like 'API::CI::Runner application context metadata', 'PATCH /api/:version/jobs/:id/trace' do let(:send_request) { patch_the_trace } end diff --git a/spec/requests/api/internal/base_spec.rb b/spec/requests/api/internal/base_spec.rb index d9d021ba758..c4420c332c7 100644 --- a/spec/requests/api/internal/base_spec.rb +++ b/spec/requests/api/internal/base_spec.rb @@ -644,7 +644,7 @@ RSpec.describe API::Internal::Base do context 'with Project' do it_behaves_like 'storing arguments in the application context' do - let(:expected_params) { { user: key.user.username, project: project.full_path } } + let(:expected_params) { { user: key.user.username, project: project.full_path, caller_id: "POST /api/:version/internal/allowed" } } subject { push(key, project) } end @@ -652,7 +652,7 @@ RSpec.describe API::Internal::Base do context 'with PersonalSnippet' do it_behaves_like 'storing arguments in the application context' do - let(:expected_params) { { user: key.user.username } } + let(:expected_params) { { user: key.user.username, caller_id: "POST /api/:version/internal/allowed" } } subject { push(key, personal_snippet) } end @@ -660,7 +660,7 @@ RSpec.describe API::Internal::Base do context 'with ProjectSnippet' do it_behaves_like 'storing arguments in the application context' do - let(:expected_params) { { user: key.user.username, project: project_snippet.project.full_path } } + let(:expected_params) { { user: key.user.username, project: project_snippet.project.full_path, caller_id: "POST /api/:version/internal/allowed" } } subject { push(key, project_snippet) } end diff --git a/spec/services/ci/register_job_service_spec.rb b/spec/services/ci/register_job_service_spec.rb index 401a40bbb39..66d96c08fe1 100644 --- a/spec/services/ci/register_job_service_spec.rb +++ b/spec/services/ci/register_job_service_spec.rb @@ -228,6 +228,7 @@ module Ci context 'when the use_distinct_in_register_job_object_hierarchy feature flag is enabled' do before do stub_feature_flags(use_distinct_in_register_job_object_hierarchy: true) + stub_feature_flags(use_distinct_for_all_object_hierarchy: true) end it 'calls DISTINCT' do @@ -238,6 +239,7 @@ module Ci context 'when the use_distinct_in_register_job_object_hierarchy feature flag is disabled' do before do stub_feature_flags(use_distinct_in_register_job_object_hierarchy: false) + stub_feature_flags(use_distinct_for_all_object_hierarchy: false) end it 'does not call DISTINCT' do diff --git a/spec/support/shared_examples/features/search_settings_shared_examples.rb b/spec/support/shared_examples/features/search_settings_shared_examples.rb index 0b9ac35de8f..e45dcd14670 100644 --- a/spec/support/shared_examples/features/search_settings_shared_examples.rb +++ b/spec/support/shared_examples/features/search_settings_shared_examples.rb @@ -25,7 +25,7 @@ RSpec.shared_examples 'can highlight results' do |search_term| end it 'highlights the search terms' do - selector = '.gl-bg-orange-50' + selector = '.gl-bg-orange-100' fill_in SearchHelpers::INPUT_PLACEHOLDER, with: search_term expect(page).to have_css(selector) diff --git a/spec/workers/remove_expired_members_worker_spec.rb b/spec/workers/remove_expired_members_worker_spec.rb index 5642de05731..6d0d4aeef89 100644 --- a/spec/workers/remove_expired_members_worker_spec.rb +++ b/spec/workers/remove_expired_members_worker_spec.rb @@ -29,6 +29,15 @@ RSpec.describe RemoveExpiredMembersWorker do worker.perform expect(non_expiring_project_member.reload).to be_present end + + it 'adds context to resulting jobs' do + worker.perform + + new_job = Sidekiq::Worker.jobs.last + + expect(new_job).to include('meta.project' => expired_project_member.project.full_path, + 'meta.user' => expired_project_member.user.username) + end end context 'project bots' do @@ -98,6 +107,15 @@ RSpec.describe RemoveExpiredMembersWorker do worker.perform expect(non_expiring_group_member.reload).to be_present end + + it 'adds context to resulting jobs' do + worker.perform + + new_job = Sidekiq::Worker.jobs.last + + expect(new_job).to include('meta.root_namespace' => expired_group_member.group.full_path, + 'meta.user' => expired_group_member.user.username) + end end context 'when the last group owner expires' do diff --git a/vendor/Dockerfile/Ruby-alpine.Dockerfile b/vendor/Dockerfile/Ruby-alpine.Dockerfile index 0f748d84b5d..d91903fac61 100644 --- a/vendor/Dockerfile/Ruby-alpine.Dockerfile +++ b/vendor/Dockerfile/Ruby-alpine.Dockerfile @@ -9,7 +9,7 @@ RUN bundle config --global frozen 1 WORKDIR /usr/src/app -COPY Gemfile Gemfile.lock . +COPY Gemfile Gemfile.lock /usr/src/app/ # Install build dependencies - required for gems with native dependencies RUN apk add --no-cache --virtual build-deps build-base postgresql-dev && \ bundle install && \