Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-10-12 12:09:35 +00:00
parent 135059c00c
commit a99c04f018
42 changed files with 358 additions and 175 deletions

View File

@ -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:

View File

@ -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: []

View File

@ -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:

View File

@ -101,6 +101,7 @@ linters:
- Style/IfUnlessModifier
- Style/IndentationWidth
- Style/Next
- Style/SoleNestedConditional
- Style/TrailingWhitespace
- Style/WhileUntilModifier
- Cop/StaticTranslationDefinition

View File

@ -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'

View File

@ -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'

View File

@ -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'

View File

@ -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';

View File

@ -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.',

View File

@ -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.',
);

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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')

View File

@ -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

View File

@ -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')

View File

@ -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

View File

@ -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"
}
]
}
]
```

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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 ""

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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}"

View File

@ -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

View File

@ -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'}

View File

@ -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,

View File

@ -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?',
);
});
});
});

View File

@ -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);
});
});
});

View File

@ -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);
});
});

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -150,4 +150,6 @@ RSpec.describe IssueEntity do
end
end
end
it_behaves_like 'issuable entity current_user properties'
end

View File

@ -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