Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
e105f6b881
commit
e46506bcc3
2
Gemfile
2
Gemfile
|
@ -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'
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
|
@ -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);
|
||||
},
|
||||
});
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
import initApplicationDeleteButtons from '~/admin/applications';
|
||||
|
||||
initApplicationDeleteButtons();
|
|
@ -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,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
return this.type === 'reviewer'
|
||||
? this.$options.i18n.attentionRequestedReviewer
|
||||
: this.$options.i18n.attentionRequestedAssignee;
|
||||
if (this.user.can_update_merge_request) {
|
||||
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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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')
|
||||
|
||||
|
|
|
@ -33,3 +33,5 @@
|
|||
%td= render 'delete_form', application: application
|
||||
|
||||
= paginate @applications, theme: 'gitlab'
|
||||
|
||||
.js-application-delete-modal
|
||||
|
|
|
@ -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)) |
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 ""
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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>
|
||||
`;
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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);
|
||||
},
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) }
|
||||
|
||||
|
|
|
@ -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) }
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
18
yarn.lock
18
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"
|
||||
|
|
Loading…
Reference in New Issue