diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-03-11 18:07:48 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-03-11 18:07:48 +0300 |
commit | e46506bcc32de1af076ec8a5d51d405f827dd986 (patch) | |
tree | bb08cb3d53132eef0e8d17e1f6bab9d672454ddd | |
parent | e105f6b881d9341331558c8c42f90391bab2fd19 (diff) |
Add latest changes from gitlab-org/gitlab@master
31 files changed, 372 insertions, 88 deletions
@@ -479,7 +479,7 @@ gem 'ssh_data', '~> 1.2' gem 'spamcheck', '~> 0.1.0' # Gitaly GRPC protocol definitions -gem 'gitaly', '~> 14.9.0.pre.rc2' +gem 'gitaly', '~> 14.9.0.pre.rc3' # KAS GRPC protocol definitions gem 'kas-grpc', '~> 0.0.2' diff --git a/Gemfile.lock b/Gemfile.lock index 6fe4cdc9726..d2e2d1e6438 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -455,7 +455,7 @@ GEM rails (>= 3.2.0) git (1.7.0) rchardet (~> 1.8) - gitaly (14.9.0.pre.rc2) + gitaly (14.9.0.pre.rc3) grpc (~> 1.0) github-markup (1.7.0) gitlab (4.16.1) @@ -1486,7 +1486,7 @@ DEPENDENCIES gettext (~> 3.3) gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails_js (~> 1.3) - gitaly (~> 14.9.0.pre.rc2) + gitaly (~> 14.9.0.pre.rc3) github-markup (~> 1.7.0) gitlab-chronic (~> 0.10.5) gitlab-dangerfiles (~> 2.10.2) diff --git a/app/assets/javascripts/admin/applications/components/delete_application.vue b/app/assets/javascripts/admin/applications/components/delete_application.vue new file mode 100644 index 00000000000..77694296b0a --- /dev/null +++ b/app/assets/javascripts/admin/applications/components/delete_application.vue @@ -0,0 +1,84 @@ +<script> +import { GlModal, GlSprintf } from '@gitlab/ui'; +import { __ } from '~/locale'; +import csrf from '~/lib/utils/csrf'; + +export default { + components: { + GlModal, + GlSprintf, + }, + data() { + return { + name: '', + path: '', + buttons: [], + }; + }, + mounted() { + this.buttons = document.querySelectorAll('.js-application-delete-button'); + + this.buttons.forEach((button) => button.addEventListener('click', this.buttonEvent)); + }, + destroy() { + this.buttons.forEach((button) => button.removeEventListener('click', this.buttonEvent)); + }, + methods: { + buttonEvent(e) { + e.preventDefault(); + this.show(e.target.dataset); + }, + show(dataset) { + const { name, path } = dataset; + + this.name = name; + this.path = path; + + this.$refs.deleteModal.show(); + }, + deleteApplication() { + this.$refs.deleteForm.submit(); + }, + }, + i18n: { + destroy: __('Destroy'), + title: __('Confirm destroy application'), + body: __('Are you sure that you want to destroy %{application}'), + }, + modal: { + actionPrimary: { + text: __('Destroy'), + attributes: { + variant: 'danger', + }, + }, + actionSecondary: { + text: __('Cancel'), + attributes: { + variant: 'default', + }, + }, + }, + csrf, +}; +</script> +<template> + <gl-modal + ref="deleteModal" + :title="$options.i18n.title" + :action-primary="$options.modal.actionPrimary" + :action-secondary="$options.modal.actionSecondary" + modal-id="delete-application-modal" + size="sm" + @primary="deleteApplication" + ><gl-sprintf :message="$options.i18n.body"> + <template #application> + <strong>{{ name }}</strong> + </template></gl-sprintf + > + <form ref="deleteForm" method="post" :action="path"> + <input type="hidden" name="_method" value="delete" /> + <input type="hidden" name="authenticity_token" :value="$options.csrf.token" /> + </form> + </gl-modal> +</template> diff --git a/app/assets/javascripts/admin/applications/index.js b/app/assets/javascripts/admin/applications/index.js new file mode 100644 index 00000000000..5875fd18729 --- /dev/null +++ b/app/assets/javascripts/admin/applications/index.js @@ -0,0 +1,15 @@ +import Vue from 'vue'; +import DeleteApplication from './components/delete_application.vue'; + +export default () => { + const el = document.querySelector('.js-application-delete-modal'); + + if (!el) return false; + + return new Vue({ + el, + render(h) { + return h(DeleteApplication); + }, + }); +}; diff --git a/app/assets/javascripts/pages/admin/applications/index.js b/app/assets/javascripts/pages/admin/applications/index.js new file mode 100644 index 00000000000..3397b02aeba --- /dev/null +++ b/app/assets/javascripts/pages/admin/applications/index.js @@ -0,0 +1,3 @@ +import initApplicationDeleteButtons from '~/admin/applications'; + +initApplicationDeleteButtons(); diff --git a/app/assets/javascripts/security_configuration/components/constants.js b/app/assets/javascripts/security_configuration/components/constants.js index 11e092d8eb4..3def5e9d6b7 100644 --- a/app/assets/javascripts/security_configuration/components/constants.js +++ b/app/assets/javascripts/security_configuration/components/constants.js @@ -222,14 +222,12 @@ export const securityFeatures = [ helpPath: COVERAGE_FUZZING_HELP_PATH, configurationHelpPath: COVERAGE_FUZZING_CONFIG_HELP_PATH, type: REPORT_TYPE_COVERAGE_FUZZING, - secondary: gon?.features?.corpusManagementUi - ? { - type: REPORT_TYPE_CORPUS_MANAGEMENT, - name: CORPUS_MANAGEMENT_NAME, - description: CORPUS_MANAGEMENT_DESCRIPTION, - configurationText: CORPUS_MANAGEMENT_CONFIG_TEXT, - } - : {}, + secondary: { + type: REPORT_TYPE_CORPUS_MANAGEMENT, + name: CORPUS_MANAGEMENT_NAME, + description: CORPUS_MANAGEMENT_DESCRIPTION, + configurationText: CORPUS_MANAGEMENT_CONFIG_TEXT, + }, }, ]; diff --git a/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue b/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue index a27dbee31ec..558fe8ca2aa 100644 --- a/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue +++ b/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue @@ -114,7 +114,7 @@ export default { class="gl-display-inline-block" > <attention-requested-toggle - v-if="showVerticalList && user.can_update_merge_request" + v-if="showVerticalList" :user="user" type="assignee" @toggle-attention-requested="toggleAttentionRequested" diff --git a/app/assets/javascripts/sidebar/components/attention_requested_toggle.vue b/app/assets/javascripts/sidebar/components/attention_requested_toggle.vue index 42e56906e2c..d11bed4f058 100644 --- a/app/assets/javascripts/sidebar/components/attention_requested_toggle.vue +++ b/app/assets/javascripts/sidebar/components/attention_requested_toggle.vue @@ -8,6 +8,8 @@ export default { attentionRequestedReviewer: __('Request attention to review'), attentionRequestedAssignee: __('Request attention'), removeAttentionRequested: __('Remove attention request'), + attentionRequestedNoPermission: __('Attention requested'), + noAttentionRequestedNoPermission: __('No attention request'), }, components: { GlButton, @@ -33,17 +35,25 @@ export default { computed: { tooltipTitle() { if (this.user.attention_requested) { - return this.$options.i18n.removeAttentionRequested; + if (this.user.can_update_merge_request) { + return this.$options.i18n.removeAttentionRequested; + } + + return this.$options.i18n.attentionRequestedNoPermission; + } + + if (this.user.can_update_merge_request) { + return this.type === 'reviewer' + ? this.$options.i18n.attentionRequestedReviewer + : this.$options.i18n.attentionRequestedAssignee; } - return this.type === 'reviewer' - ? this.$options.i18n.attentionRequestedReviewer - : this.$options.i18n.attentionRequestedAssignee; + return this.$options.i18n.noAttentionRequestedNoPermission; }, }, methods: { toggleAttentionRequired() { - if (this.loading) return; + if (this.loading || !this.user.can_update_merge_request) return; this.$root.$emit(BV_HIDE_TOOLTIP); this.loading = true; @@ -60,12 +70,13 @@ export default { </script> <template> - <span v-gl-tooltip.left.viewport="tooltipTitle"> + <span v-gl-tooltip.left.viewport="tooltipTitle" class="gl-display-inline-block"> <gl-button :loading="loading" :variant="user.attention_requested ? 'warning' : 'default'" :icon="user.attention_requested ? 'attention-solid' : 'attention'" :aria-label="tooltipTitle" + :class="{ 'gl-pointer-events-none': !user.can_update_merge_request }" size="small" category="tertiary" @click="toggleAttentionRequired" diff --git a/app/assets/javascripts/sidebar/components/reviewers/uncollapsed_reviewer_list.vue b/app/assets/javascripts/sidebar/components/reviewers/uncollapsed_reviewer_list.vue index adaf1b65f3f..9485802d3da 100644 --- a/app/assets/javascripts/sidebar/components/reviewers/uncollapsed_reviewer_list.vue +++ b/app/assets/javascripts/sidebar/components/reviewers/uncollapsed_reviewer_list.vue @@ -98,7 +98,7 @@ export default { data-testid="reviewer" > <attention-requested-toggle - v-if="glFeatures.mrAttentionRequests && user.can_update_merge_request" + v-if="glFeatures.mrAttentionRequests" :user="user" type="reviewer" @toggle-attention-requested="toggleAttentionRequested" diff --git a/app/models/repository.rb b/app/models/repository.rb index e0b1901d188..346478b6689 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -1085,10 +1085,10 @@ class Repository blob.data end - def create_if_not_exists + def create_if_not_exists(default_branch = nil) return if exists? - raw.create_repository + raw.create_repository(default_branch) after_create true diff --git a/app/models/snippet.rb b/app/models/snippet.rb index b04fca64c87..ac87da4f3c8 100644 --- a/app/models/snippet.rb +++ b/app/models/snippet.rb @@ -367,7 +367,7 @@ class Snippet < ApplicationRecord def create_repository return if repository_exists? && snippet_repository - repository.create_if_not_exists + repository.create_if_not_exists(default_branch) track_snippet_repository(repository.storage) end diff --git a/app/views/admin/applications/_delete_form.html.haml b/app/views/admin/applications/_delete_form.html.haml index d348ad507c2..16ec8014c5e 100644 --- a/app/views/admin/applications/_delete_form.html.haml +++ b/app/views/admin/applications/_delete_form.html.haml @@ -1,4 +1,5 @@ -- submit_btn_css ||= 'gl-button btn btn-danger btn-sm' -= form_tag admin_application_path(application) do - %input{ :name => "_method", :type => "hidden", :value => "delete" }/ - = submit_tag 'Destroy', class: submit_btn_css, data: { confirm: _('Are you sure?') } + +- submit_btn_css ||= 'gl-button btn btn-danger btn-sm js-application-delete-button' +%button{ class: submit_btn_css, data: { path: admin_application_path(application), name: application.name } } + = _('Destroy') + diff --git a/app/views/admin/applications/index.html.haml b/app/views/admin/applications/index.html.haml index 28a7bd1820a..86a4ab00ba3 100644 --- a/app/views/admin/applications/index.html.haml +++ b/app/views/admin/applications/index.html.haml @@ -33,3 +33,5 @@ %td= render 'delete_form', application: application = paginate @applications, theme: 'gitlab' + +.js-application-delete-modal diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 169d5dee615..16d4a8a85be 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -1161,8 +1161,6 @@ Input type: `ConfigureSecretDetectionInput` ### `Mutation.corpusCreate` -Available only when feature flag `corpus_management` is enabled. This flag is enabled by default. - Input type: `CorpusCreateInput` #### Arguments @@ -13789,7 +13787,7 @@ Represents vulnerability finding of a security report on the pipeline. | <a id="projectcontainerexpirationpolicy"></a>`containerExpirationPolicy` | [`ContainerExpirationPolicy`](#containerexpirationpolicy) | Container expiration policy of the project. | | <a id="projectcontainerregistryenabled"></a>`containerRegistryEnabled` | [`Boolean`](#boolean) | Indicates if Container Registry is enabled for the current user. | | <a id="projectcontainerrepositoriescount"></a>`containerRepositoriesCount` | [`Int!`](#int) | Number of container repositories in the project. | -| <a id="projectcorpuses"></a>`corpuses` | [`CoverageFuzzingCorpusConnection`](#coveragefuzzingcorpusconnection) | Find corpuses of the project. Available only when feature flag `corpus_management` is enabled. This flag is enabled by default. (see [Connections](#connections)) | +| <a id="projectcorpuses"></a>`corpuses` | [`CoverageFuzzingCorpusConnection`](#coveragefuzzingcorpusconnection) | Find corpuses of the project. (see [Connections](#connections)) | | <a id="projectcreatedat"></a>`createdAt` | [`Time`](#time) | Timestamp of the project creation. | | <a id="projectdastscannerprofiles"></a>`dastScannerProfiles` | [`DastScannerProfileConnection`](#dastscannerprofileconnection) | DAST scanner profiles associated with the project. (see [Connections](#connections)) | | <a id="projectdastsiteprofiles"></a>`dastSiteProfiles` | [`DastSiteProfileConnection`](#dastsiteprofileconnection) | DAST Site Profiles associated with the project. (see [Connections](#connections)) | diff --git a/doc/development/database/database_reviewer_guidelines.md b/doc/development/database/database_reviewer_guidelines.md index bc18e606f21..8c216d8247f 100644 --- a/doc/development/database/database_reviewer_guidelines.md +++ b/doc/development/database/database_reviewer_guidelines.md @@ -26,18 +26,12 @@ For more information on the database review process, check the [database review ## How to apply for becoming a database reviewer -Team members are encouraged to self-identify as database domain experts and add it to their [team profile](https://gitlab.com/gitlab-com/www-gitlab-com/-/blob/master/data/team.yml) +Team members are encouraged to self-identify as database domain experts, and add it to their profile YAML file: ```yaml projects: gitlab: - reviewer database -``` - -Assign the MR which adds your expertise to the `team.yml` file to a database maintainer -or the [Database Team's Engineering Manager](https://about.gitlab.com/handbook/engineering/development/enablement/database/). - -Once the `team.yml` update is merged, the [Reviewer roulette](../code_review.md#reviewer-roulette) may recommend you as a database reviewer. ## Resources for database reviewers diff --git a/doc/development/experiment_guide/index.md b/doc/development/experiment_guide/index.md index 254c136ef79..c34e5eb36dc 100644 --- a/doc/development/experiment_guide/index.md +++ b/doc/development/experiment_guide/index.md @@ -64,3 +64,15 @@ We recommend the following workflow: 1. **If the experiment is a success**, designers add the new icon or illustration to the Pajamas UI kit as part of the cleanup process. Engineers can then add it to the [SVG library](https://gitlab-org.gitlab.io/gitlab-svgs/) and modify the implementation based on the [Frontend Development Guidelines](../fe_guide/icons.md#usage-in-hamlrails-2). + +## Turn off all experiments + +When there is a case on GitLab.com (SaaS) that necessitates turning off all experiments, we have this control. + +You can toggle experiments on SaaS on and off using the `gitlab_experiment` [feature flag](../feature_flags). + +This can be done via chatops: + +- [disable](../feature_flags/controls.md#disabling-feature-flags): `/chatops run feature set gitlab_experiment false` +- [enable](../feature_flags/controls.md#process): `/chatops run feature delete gitlab_experiment` + - This allows the `default_enabled` [value of true in the yml](https://gitlab.com/gitlab-org/gitlab/-/blob/016430f6751b0c34abb24f74608c80a1a8268f20/config/feature_flags/ops/gitlab_experiment.yml#L8) to be honored. diff --git a/doc/user/application_security/coverage_fuzzing/index.md b/doc/user/application_security/coverage_fuzzing/index.md index 290d4a06dcc..a893106f52a 100644 --- a/doc/user/application_security/coverage_fuzzing/index.md +++ b/doc/user/application_security/coverage_fuzzing/index.md @@ -144,12 +144,8 @@ You can download the JSON report file from the CI/CD pipelines page. For more in ## Corpus registry -> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/5017) in GitLab 14.8. - -FLAG: -On self-managed GitLab, by default this feature is available. To hide the feature, ask an -administrator to [disable the feature flags](../../../administration/feature_flags.md) named -`corpus_management` and `corpus_management_ui`. On GitLab.com, this feature is available. +> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/5017) in GitLab 14.8. +> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/347187) in GitLab 14.9. [Feature flags `corpus_management` and `corpus_management_ui`](https://gitlab.com/gitlab-org/gitlab/-/issues/328418) removed. The corpus registry is a library of corpuses. Corpuses in a project's registry are available to all jobs in that project. A project-wide registry is a more efficient way to manage corpuses than diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index c3ee5b97379..1492ea1ce76 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -99,9 +99,9 @@ module Gitlab gitaly_repository_client.exists? end - def create_repository + def create_repository(default_branch = nil) wrapped_gitaly_errors do - gitaly_repository_client.create_repository + gitaly_repository_client.create_repository(default_branch) rescue GRPC::AlreadyExists => e raise RepositoryExists, e.message end diff --git a/lib/gitlab/gitaly_client/repository_service.rb b/lib/gitlab/gitaly_client/repository_service.rb index 51d0730bb1d..5c447dfd417 100644 --- a/lib/gitlab/gitaly_client/repository_service.rb +++ b/lib/gitlab/gitaly_client/repository_service.rb @@ -107,8 +107,8 @@ module Gitlab end # rubocop: enable Metrics/ParameterLists - def create_repository - request = Gitaly::CreateRepositoryRequest.new(repository: @gitaly_repo) + def create_repository(default_branch = nil) + request = Gitaly::CreateRepositoryRequest.new(repository: @gitaly_repo, default_branch: default_branch) GitalyClient.call(@storage, :repository_service, :create_repository, request, timeout: GitalyClient.fast_timeout) end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 9697ca955db..c78a131974b 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -4696,6 +4696,9 @@ msgstr "" msgid "Are you sure that you want to archive this project?" msgstr "" +msgid "Are you sure that you want to destroy %{application}" +msgstr "" + msgid "Are you sure that you want to unarchive this project?" msgstr "" @@ -5032,6 +5035,9 @@ msgstr "" msgid "Attention" msgstr "" +msgid "Attention requested" +msgstr "" + msgid "Audit Events" msgstr "" @@ -9281,6 +9287,9 @@ msgstr "" msgid "Confirm approval" msgstr "" +msgid "Confirm destroy application" +msgstr "" + msgid "Confirm new password" msgstr "" @@ -24672,6 +24681,9 @@ msgstr "" msgid "No assignee" msgstr "" +msgid "No attention request" +msgstr "" + msgid "No authentication methods configured." msgstr "" diff --git a/package.json b/package.json index 4a5dfced431..8fbf2cf3d8d 100644 --- a/package.json +++ b/package.json @@ -155,6 +155,7 @@ "pikaday": "^1.8.0", "popper.js": "^1.16.1", "portal-vue": "^2.1.7", + "postcss": "8.4.5", "prismjs": "^1.21.0", "prosemirror-markdown": "1.7.1", "prosemirror-model": "^1.16.1", @@ -239,7 +240,6 @@ "miragejs": "^0.1.40", "mock-apollo-client": "1.2.0", "nodemon": "^2.0.4", - "postcss": "^8.4.5", "prettier": "2.2.1", "prosemirror-schema-basic": "^1.1.2", "prosemirror-schema-list": "^1.1.6", diff --git a/spec/frontend/admin/applications/components/__snapshots__/delete_application_spec.js.snap b/spec/frontend/admin/applications/components/__snapshots__/delete_application_spec.js.snap new file mode 100644 index 00000000000..459a113b6d1 --- /dev/null +++ b/spec/frontend/admin/applications/components/__snapshots__/delete_application_spec.js.snap @@ -0,0 +1,20 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`DeleteApplication the modal component form matches the snapshot 1`] = ` +<form + action="application/path/1" + method="post" +> + <input + name="_method" + type="hidden" + value="delete" + /> + + <input + name="authenticity_token" + type="hidden" + value="mock-csrf-token" + /> +</form> +`; diff --git a/spec/frontend/admin/applications/components/delete_application_spec.js b/spec/frontend/admin/applications/components/delete_application_spec.js new file mode 100644 index 00000000000..20119b64952 --- /dev/null +++ b/spec/frontend/admin/applications/components/delete_application_spec.js @@ -0,0 +1,69 @@ +import { GlModal, GlSprintf } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import DeleteApplication from '~/admin/applications/components/delete_application.vue'; + +const path = 'application/path/1'; +const name = 'Application name'; + +jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' })); + +describe('DeleteApplication', () => { + let wrapper; + + const createComponent = () => { + wrapper = shallowMount(DeleteApplication, { + stubs: { + GlSprintf, + }, + }); + }; + + const findModal = () => wrapper.findComponent(GlModal); + const findForm = () => wrapper.find('form'); + + beforeEach(() => { + setFixtures(` + <button class="js-application-delete-button" data-path="${path}" data-name="${name}">Destroy</button> + `); + + createComponent(); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + describe('the modal component', () => { + beforeEach(() => { + wrapper.vm.$refs.deleteModal.show = jest.fn(); + document.querySelector('.js-application-delete-button').click(); + }); + + it('displays the modal component', () => { + const modal = findModal(); + + expect(modal.exists()).toBe(true); + expect(modal.props('title')).toBe('Confirm destroy application'); + expect(modal.text()).toBe(`Are you sure that you want to destroy ${name}`); + }); + + describe('form', () => { + it('matches the snapshot', () => { + expect(findForm().element).toMatchSnapshot(); + }); + + describe('form submission', () => { + let formSubmitSpy; + + beforeEach(() => { + formSubmitSpy = jest.spyOn(wrapper.vm.$refs.deleteForm, 'submit'); + findModal().vm.$emit('primary'); + }); + + it('submits the form on the modal primary action', () => { + expect(formSubmitSpy).toHaveBeenCalled(); + }); + }); + }); + }); +}); diff --git a/spec/frontend/sidebar/components/attention_requested_toggle_spec.js b/spec/frontend/sidebar/components/attention_requested_toggle_spec.js index 0939297a754..a9ae23c1624 100644 --- a/spec/frontend/sidebar/components/attention_requested_toggle_spec.js +++ b/spec/frontend/sidebar/components/attention_requested_toggle_spec.js @@ -16,7 +16,10 @@ describe('Attention require toggle', () => { }); it('renders button', () => { - factory({ type: 'reviewer', user: { attention_requested: false } }); + factory({ + type: 'reviewer', + user: { attention_requested: false, can_update_merge_request: true }, + }); expect(findToggle().exists()).toBe(true); }); @@ -28,7 +31,10 @@ describe('Attention require toggle', () => { `( 'renders $icon icon when attention_requested is $attentionRequested', ({ attentionRequested, icon }) => { - factory({ type: 'reviewer', user: { attention_requested: attentionRequested } }); + factory({ + type: 'reviewer', + user: { attention_requested: attentionRequested, can_update_merge_request: true }, + }); expect(findToggle().props('icon')).toBe(icon); }, @@ -41,27 +47,47 @@ describe('Attention require toggle', () => { `( 'renders button with variant $variant when attention_requested is $attentionRequested', ({ attentionRequested, variant }) => { - factory({ type: 'reviewer', user: { attention_requested: attentionRequested } }); + factory({ + type: 'reviewer', + user: { attention_requested: attentionRequested, can_update_merge_request: true }, + }); expect(findToggle().props('variant')).toBe(variant); }, ); it('emits toggle-attention-requested on click', async () => { - factory({ type: 'reviewer', user: { attention_requested: true } }); + factory({ + type: 'reviewer', + user: { attention_requested: true, can_update_merge_request: true }, + }); await findToggle().trigger('click'); expect(wrapper.emitted('toggle-attention-requested')[0]).toEqual([ { - user: { attention_requested: true }, + user: { attention_requested: true, can_update_merge_request: true }, callback: expect.anything(), }, ]); }); + it('does not emit toggle-attention-requested on click if can_update_merge_request is false', async () => { + factory({ + type: 'reviewer', + user: { attention_requested: true, can_update_merge_request: false }, + }); + + await findToggle().trigger('click'); + + expect(wrapper.emitted('toggle-attention-requested')).toBe(undefined); + }); + it('sets loading on click', async () => { - factory({ type: 'reviewer', user: { attention_requested: true } }); + factory({ + type: 'reviewer', + user: { attention_requested: true, can_update_merge_request: true }, + }); await findToggle().trigger('click'); @@ -69,14 +95,24 @@ describe('Attention require toggle', () => { }); it.each` - type | attentionRequested | tooltip - ${'reviewer'} | ${true} | ${AttentionRequestedToggle.i18n.removeAttentionRequested} - ${'reviewer'} | ${false} | ${AttentionRequestedToggle.i18n.attentionRequestedReviewer} - ${'assignee'} | ${false} | ${AttentionRequestedToggle.i18n.attentionRequestedAssignee} + type | attentionRequested | tooltip | canUpdateMergeRequest + ${'reviewer'} | ${true} | ${AttentionRequestedToggle.i18n.removeAttentionRequested} | ${true} + ${'reviewer'} | ${false} | ${AttentionRequestedToggle.i18n.attentionRequestedReviewer} | ${true} + ${'assignee'} | ${false} | ${AttentionRequestedToggle.i18n.attentionRequestedAssignee} | ${true} + ${'reviewer'} | ${true} | ${AttentionRequestedToggle.i18n.attentionRequestedNoPermission} | ${false} + ${'reviewer'} | ${false} | ${AttentionRequestedToggle.i18n.noAttentionRequestedNoPermission} | ${false} + ${'assignee'} | ${true} | ${AttentionRequestedToggle.i18n.attentionRequestedNoPermission} | ${false} + ${'assignee'} | ${false} | ${AttentionRequestedToggle.i18n.noAttentionRequestedNoPermission} | ${false} `( - 'sets tooltip as $tooltip when attention_requested is $attentionRequested and type is $type', - ({ type, attentionRequested, tooltip }) => { - factory({ type, user: { attention_requested: attentionRequested } }); + 'sets tooltip as $tooltip when attention_requested is $attentionRequested, type is $type and, can_update_merge_request is $canUpdateMergeRequest', + ({ type, attentionRequested, tooltip, canUpdateMergeRequest }) => { + factory({ + type, + user: { + attention_requested: attentionRequested, + can_update_merge_request: canUpdateMergeRequest, + }, + }); expect(findToggle().attributes('aria-label')).toBe(tooltip); }, diff --git a/spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb b/spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb index d22aa86dbe0..cfa03db52fe 100644 --- a/spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb +++ b/spec/lib/gitlab/background_migration/backfill_snippet_repositories_spec.rb @@ -78,6 +78,10 @@ RSpec.describe Gitlab::BackgroundMigration::BackfillSnippetRepositories, :migrat end shared_examples 'migration_bot user commits files' do + before do + allow(Gitlab::CurrentSettings).to receive(:default_branch_name).and_return('main') + end + it do subject @@ -89,6 +93,10 @@ RSpec.describe Gitlab::BackgroundMigration::BackfillSnippetRepositories, :migrat end shared_examples 'commits the file to the repository' do + before do + allow(Gitlab::CurrentSettings).to receive(:default_branch_name).and_return('main') + end + context 'when author can update snippet and use git' do it 'creates the repository and commit the file' do subject @@ -269,6 +277,10 @@ RSpec.describe Gitlab::BackgroundMigration::BackfillSnippetRepositories, :migrat let!(:snippet) { snippets.create!(id: 5, type: 'PersonalSnippet', author_id: other_user.id, file_name: file_name, content: content) } let(:ids) { [4, 5] } + before do + allow(Gitlab::CurrentSettings).to receive(:default_branch_name).and_return('main') + end + after do raw_repository(snippet).remove raw_repository(invalid_snippet).remove diff --git a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb index 229ab70a65d..39de9a65390 100644 --- a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb +++ b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb @@ -218,6 +218,26 @@ RSpec.describe Gitlab::GitalyClient::RepositoryService do end end + describe '#create_repository' do + it 'sends a create_repository message without arguments' do + expect_any_instance_of(Gitaly::RepositoryService::Stub) + .to receive(:create_repository) + .with(gitaly_request_with_path(storage_name, relative_path).and(gitaly_request_with_params(default_branch: '')), kind_of(Hash)) + .and_return(double) + + client.create_repository + end + + it 'sends a create_repository message with default branch' do + expect_any_instance_of(Gitaly::RepositoryService::Stub) + .to receive(:create_repository) + .with(gitaly_request_with_path(storage_name, relative_path).and(gitaly_request_with_params(default_branch: 'default-branch-name')), kind_of(Hash)) + .and_return(double) + + client.create_repository('default-branch-name') + end + end + describe '#create_from_snapshot' do it 'sends a create_repository_from_snapshot message' do expect_any_instance_of(Gitaly::RepositoryService::Stub) diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index e592a4964f5..215f83adf5d 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -3062,6 +3062,14 @@ RSpec.describe Repository do repository.create_if_not_exists end + it 'creates a repository with a default branch name' do + default_branch_name = 'branch-a' + repository.create_if_not_exists(default_branch_name) + repository.create_file(user, 'file', 'content', message: 'initial commit', branch_name: default_branch_name) + + expect(repository.root_ref).to eq(default_branch_name) + end + context 'it does nothing if the repository already existed' do let(:project) { create(:project, :repository) } diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb index 92e4bc7d1a9..e80814cef5c 100644 --- a/spec/models/snippet_spec.rb +++ b/spec/models/snippet_spec.rb @@ -667,6 +667,16 @@ RSpec.describe Snippet do expect(snippet.repository.exists?).to be_truthy end + it 'sets the default branch' do + expect(snippet).to receive(:default_branch).and_return('default-branch-1') + expect(subject).to be_truthy + + snippet.repository.create_file(snippet.author, 'file', 'content', message: 'initial commit', branch_name: 'default-branch-1') + + expect(snippet.repository.exists?).to be_truthy + expect(snippet.repository.root_ref).to eq('default-branch-1') + end + it 'tracks snippet repository' do expect do subject @@ -677,6 +687,7 @@ RSpec.describe Snippet do expect(snippet).to receive(:repository_storage).and_return('picked') expect(snippet).to receive(:repository_exists?).and_return(false) expect(snippet.repository).to receive(:create_if_not_exists) + allow(snippet).to receive(:default_branch).and_return('picked') subject @@ -899,22 +910,6 @@ RSpec.describe Snippet do end end - context 'when repository is empty' do - let(:snippet) { create(:snippet, :empty_repo) } - - before do - allow(Gitlab::CurrentSettings).to receive(:default_branch_name).and_return(default_branch) - end - - context 'when default branch in settings is different from "master"' do - let(:default_branch) { 'custom-branch' } - - it 'changes the HEAD reference to the default branch' do - expect { subject }.to change { File.read(head_path).squish }.to("ref: refs/heads/#{default_branch}") - end - end - end - context 'when repository is not empty' do let(:snippet) { create(:snippet, :empty_repo) } diff --git a/spec/presenters/projects/security/configuration_presenter_spec.rb b/spec/presenters/projects/security/configuration_presenter_spec.rb index 5f874ab5a3f..47ef0cf1192 100644 --- a/spec/presenters/projects/security/configuration_presenter_spec.rb +++ b/spec/presenters/projects/security/configuration_presenter_spec.rb @@ -13,8 +13,6 @@ RSpec.describe Projects::Security::ConfigurationPresenter do before do stub_licensed_features(licensed_scan_types.to_h { |type| [type, true] }) - - stub_feature_flags(corpus_management_ui: false) end describe '#to_html_data_attribute' do diff --git a/spec/support/shared_examples/features/manage_applications_shared_examples.rb b/spec/support/shared_examples/features/manage_applications_shared_examples.rb index 27d50c67f24..3a8267b21da 100644 --- a/spec/support/shared_examples/features/manage_applications_shared_examples.rb +++ b/spec/support/shared_examples/features/manage_applications_shared_examples.rb @@ -5,7 +5,7 @@ RSpec.shared_examples 'manage applications' do let_it_be(:application_name_changed) { "#{application_name} changed" } let_it_be(:application_redirect_uri) { 'https://foo.bar' } - it 'allows user to manage applications' do + it 'allows user to manage applications', :js do visit new_application_path expect(page).to have_content 'Add new application' diff --git a/yarn.lock b/yarn.lock index bf202d8a113..a03a9ea80d8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9447,15 +9447,7 @@ postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@^7.0.14, postcss@^7.0.5, postcss@^7.0.6: - version "7.0.39" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309" - integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA== - dependencies: - picocolors "^0.2.1" - source-map "^0.6.1" - -postcss@^8.2.1, postcss@^8.4.5: +postcss@8.4.5, postcss@^8.2.1, postcss@^8.4.5: version "8.4.5" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.5.tgz#bae665764dfd4c6fcc24dc0fdf7e7aa00cc77f95" integrity sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg== @@ -9464,6 +9456,14 @@ postcss@^8.2.1, postcss@^8.4.5: picocolors "^1.0.0" source-map-js "^1.0.1" +postcss@^7.0.14, postcss@^7.0.5, postcss@^7.0.6: + version "7.0.39" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309" + integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA== + dependencies: + picocolors "^0.2.1" + source-map "^0.6.1" + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" |