Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
135059c00c
commit
a99c04f018
|
@ -23,7 +23,7 @@ cache-workhorse:
|
|||
.cache-assets-base:
|
||||
extends:
|
||||
- .compile-assets-base
|
||||
- .ruby-node-cache
|
||||
- .assets-compile-cache
|
||||
- .caching:rules:cache-assets
|
||||
stage: prepare
|
||||
variables:
|
||||
|
|
|
@ -291,7 +291,7 @@ coverage-frontend:
|
|||
.qa-frontend-node:
|
||||
extends:
|
||||
- .default-retry
|
||||
- .yarn-cache
|
||||
- .qa-frontend-node-cache
|
||||
- .frontend:rules:qa-frontend-node
|
||||
stage: test
|
||||
needs: []
|
||||
|
|
|
@ -79,21 +79,30 @@
|
|||
policy: push # We want to rebuild the cache from scratch to ensure stale dependencies are cleaned up.
|
||||
|
||||
.assets-cache: &assets-cache
|
||||
key: "assets-debian-${DEBIAN_VERSION}-ruby-${RUBY_VERSION}-node-${NODE_ENV}-v4"
|
||||
key: "assets-debian-${DEBIAN_VERSION}-ruby-${RUBY_VERSION}-node-${NODE_ENV}-v5"
|
||||
# This list should match GITLAB_ASSETS_PATHS_LIST from scripts/gitlab_component_helpers.sh
|
||||
paths:
|
||||
- cached-assets-hash.txt
|
||||
- app/assets/javascripts/locale/**/app.js
|
||||
- public/assets/
|
||||
- tmp/cache/assets/sprockets/
|
||||
- tmp/cache/babel-loader/
|
||||
- tmp/cache/vue-loader/
|
||||
policy: pull
|
||||
|
||||
.assets-cache-push: &assets-cache-push
|
||||
<<: *assets-cache
|
||||
policy: push # We want to rebuild the cache from scratch to ensure stale dependencies are cleaned up.
|
||||
|
||||
.assets-tmp-cache: &assets-tmp-cache
|
||||
key: "assets-tmp-debian-${DEBIAN_VERSION}-ruby-${RUBY_VERSION}-node-${NODE_ENV}-v1"
|
||||
paths:
|
||||
- tmp/cache/assets/sprockets/
|
||||
- tmp/cache/babel-loader/
|
||||
- tmp/cache/vue-loader/
|
||||
policy: pull
|
||||
|
||||
.assets-tmp-cache-push: &assets-tmp-cache-push
|
||||
<<: *assets-tmp-cache
|
||||
policy: push # We want to rebuild the cache from scratch to ensure we don't pile up outdated cache files.
|
||||
|
||||
.storybook-node-modules-cache: &storybook-node-modules-cache
|
||||
key: "storybook-node-modules-${DEBIAN_VERSION}-${NODE_ENV}"
|
||||
paths:
|
||||
|
@ -201,6 +210,11 @@
|
|||
cache:
|
||||
- *node-modules-cache
|
||||
|
||||
.qa-frontend-node-cache:
|
||||
cache:
|
||||
- *node-modules-cache
|
||||
- *assets-tmp-cache
|
||||
|
||||
# TODO: Remove this as it's duplicating .assets-compile-cache-push
|
||||
.yarn-cache-push:
|
||||
cache:
|
||||
|
@ -211,12 +225,14 @@
|
|||
- *ruby-gems-cache
|
||||
- *node-modules-cache
|
||||
- *assets-cache
|
||||
- *assets-tmp-cache
|
||||
|
||||
.assets-compile-cache-push:
|
||||
cache:
|
||||
- *ruby-gems-cache # We don't push this cache as it's already rebuilt by `update-setup-test-env-cache`
|
||||
- *node-modules-cache-push
|
||||
- *assets-cache-push
|
||||
- *assets-tmp-cache-push
|
||||
|
||||
.storybook-yarn-cache:
|
||||
cache:
|
||||
|
|
|
@ -101,6 +101,7 @@ linters:
|
|||
- Style/IfUnlessModifier
|
||||
- Style/IndentationWidth
|
||||
- Style/Next
|
||||
- Style/SoleNestedConditional
|
||||
- Style/TrailingWhitespace
|
||||
- Style/WhileUntilModifier
|
||||
- Cop/StaticTranslationDefinition
|
||||
|
|
|
@ -1,29 +1,30 @@
|
|||
---
|
||||
# Cop supports --auto-correct.
|
||||
Rails/IndexWith:
|
||||
# Offense count: 54
|
||||
# Temporarily disabled due to too many offenses
|
||||
Enabled: false
|
||||
Details: grace period
|
||||
Exclude:
|
||||
- 'app/helpers/ci/jobs_helper.rb'
|
||||
- 'app/models/ci/build_trace_chunk.rb'
|
||||
- 'app/models/ci/processable.rb'
|
||||
- 'app/models/concerns/cached_commit.rb'
|
||||
- 'app/models/customer_relations/organization.rb'
|
||||
- 'app/models/environment.rb'
|
||||
- 'app/services/concerns/rate_limited_service.rb'
|
||||
- 'app/services/packages/rpm/parse_package_service.rb'
|
||||
- 'db/post_migrate/20210731132939_backfill_stage_event_hash.rb'
|
||||
- 'ee/app/models/concerns/identity_verifiable.rb'
|
||||
- 'ee/app/models/vulnerabilities/projects_grade.rb'
|
||||
- 'ee/lib/ee/gitlab/usage_data.rb'
|
||||
- 'ee/lib/gitlab/auth/group_saml/auth_hash.rb'
|
||||
- 'ee/lib/gitlab/custom_file_templates.rb'
|
||||
- 'ee/lib/gitlab/insights/reducers/count_per_label_reducer.rb'
|
||||
- 'ee/spec/lib/ee/gitlab/application_context_spec.rb'
|
||||
- 'ee/spec/models/ee/namespace_spec.rb'
|
||||
- 'ee/spec/models/sca/license_compliance_spec.rb'
|
||||
- 'ee/spec/views/admin/dashboard/index.html.haml_spec.rb'
|
||||
- 'lib/api/entities/project_integration.rb'
|
||||
- 'lib/api/helpers/packages/conan/api_helpers.rb'
|
||||
- 'lib/banzai/filter/repository_link_filter.rb'
|
||||
- 'lib/gitlab/background_migration/backfill_note_discussion_id.rb'
|
||||
- 'lib/gitlab/background_migration/update_jira_tracker_data_deployment_type_based_on_url.rb'
|
||||
- 'lib/gitlab/ci/ansi2html.rb'
|
||||
- 'lib/gitlab/ci/reports/security/finding.rb'
|
||||
|
@ -32,10 +33,12 @@ Rails/IndexWith:
|
|||
- 'lib/gitlab/database/count/exact_count_strategy.rb'
|
||||
- 'lib/gitlab/database/migration_helpers.rb'
|
||||
- 'lib/gitlab/database/obsolete_ignored_columns.rb'
|
||||
- 'lib/gitlab/database/tables_sorted_by_foreign_keys.rb'
|
||||
- 'lib/gitlab/issuable_metadata.rb'
|
||||
- 'lib/gitlab/template/base_template.rb'
|
||||
- 'lib/gitlab/usage_data.rb'
|
||||
- 'lib/google_api/cloud_platform/client.rb'
|
||||
- 'lib/tasks/gitlab/db.rake'
|
||||
- 'qa/qa/resource/reusable.rb'
|
||||
- 'scripts/trigger-build.rb'
|
||||
- 'spec/lib/gitlab/api_authentication/sent_through_builder_spec.rb'
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
---
|
||||
# Cop supports --auto-correct.
|
||||
Rails/RedundantForeignKey:
|
||||
# Offense count: 90
|
||||
# Temporarily disabled due to too many offenses
|
||||
Enabled: false
|
||||
Details: grace period
|
||||
Exclude:
|
||||
- 'app/models/alert_management/metric_image.rb'
|
||||
- 'app/models/ci/build.rb'
|
||||
|
@ -23,9 +21,11 @@ Rails/RedundantForeignKey:
|
|||
- 'app/models/commit_signatures/x509_commit_signature.rb'
|
||||
- 'app/models/concerns/analytics/cycle_analytics/stage.rb'
|
||||
- 'app/models/concerns/commit_signature.rb'
|
||||
- 'app/models/concerns/integrations/base_data_fields.rb'
|
||||
- 'app/models/group.rb'
|
||||
- 'app/models/group_group_link.rb'
|
||||
- 'app/models/integrations/zentao_tracker_data.rb'
|
||||
- 'app/models/incident_management/timeline_event.rb'
|
||||
- 'app/models/issue.rb'
|
||||
- 'app/models/member.rb'
|
||||
- 'app/models/merge_request.rb'
|
||||
- 'app/models/merge_request/metrics.rb'
|
||||
|
@ -35,9 +35,13 @@ Rails/RedundantForeignKey:
|
|||
- 'app/models/project.rb'
|
||||
- 'app/models/resource_state_event.rb'
|
||||
- 'app/models/review.rb'
|
||||
- 'app/models/time_tracking/timelog_category.rb'
|
||||
- 'app/models/user.rb'
|
||||
- 'app/models/users/phone_number_validation.rb'
|
||||
- 'app/models/work_item.rb'
|
||||
- 'app/models/x509_certificate.rb'
|
||||
- 'ee/app/models/allowed_email_domain.rb'
|
||||
- 'ee/app/models/audit_events/streaming/header.rb'
|
||||
- 'ee/app/models/boards/epic_board.rb'
|
||||
- 'ee/app/models/boards/epic_list_user_preference.rb'
|
||||
- 'ee/app/models/ci/sources/project.rb'
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
---
|
||||
# Cop supports --auto-correct.
|
||||
Style/SoleNestedConditional:
|
||||
# Offense count: 64
|
||||
# Temporarily disabled due to too many offenses
|
||||
Enabled: false
|
||||
Details: grace period
|
||||
Exclude:
|
||||
- 'app/controllers/admin/application_settings_controller.rb'
|
||||
- 'app/controllers/ldap/omniauth_callbacks_controller.rb'
|
||||
|
@ -17,7 +16,6 @@ Style/SoleNestedConditional:
|
|||
- 'app/models/network/graph.rb'
|
||||
- 'app/models/packages/package.rb'
|
||||
- 'app/models/protected_branch.rb'
|
||||
- 'app/services/ci/register_job_service.rb'
|
||||
- 'app/services/concerns/update_visibility_level.rb'
|
||||
- 'app/services/incident_management/incidents/create_service.rb'
|
||||
- 'app/services/merge_requests/update_service.rb'
|
||||
|
@ -27,9 +25,11 @@ Style/SoleNestedConditional:
|
|||
- 'app/services/projects/create_service.rb'
|
||||
- 'app/services/projects/hashed_storage/migration_service.rb'
|
||||
- 'app/services/projects/hashed_storage/rollback_service.rb'
|
||||
- 'app/workers/merge_requests/delete_source_branch_worker.rb'
|
||||
- 'ee/app/finders/ee/snippets_finder.rb'
|
||||
- 'ee/app/services/ee/issue_links/create_service.rb'
|
||||
- 'ee/app/services/ee/lfs/unlock_file_service.rb'
|
||||
- 'ee/app/services/ee/merge_requests/create_pipeline_service.rb'
|
||||
- 'ee/app/services/epics/tree_reorder_service.rb'
|
||||
- 'ee/app/services/geo/framework_repository_sync_service.rb'
|
||||
- 'ee/app/services/geo/repository_base_sync_service.rb'
|
||||
|
@ -43,6 +43,7 @@ Style/SoleNestedConditional:
|
|||
- 'lib/api/ci/helpers/runner.rb'
|
||||
- 'lib/api/deploy_keys.rb'
|
||||
- 'lib/api/helpers/label_helpers.rb'
|
||||
- 'lib/api/maven_packages.rb'
|
||||
- 'lib/api/users.rb'
|
||||
- 'lib/banzai/filter/ascii_doc_sanitization_filter.rb'
|
||||
- 'lib/banzai/filter/base_sanitization_filter.rb'
|
||||
|
@ -52,7 +53,9 @@ Style/SoleNestedConditional:
|
|||
- 'lib/gitlab/config/entry/configurable.rb'
|
||||
- 'lib/gitlab/config/entry/validators.rb'
|
||||
- 'lib/gitlab/database/each_database.rb'
|
||||
- 'lib/gitlab/database/load_balancing/load_balancer.rb'
|
||||
- 'lib/gitlab/email/handler/reply_processing.rb'
|
||||
- 'lib/gitlab/patch/database_config.rb'
|
||||
- 'lib/gitlab/user_access.rb'
|
||||
- 'lib/gitlab/utils.rb'
|
||||
- 'lib/gitlab/x509/signature.rb'
|
||||
|
@ -60,5 +63,5 @@ Style/SoleNestedConditional:
|
|||
- 'lib/mattermost/session.rb'
|
||||
- 'lib/object_storage/direct_upload.rb'
|
||||
- 'qa/qa/flow/login.rb'
|
||||
- 'qa/qa/support/page_error_checker.rb'
|
||||
- 'qa/qa/page/project/web_ide/edit.rb'
|
||||
- 'spec/spec_helper.rb'
|
||||
|
|
|
@ -111,7 +111,10 @@ export default {
|
|||
return this.getNoteableData.current_user.can_create_note;
|
||||
},
|
||||
canSetInternalNote() {
|
||||
return this.getNoteableData.current_user.can_update && (this.isIssue || this.isEpic);
|
||||
return (
|
||||
this.getNoteableData.current_user.can_create_confidential_note &&
|
||||
(this.isIssue || this.isEpic)
|
||||
);
|
||||
},
|
||||
issueActionButtonTitle() {
|
||||
const openOrClose = this.isOpen ? 'close' : 'reopen';
|
||||
|
|
|
@ -16,7 +16,7 @@ export const COMMENT_FORM = {
|
|||
bodyPlaceholderInternal: __('Write an internal note or drag your files here…'),
|
||||
internal: s__('Notes|Make this an internal note'),
|
||||
internalVisibility: s__(
|
||||
'Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher',
|
||||
'Notes|Internal notes are only visible to members with the role of Reporter or higher',
|
||||
),
|
||||
discussionThatNeedsResolution: __(
|
||||
'Discuss a specific suggestion or question that needs to be resolved.',
|
||||
|
|
|
@ -78,6 +78,17 @@ export const TRACKING_ACTION_CLICK_COMMIT_LINK = 'click_commit_link_from_package
|
|||
export const TRACKING_LABEL_PACKAGE_HISTORY = 'package_history';
|
||||
|
||||
export const SHOW_DELETE_SUCCESS_ALERT = 'showSuccessDeleteAlert';
|
||||
|
||||
export const DELETE_MODAL_TITLE = s__('PackageRegistry|Delete package version');
|
||||
export const DELETE_MODAL_CONTENT = s__(
|
||||
`PackageRegistry|You are about to delete version %{version} of %{name}. Are you sure?`,
|
||||
);
|
||||
export const DELETE_ALL_PACKAGE_FILES_MODAL_CONTENT = s__(
|
||||
`PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?`,
|
||||
);
|
||||
export const DELETE_LAST_PACKAGE_FILE_MODAL_CONTENT = s__(
|
||||
`PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?`,
|
||||
);
|
||||
export const DELETE_PACKAGE_FILE_ERROR_MESSAGE = s__(
|
||||
'PackageRegistry|Something went wrong while deleting the package asset.',
|
||||
);
|
||||
|
|
|
@ -44,6 +44,10 @@ import {
|
|||
DELETE_PACKAGE_FILES_ERROR_MESSAGE,
|
||||
DELETE_PACKAGE_FILES_SUCCESS_MESSAGE,
|
||||
DOWNLOAD_PACKAGE_ASSET_TRACKING_ACTION,
|
||||
DELETE_MODAL_TITLE,
|
||||
DELETE_MODAL_CONTENT,
|
||||
DELETE_ALL_PACKAGE_FILES_MODAL_CONTENT,
|
||||
DELETE_LAST_PACKAGE_FILE_MODAL_CONTENT,
|
||||
} from '~/packages_and_registries/package_registry/constants';
|
||||
|
||||
import destroyPackageFilesMutation from '~/packages_and_registries/package_registry/graphql/mutations/destroy_package_files.mutation.graphql';
|
||||
|
@ -86,6 +90,7 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
deletePackageModalContent: DELETE_MODAL_CONTENT,
|
||||
filesToDelete: [],
|
||||
mutationLoading: false,
|
||||
packageEntity: {},
|
||||
|
@ -206,18 +211,16 @@ export default {
|
|||
throw data.destroyPackageFiles.errors[0];
|
||||
}
|
||||
createAlert({
|
||||
message:
|
||||
ids.length === 1
|
||||
? DELETE_PACKAGE_FILE_SUCCESS_MESSAGE
|
||||
: DELETE_PACKAGE_FILES_SUCCESS_MESSAGE,
|
||||
message: this.isLastItem(ids)
|
||||
? DELETE_PACKAGE_FILE_SUCCESS_MESSAGE
|
||||
: DELETE_PACKAGE_FILES_SUCCESS_MESSAGE,
|
||||
variant: VARIANT_SUCCESS,
|
||||
});
|
||||
} catch (error) {
|
||||
createAlert({
|
||||
message:
|
||||
ids.length === 1
|
||||
? DELETE_PACKAGE_FILE_ERROR_MESSAGE
|
||||
: DELETE_PACKAGE_FILES_ERROR_MESSAGE,
|
||||
message: this.isLastItem(ids)
|
||||
? DELETE_PACKAGE_FILE_ERROR_MESSAGE
|
||||
: DELETE_PACKAGE_FILES_ERROR_MESSAGE,
|
||||
variant: VARIANT_WARNING,
|
||||
captureError: true,
|
||||
error,
|
||||
|
@ -231,18 +234,26 @@ export default {
|
|||
files.length === this.packageFiles.length &&
|
||||
!this.packageEntity.packageFiles?.pageInfo?.hasNextPage
|
||||
) {
|
||||
if (this.isLastItem(files)) {
|
||||
this.deletePackageModalContent = DELETE_LAST_PACKAGE_FILE_MODAL_CONTENT;
|
||||
} else {
|
||||
this.deletePackageModalContent = DELETE_ALL_PACKAGE_FILES_MODAL_CONTENT;
|
||||
}
|
||||
this.$refs.deleteModal.show();
|
||||
} else {
|
||||
this.filesToDelete = files;
|
||||
if (files.length === 1) {
|
||||
if (this.isLastItem(files)) {
|
||||
this.$refs.deleteFileModal.show();
|
||||
} else if (files.length > 1) {
|
||||
this.$refs.deleteFilesModal.show();
|
||||
}
|
||||
}
|
||||
},
|
||||
isLastItem(items) {
|
||||
return items.length === 1;
|
||||
},
|
||||
confirmFilesDelete() {
|
||||
if (this.filesToDelete.length === 1) {
|
||||
if (this.isLastItem(this.filesToDelete)) {
|
||||
this.track(DELETE_PACKAGE_FILE_TRACKING_ACTION);
|
||||
} else {
|
||||
this.track(DELETE_PACKAGE_FILES_TRACKING_ACTION);
|
||||
|
@ -250,12 +261,12 @@ export default {
|
|||
this.deletePackageFiles(this.filesToDelete.map((file) => file.id));
|
||||
this.filesToDelete = [];
|
||||
},
|
||||
resetDeleteModalContent() {
|
||||
this.deletePackageModalContent = DELETE_MODAL_CONTENT;
|
||||
},
|
||||
},
|
||||
i18n: {
|
||||
deleteModalTitle: s__(`PackageRegistry|Delete Package Version`),
|
||||
deleteModalContent: s__(
|
||||
`PackageRegistry|You are about to delete version %{version} of %{name}. Are you sure?`,
|
||||
),
|
||||
DELETE_MODAL_TITLE,
|
||||
deleteFileModalTitle: s__(`PackageRegistry|Delete package asset`),
|
||||
deleteFileModalContent: s__(
|
||||
`PackageRegistry|You are about to delete %{filename}. This is a destructive action that may render your package unusable. Are you sure?`,
|
||||
|
@ -371,10 +382,11 @@ export default {
|
|||
:action-primary="$options.modal.packageDeletePrimaryAction"
|
||||
:action-cancel="$options.modal.cancelAction"
|
||||
@primary="deletePackage(packageEntity)"
|
||||
@hidden="resetDeleteModalContent"
|
||||
@canceled="track($options.trackingActions.CANCEL_DELETE_PACKAGE)"
|
||||
>
|
||||
<template #modal-title>{{ $options.i18n.deleteModalTitle }}</template>
|
||||
<gl-sprintf :message="$options.i18n.deleteModalContent">
|
||||
<template #modal-title>{{ $options.i18n.DELETE_MODAL_TITLE }}</template>
|
||||
<gl-sprintf :message="deletePackageModalContent">
|
||||
<template #version>
|
||||
<strong>{{ packageEntity.version }}</strong>
|
||||
</template>
|
||||
|
@ -398,7 +410,7 @@ export default {
|
|||
@canceled="track($options.trackingActions.CANCEL_DELETE_PACKAGE_FILE)"
|
||||
>
|
||||
<template #modal-title>{{ $options.i18n.deleteFileModalTitle }}</template>
|
||||
<gl-sprintf v-if="filesToDelete.length === 1" :message="$options.i18n.deleteFileModalContent">
|
||||
<gl-sprintf v-if="isLastItem(filesToDelete)" :message="$options.i18n.deleteFileModalContent">
|
||||
<template #filename>
|
||||
<strong>{{ filesToDelete[0].fileName }}</strong>
|
||||
</template>
|
||||
|
|
|
@ -53,7 +53,7 @@ export default {
|
|||
:svg-path="svgPath"
|
||||
:svg-height="$options.svgHeight"
|
||||
>
|
||||
<template #description>
|
||||
<template v-if="registrationToken" #description>
|
||||
<gl-sprintf
|
||||
:message="
|
||||
s__(
|
||||
|
@ -71,5 +71,12 @@ export default {
|
|||
:registration-token="registrationToken"
|
||||
/>
|
||||
</template>
|
||||
<template v-else #description>
|
||||
{{
|
||||
s__(
|
||||
'Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator.',
|
||||
)
|
||||
}}
|
||||
</template>
|
||||
</gl-empty-state>
|
||||
</template>
|
||||
|
|
|
@ -246,16 +246,16 @@ export default {
|
|||
{{ contentError }}
|
||||
</template>
|
||||
</content-row>
|
||||
<slot v-else name="content">
|
||||
<div class="gl-w-full">
|
||||
<div v-else class="gl-w-full">
|
||||
<slot name="content">
|
||||
<dynamic-content
|
||||
v-for="(data, index) in content"
|
||||
:key="data.id || index"
|
||||
:data="data"
|
||||
:widget-name="widgetName"
|
||||
/>
|
||||
</div>
|
||||
</slot>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
@ -45,25 +45,24 @@ export default {
|
|||
</script>
|
||||
<template>
|
||||
<div
|
||||
class="gl-w-full mr-widget-content-row"
|
||||
class="gl-w-full gl-display-flex mr-widget-content-row gl-align-items-baseline"
|
||||
:class="{ 'gl-border-t gl-py-3 gl-pl-7': level === 2 }"
|
||||
>
|
||||
<div v-if="header" class="gl-mb-2">
|
||||
<strong v-safe-html="generatedHeader" class="gl-display-block"></strong
|
||||
><span
|
||||
v-if="generatedSubheader"
|
||||
v-safe-html="generatedSubheader"
|
||||
class="gl-display-block"
|
||||
></span>
|
||||
</div>
|
||||
<div class="gl-display-flex gl-align-items-baseline gl-w-full">
|
||||
<status-icon
|
||||
v-if="statusIconName"
|
||||
:level="2"
|
||||
:name="widgetName"
|
||||
:icon-name="statusIconName"
|
||||
/>
|
||||
<slot name="body"></slot>
|
||||
<status-icon v-if="statusIconName" :level="2" :name="widgetName" :icon-name="statusIconName" />
|
||||
<div>
|
||||
<slot name="header">
|
||||
<div v-if="header" class="gl-mb-2">
|
||||
<strong v-safe-html="generatedHeader" class="gl-display-block"></strong
|
||||
><span
|
||||
v-if="generatedSubheader"
|
||||
v-safe-html="generatedSubheader"
|
||||
class="gl-display-block"
|
||||
></span>
|
||||
</div>
|
||||
</slot>
|
||||
<div class="gl-display-flex gl-align-items-baseline gl-w-full">
|
||||
<slot name="body"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -81,6 +81,10 @@ class IssuePolicy < IssuablePolicy
|
|||
rule { can?(:set_issue_metadata) & can_read_crm_contacts }.policy do
|
||||
enable :set_issue_crm_contacts
|
||||
end
|
||||
|
||||
rule { can?(:reporter_access) }.policy do
|
||||
enable :mark_note_as_confidential
|
||||
end
|
||||
end
|
||||
|
||||
IssuePolicy.prepend_mod_with('IssuePolicy')
|
||||
|
|
|
@ -43,6 +43,10 @@ class IssueEntity < IssuableEntity
|
|||
can?(request.current_user, :create_note, issue)
|
||||
end
|
||||
|
||||
expose :can_create_confidential_note do |issue|
|
||||
can?(request.current_user, :mark_note_as_confidential, issue)
|
||||
end
|
||||
|
||||
expose :can_update do |issue|
|
||||
can?(request.current_user, :update_issue, issue)
|
||||
end
|
||||
|
|
|
@ -9,6 +9,11 @@
|
|||
%h1.page-title.gl-font-size-h-display
|
||||
= s_('TagsPage|New Tag')
|
||||
|
||||
%p.gl-text-secondary
|
||||
- link_start = '<a href="%{url}">'.html_safe % { url: new_namespace_project_release_path }
|
||||
- link_end = '</a>'.html_safe
|
||||
= s_('TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}.').html_safe % { link_start: link_start, link_end: link_end }
|
||||
|
||||
= form_tag namespace_project_tags_path, method: :post, id: "new-tag-form", class: "common-note-form tag-form js-quick-submit js-requires-input" do
|
||||
.form-group.row
|
||||
.col-sm-12
|
||||
|
@ -31,22 +36,7 @@
|
|||
= text_area_tag :message, @message, required: false, class: 'form-control', rows: 5, data: { qa_selector: "tag_message_field" }
|
||||
.form-text.text-muted
|
||||
= tag_description_help_text
|
||||
.form-group.row
|
||||
.col-sm-12
|
||||
= label_tag :release_description, s_('TagsPage|Release notes'), class: 'gl-mb-0'
|
||||
.form-text.mb-3
|
||||
- link_start = '<a href="%{url}" rel="noopener noreferrer" target="_blank">'.html_safe
|
||||
- releases_page_path = project_releases_path(@project)
|
||||
- releases_page_link_start = link_start % { url: releases_page_path }
|
||||
- docs_url = help_page_path('user/project/releases/index.md', anchor: 'create-a-release')
|
||||
- docs_link_start = link_start % { url: docs_url }
|
||||
- link_end = '</a>'.html_safe
|
||||
- replacements = { releases_page_link_start: releases_page_link_start, docs_link_start: docs_link_start, link_end: link_end }
|
||||
= s_('TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}').html_safe % replacements
|
||||
|
||||
= render layout: 'shared/md_preview', locals: { url: preview_markdown_path(@project), referenced_users: true } do
|
||||
= render 'shared/zen', attr: :release_description, classes: 'note-textarea', placeholder: s_('TagsPage|Write your release notes or drag files here…'), current_text: @release_description, qa_selector: 'release_notes_field'
|
||||
= render 'shared/notes/hints'
|
||||
.gl-display-flex
|
||||
= render Pajamas::ButtonComponent.new(variant: :confirm, button_options: { class: 'gl-mr-3', data: { qa_selector: "create_tag_button" }, type: 'submit' }) do
|
||||
= s_('TagsPage|Create tag')
|
||||
|
|
|
@ -9,9 +9,12 @@ product_category: web_ide
|
|||
value_type: number
|
||||
status: active
|
||||
time_frame: 7d
|
||||
instrumentation_class: AggregatedMetric
|
||||
data_source: redis_hll
|
||||
instrumentation_class: RedisHLLMetric
|
||||
options:
|
||||
aggregate:
|
||||
operator: OR
|
||||
attribute: user_id
|
||||
events:
|
||||
- g_edit_by_web_ide
|
||||
- g_edit_by_sfe
|
||||
|
|
|
@ -49,18 +49,34 @@ Example response:
|
|||
"version": "5.0.1",
|
||||
"package_manager": "bundler",
|
||||
"dependency_file_path": "Gemfile.lock",
|
||||
"vulnerabilities": [{
|
||||
"name": "DDoS",
|
||||
"severity": "unknown"
|
||||
}]
|
||||
"vulnerabilities": [
|
||||
{
|
||||
"name": "DDoS",
|
||||
"severity": "unknown",
|
||||
"id": 144827,
|
||||
"url": "https://gitlab.example.com/group/project/-/security/vulnerabilities/144827"
|
||||
}
|
||||
],
|
||||
"licenses": [
|
||||
{
|
||||
"name": "MIT",
|
||||
"url": "https://opensource.org/licenses/MIT"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "hanami",
|
||||
"version": "1.3.1",
|
||||
"package_manager": "bundler",
|
||||
"dependency_file_path": "Gemfile.lock",
|
||||
"vulnerabilities": []
|
||||
}
|
||||
"name": "hanami",
|
||||
"version": "1.3.1",
|
||||
"package_manager": "bundler",
|
||||
"dependency_file_path": "Gemfile.lock",
|
||||
"vulnerabilities": [],
|
||||
"licenses": [
|
||||
{
|
||||
"name": "MIT",
|
||||
"url": "https://opensource.org/licenses/MIT"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
|
|
|
@ -800,8 +800,7 @@ and `cache-assets:production` jobs that:
|
|||
|
||||
This job tries to download a generic package that contains GitLab compiled assets
|
||||
needed in the GitLab test suite (under `app/assets/javascripts/locale/**/app.js`,
|
||||
`public/assets`, `tmp/cache/assets/sprockets/`, `tmp/cache/babel-loader/`,
|
||||
and `tmp/cache/vue-loader/`).
|
||||
and `public/assets`).
|
||||
|
||||
- If the package URL returns a 404:
|
||||
1. It runs `bin/rake gitlab:assets:compile`, so that the GitLab assets are compiled.
|
||||
|
|
|
@ -801,6 +801,8 @@ module Gitlab
|
|||
|
||||
break nil if licensee_object.name.blank?
|
||||
|
||||
licensee_object.meta.nickname = "LICENSE" if licensee_object.key == "other"
|
||||
|
||||
licensee_object
|
||||
end
|
||||
rescue Licensee::InvalidLicense => e
|
||||
|
|
|
@ -58,8 +58,7 @@ namespace :gitlab do
|
|||
end
|
||||
|
||||
FileUtils.mkdir_p(path)
|
||||
FileUtils.chdir(path)
|
||||
File.write('sql_metrics_queries.json', Gitlab::Json.pretty_generate(queries))
|
||||
File.write(File.join(path, 'sql_metrics_queries.json'), Gitlab::Json.pretty_generate(queries))
|
||||
end
|
||||
|
||||
# Events for templates included via YAML-less Auto-DevOps
|
||||
|
|
|
@ -27165,7 +27165,7 @@ msgstr ""
|
|||
msgid "Notes|Expand replies"
|
||||
msgstr ""
|
||||
|
||||
msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
|
||||
msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
|
||||
msgstr ""
|
||||
|
||||
msgid "Notes|Last reply by %{name}"
|
||||
|
@ -28622,12 +28622,21 @@ msgstr ""
|
|||
msgid "PackageRegistry|Delete package asset"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Delete package version"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Delete selected"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Delete this package"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Duplicate packages"
|
||||
msgstr ""
|
||||
|
||||
|
@ -34894,6 +34903,9 @@ msgstr ""
|
|||
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
|
||||
msgstr ""
|
||||
|
||||
msgid "Runners|Runs untagged jobs"
|
||||
msgstr ""
|
||||
|
||||
|
@ -39460,6 +39472,9 @@ msgstr ""
|
|||
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
|
||||
msgstr ""
|
||||
|
||||
msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
|
||||
msgstr ""
|
||||
|
||||
msgid "TagsPage|Edit release"
|
||||
msgstr ""
|
||||
|
||||
|
@ -39481,15 +39496,9 @@ msgstr ""
|
|||
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
|
||||
msgstr ""
|
||||
|
||||
msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
|
||||
msgstr ""
|
||||
|
||||
msgid "TagsPage|Please type the following to confirm:"
|
||||
msgstr ""
|
||||
|
||||
msgid "TagsPage|Release notes"
|
||||
msgstr ""
|
||||
|
||||
msgid "TagsPage|Repository has no tags yet."
|
||||
msgstr ""
|
||||
|
||||
|
@ -39511,9 +39520,6 @@ msgstr ""
|
|||
msgid "TagsPage|Use git tag command to add a new one:"
|
||||
msgstr ""
|
||||
|
||||
msgid "TagsPage|Write your release notes or drag files here…"
|
||||
msgstr ""
|
||||
|
||||
msgid "TagsPage|Yes, delete protected tag"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
This software is licensed under the Other license
|
||||
=======
|
||||
|
||||
This Other license isn't a real license and won't be used by any real project.
|
||||
This license does not come with any guarantees. The author cannot be hold liable
|
||||
in any way, and users are permitted to do anything they want with the provided
|
||||
code.
|
|
@ -8,17 +8,9 @@ module QA
|
|||
view 'app/views/projects/tags/new.html.haml' do
|
||||
element :tag_name_field
|
||||
element :tag_message_field
|
||||
element :release_notes_field
|
||||
element :create_tag_button
|
||||
end
|
||||
|
||||
view 'app/views/shared/_zen.html.haml' do
|
||||
# This partial adds the `release_notes_field` selector passed from 'app/views/projects/tags/new.html.haml'
|
||||
# The checks below ensure that required lines are not removed without updating this page object
|
||||
element :_, "qa_selector = local_assigns.fetch(:qa_selector, '')" # rubocop:disable QA/ElementWithPattern
|
||||
element :_, "text_area_tag attr, current_text, data: { qa_selector: qa_selector }" # rubocop:disable QA/ElementWithPattern
|
||||
end
|
||||
|
||||
def fill_tag_name(text)
|
||||
fill_element(:tag_name_field, text)
|
||||
end
|
||||
|
@ -27,10 +19,6 @@ module QA
|
|||
fill_element(:tag_message_field, text)
|
||||
end
|
||||
|
||||
def fill_release_notes(text)
|
||||
fill_element(:release_notes_field, text)
|
||||
end
|
||||
|
||||
def click_create_tag_button
|
||||
click_element :create_tag_button
|
||||
end
|
||||
|
|
|
@ -44,7 +44,7 @@ module QA
|
|||
alias_method :ldap_username, :username
|
||||
|
||||
def password
|
||||
@password ||= SecureRandom.hex(8)
|
||||
@password ||= "Pa$$w0rd"
|
||||
end
|
||||
alias_method :ldap_password, :password
|
||||
|
||||
|
|
|
@ -36,11 +36,11 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
context 'on a project with a less commonly used LICENSE',
|
||||
context 'on a project with an unrecognized LICENSE',
|
||||
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/366843' do
|
||||
it_behaves_like 'project license detection' do
|
||||
let(:license_file_name) { 'GFDL-1.2-only' }
|
||||
let(:rendered_license_name) { 'Other' }
|
||||
let(:license_file_name) { 'other' }
|
||||
let(:rendered_license_name) { 'LICENSE' }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -31,7 +31,6 @@ module QA
|
|||
Page::Project::Tag::Show.perform do |show|
|
||||
expect(show).to have_tag_name(tag_name)
|
||||
expect(show).to have_tag_message(tag_message)
|
||||
expect(show).to have_tag_release_notes(tag_release_notes)
|
||||
expect(show).not_to have_element(:create_tag_button)
|
||||
end
|
||||
end
|
||||
|
@ -83,7 +82,6 @@ module QA
|
|||
Page::Project::Tag::New.perform do |new_tag|
|
||||
new_tag.fill_tag_name(name)
|
||||
new_tag.fill_tag_message(message)
|
||||
new_tag.fill_release_notes(release_notes)
|
||||
new_tag.click_create_tag_button
|
||||
end
|
||||
end
|
||||
|
|
|
@ -23,8 +23,8 @@ RSpec.describe QA::Resource::User do
|
|||
end
|
||||
|
||||
describe '#password' do
|
||||
it 'generates a random 16 character password by default' do
|
||||
expect(subject.password).to match(/\w{16}/)
|
||||
it 'generates a default password' do
|
||||
expect(subject.password).to match('Pa$$w0rd')
|
||||
end
|
||||
|
||||
it 'is possible to set the password' do
|
||||
|
|
|
@ -39,7 +39,8 @@ export GITLAB_WORKHORSE_PACKAGE="workhorse-${GITLAB_WORKHORSE_TREE}.tar.gz"
|
|||
export GITLAB_WORKHORSE_PACKAGE_URL="${API_PACKAGES_BASE_URL}/${GITLAB_WORKHORSE_FOLDER}/${GITLAB_WORKHORSE_TREE}/${GITLAB_WORKHORSE_PACKAGE}"
|
||||
|
||||
# Assets constants
|
||||
export GITLAB_ASSETS_PATHS_LIST="cached-assets-hash.txt app/assets/javascripts/locale/**/app.js public/assets/ tmp/cache/assets/sprockets/ tmp/cache/babel-loader/ tmp/cache/vue-loader/"
|
||||
export GITLAB_ASSETS_PATHS_LIST="cached-assets-hash.txt app/assets/javascripts/locale/**/app.js public/assets/"
|
||||
export GITLAB_ASSETS_PACKAGE_VERSION="v2" # bump this version each time GITLAB_ASSETS_PATHS_LIST is changed
|
||||
|
||||
export GITLAB_EDITION="ee"
|
||||
if [[ "${FOSS_ONLY:-no}" = "1" ]] || [[ "${CI_PROJECT_NAME}" = "gitlab-foss" ]]; then
|
||||
|
@ -47,7 +48,7 @@ if [[ "${FOSS_ONLY:-no}" = "1" ]] || [[ "${CI_PROJECT_NAME}" = "gitlab-foss" ]];
|
|||
fi
|
||||
|
||||
export GITLAB_ASSETS_HASH="${GITLAB_ASSETS_HASH:-"NO_HASH"}"
|
||||
export GITLAB_ASSETS_PACKAGE="assets-${NODE_ENV}-${GITLAB_EDITION}-${GITLAB_ASSETS_HASH}.tar.gz"
|
||||
export GITLAB_ASSETS_PACKAGE="assets-${NODE_ENV}-${GITLAB_EDITION}-${GITLAB_ASSETS_HASH}-${GITLAB_ASSETS_PACKAGE_VERSION}.tar.gz"
|
||||
export GITLAB_ASSETS_PACKAGE_URL="${API_PACKAGES_BASE_URL}/assets/${NODE_ENV}-${GITLAB_EDITION}-${GITLAB_ASSETS_HASH}/${GITLAB_ASSETS_PACKAGE}"
|
||||
|
||||
# Generic helper functions
|
||||
|
|
|
@ -297,6 +297,12 @@ function rspec_paralellized_job() {
|
|||
function retry_failed_rspec_examples() {
|
||||
local rspec_run_status=0
|
||||
|
||||
# Sometimes the file isn't created or is empty. In that case we exit(1) ourselves, otherwise, RSpec would
|
||||
# not run any examples an exit successfully, actually hiding failed tests!
|
||||
if [[ ! -f "${RSPEC_LAST_RUN_RESULTS_FILE}" ]] || [[ ! -s "${RSPEC_LAST_RUN_RESULTS_FILE}" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Keep track of the tests that are retried, later consolidated in a single file by the `rspec:flaky-tests-report` job
|
||||
local failed_examples=$(grep " failed" ${RSPEC_LAST_RUN_RESULTS_FILE})
|
||||
echo "${CI_JOB_URL}" > "${RETRIED_TESTS_REPORT_PATH}"
|
||||
|
|
|
@ -46,18 +46,6 @@ RSpec.describe 'Developer creates tag' do
|
|||
end
|
||||
end
|
||||
|
||||
it 'with multiline release notes parses the release note as Markdown' do
|
||||
create_tag_in_form(tag: 'v4.0', ref: 'master', desc: "Awesome release notes\n\n- hello\n- world")
|
||||
|
||||
expect(page).to have_current_path(
|
||||
project_tag_path(project, 'v4.0'), ignore_query: true)
|
||||
expect(page).to have_content 'v4.0'
|
||||
page.within '.description' do
|
||||
expect(page).to have_content 'Awesome release notes'
|
||||
expect(page).to have_selector('ul li', count: 2)
|
||||
end
|
||||
end
|
||||
|
||||
it 'opens dropdown for ref', :js do
|
||||
click_link 'New tag'
|
||||
ref_row = find('.form-group:nth-of-type(2) .col-sm-12')
|
||||
|
@ -73,19 +61,6 @@ RSpec.describe 'Developer creates tag' do
|
|||
end
|
||||
end
|
||||
|
||||
context 'from new tag page' do
|
||||
before do
|
||||
visit new_project_tag_path(project)
|
||||
end
|
||||
|
||||
it 'description has emoji autocomplete', :js do
|
||||
find('#release_description').native.send_keys('')
|
||||
fill_in 'release_description', with: ':'
|
||||
|
||||
expect(page).to have_selector('.atwho-view')
|
||||
end
|
||||
end
|
||||
|
||||
def create_tag_in_form(tag:, ref:, message: nil, desc: nil)
|
||||
click_link 'New tag'
|
||||
fill_in 'tag_name', with: tag
|
||||
|
|
|
@ -71,11 +71,19 @@ describe('issue_comment_form component', () => {
|
|||
};
|
||||
|
||||
const notableDataMockCanUpdateIssuable = createNotableDataMock({
|
||||
current_user: { can_update: true, can_create_note: true },
|
||||
current_user: { can_update: true, can_create_note: true, can_create_confidential_note: true },
|
||||
});
|
||||
|
||||
const notableDataMockCannotUpdateIssuable = createNotableDataMock({
|
||||
current_user: { can_update: false, can_create_note: true },
|
||||
current_user: {
|
||||
can_update: false,
|
||||
can_create_note: false,
|
||||
can_create_confidential_note: false,
|
||||
},
|
||||
});
|
||||
|
||||
const notableDataMockCannotCreateConfidentialNote = createNotableDataMock({
|
||||
current_user: { can_update: false, can_create_note: true, can_create_confidential_note: false },
|
||||
});
|
||||
|
||||
const mountComponent = ({
|
||||
|
@ -562,6 +570,17 @@ describe('issue_comment_form component', () => {
|
|||
expect(checkbox.element.checked).toBe(false);
|
||||
});
|
||||
|
||||
it('should not render checkbox if user is not at least a reporter', () => {
|
||||
mountComponent({
|
||||
mountFunction: mount,
|
||||
initialData: { note: 'confidential note' },
|
||||
noteableData: { ...notableDataMockCannotCreateConfidentialNote },
|
||||
});
|
||||
|
||||
const checkbox = findConfidentialNoteCheckbox();
|
||||
expect(checkbox.exists()).toBe(false);
|
||||
});
|
||||
|
||||
it.each`
|
||||
noteableType | rendered | message
|
||||
${'Issue'} | ${true} | ${'render'}
|
||||
|
|
|
@ -36,6 +36,7 @@ export const noteableDataMock = {
|
|||
can_create_note: true,
|
||||
can_update: true,
|
||||
can_award_emoji: true,
|
||||
can_create_confidential_note: true,
|
||||
},
|
||||
description: '',
|
||||
due_date: null,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { GlEmptyState, GlBadge, GlTabs, GlTab } from '@gitlab/ui';
|
||||
import { GlEmptyState, GlBadge, GlTabs, GlTab, GlSprintf } from '@gitlab/ui';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
|
||||
import VueApollo from 'vue-apollo';
|
||||
|
@ -86,11 +86,17 @@ describe('PackagesApp', () => {
|
|||
PackageTitle,
|
||||
DeletePackage,
|
||||
GlModal: {
|
||||
template: '<div></div>',
|
||||
template: `
|
||||
<div>
|
||||
<slot name="modal-title"></slot>
|
||||
<p><slot></slot></p>
|
||||
</div>
|
||||
`,
|
||||
methods: {
|
||||
show: jest.fn(),
|
||||
},
|
||||
},
|
||||
GlSprintf,
|
||||
GlTabs,
|
||||
GlTab,
|
||||
},
|
||||
|
@ -245,7 +251,9 @@ describe('PackagesApp', () => {
|
|||
|
||||
await findDeleteButton().trigger('click');
|
||||
|
||||
expect(findDeleteModal().exists()).toBe(true);
|
||||
expect(findDeleteModal().find('p').text()).toBe(
|
||||
'You are about to delete version 1.0.0 of @gitlab-org/package-15. Are you sure?',
|
||||
);
|
||||
});
|
||||
|
||||
describe('successful request', () => {
|
||||
|
@ -359,6 +367,12 @@ describe('PackagesApp', () => {
|
|||
|
||||
expect(showDeletePackageSpy).toHaveBeenCalled();
|
||||
expect(showDeleteFileSpy).not.toHaveBeenCalled();
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
expect(findDeleteModal().find('p').text()).toBe(
|
||||
'Deleting the last package asset will remove version 1.0.0 of @gitlab-org/package-15. Are you sure?',
|
||||
);
|
||||
});
|
||||
|
||||
it('confirming on the modal sets the loading state', async () => {
|
||||
|
@ -533,6 +547,12 @@ describe('PackagesApp', () => {
|
|||
findPackageFiles().vm.$emit('delete-files', packageFiles());
|
||||
|
||||
expect(showDeletePackageSpy).toHaveBeenCalled();
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
expect(findDeleteModal().find('p').text()).toBe(
|
||||
'Deleting all package assets will remove version 1.0.0 of @gitlab-org/package-15. Are you sure?',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,6 +8,7 @@ import RunnerListEmptyState from '~/runner/components/runner_list_empty_state.vu
|
|||
|
||||
const mockSvgPath = 'mock-svg-path.svg';
|
||||
const mockFilteredSvgPath = 'mock-filtered-svg-path.svg';
|
||||
const mockRegistrationToken = 'REGISTRATION_TOKEN';
|
||||
|
||||
describe('RunnerListEmptyState', () => {
|
||||
let wrapper;
|
||||
|
@ -21,6 +22,7 @@ describe('RunnerListEmptyState', () => {
|
|||
propsData: {
|
||||
svgPath: mockSvgPath,
|
||||
filteredSvgPath: mockFilteredSvgPath,
|
||||
registrationToken: mockRegistrationToken,
|
||||
...props,
|
||||
},
|
||||
directives: {
|
||||
|
@ -35,27 +37,52 @@ describe('RunnerListEmptyState', () => {
|
|||
};
|
||||
|
||||
describe('when search is not filtered', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
const title = s__('Runners|Get started with runners');
|
||||
|
||||
describe('when there is a registration token', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
|
||||
it('renders an illustration', () => {
|
||||
expect(findEmptyState().props('svgPath')).toBe(mockSvgPath);
|
||||
});
|
||||
|
||||
it('displays "no results" text with instructions', () => {
|
||||
const desc = s__(
|
||||
'Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner.',
|
||||
);
|
||||
|
||||
expect(findEmptyState().text()).toMatchInterpolatedText(`${title} ${desc}`);
|
||||
});
|
||||
|
||||
it('opens a runner registration instructions modal with a link', () => {
|
||||
const { value } = getBinding(findLink().element, 'gl-modal');
|
||||
|
||||
expect(findRunnerInstructionsModal().props('modalId')).toEqual(value);
|
||||
});
|
||||
});
|
||||
|
||||
it('renders an illustration', () => {
|
||||
expect(findEmptyState().props('svgPath')).toBe(mockSvgPath);
|
||||
});
|
||||
describe('when there is no registration token', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({ props: { registrationToken: null } });
|
||||
});
|
||||
|
||||
it('displays "no results" text', () => {
|
||||
const title = s__('Runners|Get started with runners');
|
||||
const desc = s__(
|
||||
'Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner.',
|
||||
);
|
||||
it('renders an illustration', () => {
|
||||
expect(findEmptyState().props('svgPath')).toBe(mockSvgPath);
|
||||
});
|
||||
|
||||
expect(findEmptyState().text()).toMatchInterpolatedText(`${title} ${desc}`);
|
||||
});
|
||||
it('displays "no results" text', () => {
|
||||
const desc = s__(
|
||||
'Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator.',
|
||||
);
|
||||
|
||||
it('opens a runner registration instructions modal with a link', () => {
|
||||
const { value } = getBinding(findLink().element, 'gl-modal');
|
||||
expect(findEmptyState().text()).toMatchInterpolatedText(`${title} ${desc}`);
|
||||
});
|
||||
|
||||
expect(findRunnerInstructionsModal().props('modalId')).toEqual(value);
|
||||
it('has no registration instructions link', () => {
|
||||
expect(findLink().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -35,11 +35,13 @@ describe('~/vue_merge_request_widget/components/widget/widget_content_row.vue',
|
|||
statusIconName: 'success',
|
||||
},
|
||||
slots: {
|
||||
header: '<span>this is a header</span>',
|
||||
body: '<span>this is a body</span>',
|
||||
},
|
||||
});
|
||||
|
||||
expect(wrapper.findByText('this is a body').exists()).toBe(true);
|
||||
expect(wrapper.findByText('this is a header').exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1801,7 +1801,7 @@ RSpec.describe Gitlab::Git::Repository do
|
|||
subject(:license) { repository.license(from_gitaly) }
|
||||
|
||||
context 'when no license file can be found' do
|
||||
let(:project) { create(:project, :repository) }
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
let(:repository) { project.repository.raw_repository }
|
||||
|
||||
before do
|
||||
|
@ -1814,9 +1814,25 @@ RSpec.describe Gitlab::Git::Repository do
|
|||
context 'when an mit license is found' do
|
||||
it { is_expected.to have_attributes(key: 'mit') }
|
||||
end
|
||||
|
||||
context 'when license is not recognized ' do
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
let(:repository) { project.repository.raw_repository }
|
||||
|
||||
before do
|
||||
project.repository.update_file(
|
||||
project.owner,
|
||||
'LICENSE',
|
||||
'This software is licensed under the Dummy license.',
|
||||
message: 'Update license',
|
||||
branch_name: 'master')
|
||||
end
|
||||
|
||||
it { is_expected.to have_attributes(key: 'other', nickname: 'LICENSE') }
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not crash when license is not recognized' do
|
||||
it 'does not crash when license is invalid' do
|
||||
expect(Licensee::License).to receive(:new)
|
||||
.and_raise(Licensee::InvalidLicense)
|
||||
|
||||
|
|
|
@ -235,10 +235,27 @@ RSpec.describe Gitlab::Usage::Metrics::Aggregates::Aggregate, :clean_gitlab_redi
|
|||
end
|
||||
end
|
||||
|
||||
it 'allows for YAML aliases in aggregated metrics configs' do
|
||||
expect(YAML).to receive(:safe_load).with(kind_of(String), aliases: true).at_least(:once)
|
||||
context 'legacy aggregated metrics configuration' do
|
||||
let(:temp_dir) { Dir.mktmpdir }
|
||||
let(:temp_file) { Tempfile.new(%w[common .yml], temp_dir) }
|
||||
|
||||
described_class.new(recorded_at)
|
||||
before do
|
||||
stub_const("#{namespace}::AGGREGATED_METRICS_PATH", File.expand_path('*.yml', temp_dir))
|
||||
File.open(temp_file.path, "w+b") do |file|
|
||||
file.write [aggregated_metric(name: "gmau_1", time_frame: '7d')].to_yaml
|
||||
end
|
||||
end
|
||||
|
||||
after do
|
||||
temp_file.unlink
|
||||
FileUtils.remove_entry(temp_dir) if Dir.exist?(temp_dir)
|
||||
end
|
||||
|
||||
it 'allows for YAML aliases in aggregated metrics configs' do
|
||||
expect(YAML).to receive(:safe_load).with(kind_of(String), aliases: true).at_least(:once)
|
||||
|
||||
described_class.new(recorded_at)
|
||||
end
|
||||
end
|
||||
|
||||
describe '.aggregated_metrics_weekly_data' do
|
||||
|
|
|
@ -85,7 +85,7 @@ RSpec.describe IssuePolicy do
|
|||
|
||||
it 'allows guests to read issues' do
|
||||
expect(permissions(guest, issue)).to be_allowed(:read_issue, :read_issue_iid)
|
||||
expect(permissions(guest, issue)).to be_disallowed(:update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
|
||||
expect(permissions(guest, issue)).to be_disallowed(:update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality, :mark_note_as_confidential)
|
||||
|
||||
expect(permissions(guest, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid)
|
||||
expect(permissions(guest, issue_no_assignee)).to be_disallowed(:update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
|
||||
|
@ -93,10 +93,10 @@ RSpec.describe IssuePolicy do
|
|||
expect(permissions(guest, new_issue)).to be_allowed(:create_issue, :set_issue_metadata, :set_confidentiality)
|
||||
end
|
||||
|
||||
it 'allows reporters to read, update, and admin issues' do
|
||||
it 'allows reporters to read, update, admin and create confidential notes' do
|
||||
expect(permissions(reporter, issue)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
|
||||
expect(permissions(reporter, issue_no_assignee)).to be_allowed(:read_issue, :read_issue_iid, :update_issue, :admin_issue, :set_issue_metadata, :set_confidentiality)
|
||||
expect(permissions(reporter, new_issue)).to be_allowed(:create_issue, :set_issue_metadata, :set_confidentiality)
|
||||
expect(permissions(reporter, new_issue)).to be_allowed(:create_issue, :set_issue_metadata, :set_confidentiality, :mark_note_as_confidential)
|
||||
end
|
||||
|
||||
it 'allows reporters from group links to read, update, and admin issues' do
|
||||
|
|
|
@ -150,4 +150,6 @@ RSpec.describe IssueEntity do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'issuable entity current_user properties'
|
||||
end
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_examples 'issuable entity current_user properties' do
|
||||
describe 'can_create_confidential_note' do
|
||||
subject do
|
||||
described_class.new(resource, request: request)
|
||||
.as_json[:current_user][:can_create_confidential_note]
|
||||
end
|
||||
|
||||
context 'when user can create confidential notes' do
|
||||
before do
|
||||
resource.resource_parent.add_reporter(user)
|
||||
end
|
||||
|
||||
it { is_expected.to be(true) }
|
||||
end
|
||||
|
||||
context 'when user cannot create confidential notes' do
|
||||
it { is_expected.to eq(false) }
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue