diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-06-08 06:08:19 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-06-08 06:08:19 +0300 |
commit | bf293d47937b3332462689c3fecc868706553f3a (patch) | |
tree | 47f0f1063aa27e4529c23068537ce45d6adb4cf0 | |
parent | 356e3c444dc8fab920d3547461b6ae721c5eb50f (diff) |
Add latest changes from gitlab-org/gitlab@master
61 files changed, 614 insertions, 299 deletions
diff --git a/.gitlab/issue_templates/Geo Replicate a new Git repository type.md b/.gitlab/issue_templates/Geo Replicate a new Git repository type.md index e93c5d79964..88c82688273 100644 --- a/.gitlab/issue_templates/Geo Replicate a new Git repository type.md +++ b/.gitlab/issue_templates/Geo Replicate a new Git repository type.md @@ -542,7 +542,6 @@ That's all of the required database changes. belongs_to :cool_widget, inverse_of: :cool_widget_state - validates :verification_failure, length: { maximum: 255 } validates :verification_state, :cool_widget, presence: true end end diff --git a/.gitlab/issue_templates/Geo Replicate a new blob type.md b/.gitlab/issue_templates/Geo Replicate a new blob type.md index 2183ba9c384..edef88cb022 100644 --- a/.gitlab/issue_templates/Geo Replicate a new blob type.md +++ b/.gitlab/issue_templates/Geo Replicate a new blob type.md @@ -509,7 +509,6 @@ That's all of the required database changes. belongs_to :cool_widget, inverse_of: :cool_widget_state - validates :verification_failure, length: { maximum: 255 } validates :verification_state, :cool_widget, presence: true end end diff --git a/app/assets/javascripts/analytics/shared/constants.js b/app/assets/javascripts/analytics/shared/constants.js index 9463286e53e..25699c17b10 100644 --- a/app/assets/javascripts/analytics/shared/constants.js +++ b/app/assets/javascripts/analytics/shared/constants.js @@ -133,15 +133,15 @@ export const METRIC_TOOLTIPS = { }, [VULNERABILITY_METRICS.CRITICAL]: { description: s__('ValueStreamAnalytics|Critical vulnerabilities over time.'), - groupLink: '-/security/vulnerabilities', - projectLink: '-/security/vulnerability_report', - docsLink: helpPagePath('user/application_security/vulnerability_report/index'), + groupLink: '-/security/vulnerabilities?severity=CRITICAL', + projectLink: '-/security/vulnerability_report?severity=CRITICAL', + docsLink: helpPagePath('user/application_security/vulnerabilities/severities.html'), }, [VULNERABILITY_METRICS.HIGH]: { description: s__('ValueStreamAnalytics|High vulnerabilities over time.'), - groupLink: '-/security/vulnerabilities', - projectLink: '-/security/vulnerability_report', - docsLink: helpPagePath('user/application_security/vulnerability_report/index'), + groupLink: '-/security/vulnerabilities?severity=HIGH', + projectLink: '-/security/vulnerability_report?severity=HIGH', + docsLink: helpPagePath('user/application_security/vulnerabilities/severities.html'), }, [MERGE_REQUEST_METRICS.THROUGHPUT]: { description: s__('ValueStreamAnalytics|The number of merge requests merged by month.'), diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue index f644c69f0a0..c0a9643e59e 100644 --- a/app/assets/javascripts/diffs/components/app.vue +++ b/app/assets/javascripts/diffs/components/app.vue @@ -90,22 +90,6 @@ export default { ALERT_COLLAPSED_FILES, }, props: { - endpoint: { - type: String, - required: true, - }, - endpointMetadata: { - type: String, - required: true, - }, - endpointBatch: { - type: String, - required: true, - }, - endpointDiffForPath: { - type: String, - required: true, - }, endpointCoverage: { type: String, required: false, @@ -116,15 +100,6 @@ export default { required: false, default: '', }, - endpointUpdateUser: { - type: String, - required: false, - default: '', - }, - projectPath: { - type: String, - required: true, - }, shouldShow: { type: Boolean, required: false, @@ -144,51 +119,6 @@ export default { required: false, default: '', }, - isFluidLayout: { - type: Boolean, - required: false, - default: false, - }, - dismissEndpoint: { - type: String, - required: false, - default: '', - }, - showSuggestPopover: { - type: Boolean, - required: false, - default: false, - }, - fileByFileUserPreference: { - type: Boolean, - required: false, - default: false, - }, - defaultSuggestionCommitMessage: { - type: String, - required: false, - default: '', - }, - rehydratedMrReviews: { - type: Object, - required: false, - default: () => ({}), - }, - sourceProjectDefaultUrl: { - type: String, - required: false, - default: '', - }, - sourceProjectFullPath: { - type: String, - required: false, - default: '', - }, - isForked: { - type: Boolean, - required: false, - default: false, - }, }, data() { const treeWidth = @@ -343,21 +273,6 @@ export default { renderFileTree: 'adjustView', }, mounted() { - this.setBaseConfig({ - endpoint: this.endpoint, - endpointMetadata: this.endpointMetadata, - endpointBatch: this.endpointBatch, - endpointDiffForPath: this.endpointDiffForPath, - endpointCoverage: this.endpointCoverage, - endpointUpdateUser: this.endpointUpdateUser, - projectPath: this.projectPath, - dismissEndpoint: this.dismissEndpoint, - showSuggestPopover: this.showSuggestPopover, - viewDiffsFileByFile: this.fileByFileUserPreference || false, - defaultSuggestionCommitMessage: this.defaultSuggestionCommitMessage, - mrReviews: this.rehydratedMrReviews, - }); - if (this.endpointCodequality) { this.setCodequalityEndpoint(this.endpointCodequality); } diff --git a/app/assets/javascripts/diffs/index.js b/app/assets/javascripts/diffs/index.js index 53c27632c4f..29cf90dcbe2 100644 --- a/app/assets/javascripts/diffs/index.js +++ b/app/assets/javascripts/diffs/index.js @@ -9,8 +9,6 @@ import eventHub from '../notes/event_hub'; import DiffsApp from './components/app.vue'; import { TREE_LIST_STORAGE_KEY, DIFF_WHITESPACE_COOKIE_NAME } from './constants'; -import { getReviewsForMergeRequest } from './utils/file_reviews'; -import { getDerivedMergeRequestInformation } from './utils/merge_request'; export default function initDiffsApp(store = notesStore) { const el = document.getElementById('js-diffs-app'); @@ -32,26 +30,13 @@ export default function initDiffsApp(store = notesStore) { }, data() { return { - endpoint: dataset.endpoint, - endpointMetadata: dataset.endpointMetadata || '', - endpointBatch: dataset.endpointBatch || '', - endpointDiffForPath: dataset.endpointDiffForPath || '', endpointCoverage: dataset.endpointCoverage || '', endpointCodequality: dataset.endpointCodequality || '', - endpointUpdateUser: dataset.updateCurrentUserPath, - projectPath: dataset.projectPath, helpPagePath: dataset.helpPagePath, currentUser: JSON.parse(dataset.currentUserData) || {}, changesEmptyStateIllustration: dataset.changesEmptyStateIllustration, - isFluidLayout: parseBoolean(dataset.isFluidLayout), dismissEndpoint: dataset.dismissEndpoint, - showSuggestPopover: parseBoolean(dataset.showSuggestPopover), showWhitespaceDefault: parseBoolean(dataset.showWhitespaceDefault), - viewDiffsFileByFile: parseBoolean(dataset.fileByFileDefault), - defaultSuggestionCommitMessage: dataset.defaultSuggestionCommitMessage, - sourceProjectDefaultUrl: dataset.sourceProjectDefaultUrl, - sourceProjectFullPath: dataset.sourceProjectFullPath, - isForked: parseBoolean(dataset.isForked), }; }, computed: { @@ -90,31 +75,14 @@ export default function initDiffsApp(store = notesStore) { ...mapActions('diffs', ['setRenderTreeList', 'setShowWhitespace']), }, render(createElement) { - const { mrPath } = getDerivedMergeRequestInformation({ endpoint: this.endpoint }); - return createElement('diffs-app', { props: { - endpoint: this.endpoint, - endpointMetadata: this.endpointMetadata, - endpointBatch: this.endpointBatch, - endpointDiffForPath: this.endpointDiffForPath, endpointCoverage: this.endpointCoverage, endpointCodequality: this.endpointCodequality, - endpointUpdateUser: this.endpointUpdateUser, currentUser: this.currentUser, - projectPath: this.projectPath, helpPagePath: this.helpPagePath, shouldShow: this.activeTab === 'diffs', changesEmptyStateIllustration: this.changesEmptyStateIllustration, - isFluidLayout: this.isFluidLayout, - dismissEndpoint: this.dismissEndpoint, - showSuggestPopover: this.showSuggestPopover, - fileByFileUserPreference: this.viewDiffsFileByFile, - defaultSuggestionCommitMessage: this.defaultSuggestionCommitMessage, - rehydratedMrReviews: getReviewsForMergeRequest(mrPath), - sourceProjectDefaultUrl: this.sourceProjectDefaultUrl, - sourceProjectFullPath: this.sourceProjectFullPath, - isForked: this.isForked, }, }); }, diff --git a/app/assets/javascripts/lib/utils/constants.js b/app/assets/javascripts/lib/utils/constants.js index fb69a61880a..d1e5e4eea13 100644 --- a/app/assets/javascripts/lib/utils/constants.js +++ b/app/assets/javascripts/lib/utils/constants.js @@ -27,7 +27,7 @@ export const DRAWER_Z_INDEX = 252; export const MIN_USERNAME_LENGTH = 2; -export const BYTES_FORMAT_BYTES = 'Bytes'; +export const BYTES_FORMAT_BYTES = 'B'; export const BYTES_FORMAT_KIB = 'KiB'; export const BYTES_FORMAT_MIB = 'MiB'; export const BYTES_FORMAT_GIB = 'GiB'; diff --git a/app/assets/javascripts/lib/utils/number_utils.js b/app/assets/javascripts/lib/utils/number_utils.js index d64f84d2040..0e943cdb623 100644 --- a/app/assets/javascripts/lib/utils/number_utils.js +++ b/app/assets/javascripts/lib/utils/number_utils.js @@ -106,7 +106,7 @@ export function numberToHumanSize(size, digits = 2) { switch (format) { case BYTES_FORMAT_BYTES: - return sprintf(__('%{size} bytes'), { size: humanSize }); + return sprintf(__('%{size} B'), { size: humanSize }); case BYTES_FORMAT_KIB: return sprintf(__('%{size} KiB'), { size: humanSize }); case BYTES_FORMAT_MIB: diff --git a/app/assets/javascripts/mr_notes/init.js b/app/assets/javascripts/mr_notes/init.js index 9852efea95f..e8e3376cee2 100644 --- a/app/assets/javascripts/mr_notes/init.js +++ b/app/assets/javascripts/mr_notes/init.js @@ -1,12 +1,14 @@ import { parseBoolean } from '~/lib/utils/common_utils'; -import store from '~/mr_notes/stores'; +import mrNotes from '~/mr_notes/stores'; import { getLocationHash } from '~/lib/utils/url_utility'; import eventHub from '~/notes/event_hub'; import { initReviewBar } from '~/batch_comments'; import { initDiscussionCounter } from '~/mr_notes/discussion_counter'; import { initOverviewTabCounter } from '~/mr_notes/init_count'; +import { getDerivedMergeRequestInformation } from '~/diffs/utils/merge_request'; +import { getReviewsForMergeRequest } from '~/diffs/utils/file_reviews'; -function setupMrNotesState(notesDataset) { +function setupMrNotesState(store, notesDataset, diffsDataset) { const noteableData = JSON.parse(notesDataset.noteableData); noteableData.noteableType = notesDataset.noteableType; noteableData.targetType = notesDataset.targetType; @@ -15,26 +17,43 @@ function setupMrNotesState(notesDataset) { const currentUserData = JSON.parse(notesDataset.currentUserData); const endpoints = { metadata: notesDataset.endpointMetadata }; + const { mrPath } = getDerivedMergeRequestInformation({ endpoint: diffsDataset.endpoint }); + store.dispatch('setNotesData', notesData); store.dispatch('setNoteableData', noteableData); store.dispatch('setUserData', currentUserData); store.dispatch('setTargetNoteHash', getLocationHash()); store.dispatch('setEndpoints', endpoints); + store.dispatch('diffs/setBaseConfig', { + endpoint: diffsDataset.endpoint, + endpointMetadata: diffsDataset.endpointMetadata, + endpointBatch: diffsDataset.endpointBatch, + endpointDiffForPath: diffsDataset.endpointDiffForPath, + endpointCoverage: diffsDataset.endpointCoverage, + endpointUpdateUser: diffsDataset.updateCurrentUserPath, + projectPath: diffsDataset.projectPath, + dismissEndpoint: diffsDataset.dismissEndpoint, + showSuggestPopover: parseBoolean(diffsDataset.showSuggestPopover), + viewDiffsFileByFile: parseBoolean(diffsDataset.fileByFileDefault), + defaultSuggestionCommitMessage: diffsDataset.defaultSuggestionCommitMessage, + mrReviews: getReviewsForMergeRequest(mrPath), + }); } -export function initMrStateLazyLoad({ reviewBarParams } = {}) { +export function initMrStateLazyLoad(store = mrNotes, { reviewBarParams } = {}) { store.dispatch('setActiveTab', window.mrTabs.getCurrentAction()); window.mrTabs.eventHub.$on('MergeRequestTabChange', (value) => store.dispatch('setActiveTab', value), ); const discussionsEl = document.getElementById('js-vue-mr-discussions'); - const notesDataset = discussionsEl.dataset; + const diffsEl = document.getElementById('js-diffs-app'); + let stop = () => {}; stop = store.watch( (state) => state.page.activeTab, (activeTab) => { - setupMrNotesState(notesDataset); + setupMrNotesState(store, discussionsEl.dataset, diffsEl.dataset); // prevent loading MR state on commits and pipelines pages // this is due to them having a shared controller with the Overview page diff --git a/app/assets/javascripts/mr_notes/init_mr_notes.js b/app/assets/javascripts/mr_notes/init_mr_notes.js index e0a8d1f7e7d..3fcf0958868 100644 --- a/app/assets/javascripts/mr_notes/init_mr_notes.js +++ b/app/assets/javascripts/mr_notes/init_mr_notes.js @@ -13,7 +13,7 @@ export default function initMrNotes(lazyLoadParams) { action: mrShowNode.dataset.mrAction, }); - initMrStateLazyLoad(lazyLoadParams); + initMrStateLazyLoad(undefined, lazyLoadParams); document.addEventListener('merged:UpdateActions', () => { initRevertCommitModal('i_code_review_post_merge_submit_revert_modal'); diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/details.js b/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/details.js index 7ac803a8ece..3a5992d182a 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/details.js +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/details.js @@ -68,7 +68,7 @@ export const MISSING_MANIFEST_WARNING_TOOLTIP = s__( export const CREATED_AT = s__('ContainerRegistry|Created %{time}'); export const NOT_AVAILABLE_TEXT = __('Not applicable.'); -export const NOT_AVAILABLE_SIZE = __('0 bytes'); +export const NOT_AVAILABLE_SIZE = __('0 B'); export const CLEANUP_UNSCHEDULED_TEXT = s__('ContainerRegistry|Cleanup will run %{time}'); export const CLEANUP_SCHEDULED_TEXT = s__('ContainerRegistry|Cleanup pending'); diff --git a/app/assets/javascripts/packages_and_registries/harbor_registry/constants/details.js b/app/assets/javascripts/packages_and_registries/harbor_registry/constants/details.js index 5b4b85ec31e..ce98be914ae 100644 --- a/app/assets/javascripts/packages_and_registries/harbor_registry/constants/details.js +++ b/app/assets/javascripts/packages_and_registries/harbor_registry/constants/details.js @@ -16,7 +16,7 @@ export const DIGEST_LABEL = s__('HarborRegistry|Digest: %{imageId}'); export const CREATED_AT_LABEL = s__('HarborRegistry|Published %{timeInfo}'); export const NOT_AVAILABLE_TEXT = __('Not applicable.'); -export const NOT_AVAILABLE_SIZE = __('0 bytes'); +export const NOT_AVAILABLE_SIZE = __('0 B'); export const TOKEN_TYPE_TAG_NAME = 'tag_name'; diff --git a/app/assets/javascripts/super_sidebar/components/help_center.vue b/app/assets/javascripts/super_sidebar/components/help_center.vue index 1a965f21ef5..6d51063dbfb 100644 --- a/app/assets/javascripts/super_sidebar/components/help_center.vue +++ b/app/assets/javascripts/super_sidebar/components/help_center.vue @@ -216,7 +216,11 @@ export default { > <template #toggle> <gl-button category="tertiary" icon="question-o" class="btn-with-notification"> - <span v-if="showWhatsNewNotification" class="notification-dot-info"></span> + <span + v-if="showWhatsNewNotification" + data-testid="notification-dot" + class="notification-dot-info" + ></span> {{ $options.i18n.help }} </gl-button> </template> diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss index 7a3db63b478..b7a674a35e7 100644 --- a/app/assets/stylesheets/framework/sidebar.scss +++ b/app/assets/stylesheets/framework/sidebar.scss @@ -489,14 +489,12 @@ padding: 0; .issuable-context-form { - $issue-sticky-header-height: 76px; - - top: calc(#{$calc-application-header-height} + #{$issue-sticky-header-height}); - height: calc(#{$calc-application-viewport-height} - #{$issue-sticky-header-height} - var(--mr-review-bar-height) - $content-wrapper-padding); + top: calc(#{$calc-application-header-height} + #{$mr-sticky-header-height}); + height: calc(#{$calc-application-viewport-height} - #{$mr-sticky-header-height} - var(--mr-review-bar-height)); position: sticky; overflow: auto; padding: 0 15px; - margin-bottom: calc((#{$header-height} + $issue-sticky-header-height) * -1); + margin-bottom: calc((#{$content-wrapper-padding} * -1) + var(--mr-review-bar-height)); } } } diff --git a/app/models/personal_access_token.rb b/app/models/personal_access_token.rb index 80825c4bf08..2749404b7b5 100644 --- a/app/models/personal_access_token.rb +++ b/app/models/personal_access_token.rb @@ -44,6 +44,7 @@ class PersonalAccessToken < ApplicationRecord validates :scopes, presence: true validate :validate_scopes + validates :expires_at, presence: true, on: :create validate :expires_at_before_instance_max_expiry_date, on: :create def revoke! @@ -54,14 +55,6 @@ class PersonalAccessToken < ApplicationRecord !revoked? && !expired? end - # fall back to default value until background migration has updated all - # existing PATs and we can add a validation - # https://gitlab.com/gitlab-org/gitlab/-/issues/369123 - def expires_at=(value) - datetime = value.presence || MAX_PERSONAL_ACCESS_TOKEN_LIFETIME_IN_DAYS.days.from_now - super(datetime) - end - override :simple_sorts def self.simple_sorts super.merge( diff --git a/app/services/personal_access_tokens/create_service.rb b/app/services/personal_access_tokens/create_service.rb index adb7924f35e..31ba88af46c 100644 --- a/app/services/personal_access_tokens/create_service.rb +++ b/app/services/personal_access_tokens/create_service.rb @@ -13,7 +13,7 @@ module PersonalAccessTokens def execute return ServiceResponse.error(message: 'Not permitted to create') unless creation_permitted? - token = target_user.personal_access_tokens.create(params.slice(*allowed_params)) + token = target_user.personal_access_tokens.create(personal_access_token_params) if token.persisted? log_event(token) @@ -31,13 +31,17 @@ module PersonalAccessTokens attr_reader :target_user, :ip_address - def allowed_params - [ - :name, - :impersonation, - :scopes, - :expires_at - ] + def personal_access_token_params + { + name: params[:name], + impersonation: params[:impersonation] || false, + scopes: params[:scopes], + expires_at: pat_expiration + } + end + + def pat_expiration + params[:expires_at].presence || PersonalAccessToken::MAX_PERSONAL_ACCESS_TOKEN_LIFETIME_IN_DAYS.days.from_now end def creation_permitted? diff --git a/app/services/resource_access_tokens/create_service.rb b/app/services/resource_access_tokens/create_service.rb index b184c2f8f58..1fea894a599 100644 --- a/app/services/resource_access_tokens/create_service.rb +++ b/app/services/resource_access_tokens/create_service.rb @@ -97,7 +97,7 @@ module ResourceAccessTokens name: params[:name] || "#{resource_type}_bot", impersonation: false, scopes: params[:scopes] || default_scopes, - expires_at: params[:expires_at] || nil + expires_at: pat_expiration } end @@ -106,10 +106,10 @@ module ResourceAccessTokens end def create_membership(resource, user, access_level) - resource.add_member(user, access_level, expires_at: default_pat_expiration) + resource.add_member(user, access_level, expires_at: pat_expiration) end - def default_pat_expiration + def pat_expiration params[:expires_at].presence || PersonalAccessToken::MAX_PERSONAL_ACCESS_TOKEN_LIFETIME_IN_DAYS.days.from_now end diff --git a/config/feature_flags/development/adherence_report_ui.yml b/config/feature_flags/development/adherence_report_ui.yml new file mode 100644 index 00000000000..5648299c689 --- /dev/null +++ b/config/feature_flags/development/adherence_report_ui.yml @@ -0,0 +1,8 @@ +--- +name: adherence_report_ui +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/122374 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/414495 +milestone: '16.1' +type: development +group: group::compliance +default_enabled: false diff --git a/config/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml b/config/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml index 9358d756644..bfef9b0ed10 100755 --- a/config/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml +++ b/config/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml @@ -179,6 +179,7 @@ options: - p_ci_templates_katalon - p_ci_templates_terraform_module_base - p_ci_templates_terraform_module + - p_ci_templates_pages_zola distribution: - ce - ee diff --git a/config/metrics/counts_28d/20230527152402_p_ci_templates_pages_zola_monthly.yml b/config/metrics/counts_28d/20230527152402_p_ci_templates_pages_zola_monthly.yml new file mode 100644 index 00000000000..778b70d699d --- /dev/null +++ b/config/metrics/counts_28d/20230527152402_p_ci_templates_pages_zola_monthly.yml @@ -0,0 +1,24 @@ +--- +key_path: redis_hll_counters.ci_templates.p_ci_templates_pages_zola_monthly +description: Count of pipelines using the Zola Pages template +product_section: '' +product_stage: '' +product_group: '' +value_type: number +status: active +milestone: "16.1" +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121946 +time_frame: 28d +data_source: redis_hll +data_category: optional +instrumentation_class: RedisHLLMetric +distribution: +- ce +- ee +tier: +- free +- premium +- ultimate +options: + events: + - p_ci_templates_pages_zola diff --git a/config/metrics/counts_7d/20210216184557_ci_templates_total_unique_counts_weekly.yml b/config/metrics/counts_7d/20210216184557_ci_templates_total_unique_counts_weekly.yml index 64ef9858a64..3e1becde7d7 100755 --- a/config/metrics/counts_7d/20210216184557_ci_templates_total_unique_counts_weekly.yml +++ b/config/metrics/counts_7d/20210216184557_ci_templates_total_unique_counts_weekly.yml @@ -180,6 +180,7 @@ options: - p_ci_templates_katalon - p_ci_templates_terraform_module_base - p_ci_templates_terraform_module + - p_ci_templates_pages_zola distribution: - ce - ee diff --git a/config/metrics/counts_7d/20230527152358_p_ci_templates_pages_zola_weekly.yml b/config/metrics/counts_7d/20230527152358_p_ci_templates_pages_zola_weekly.yml new file mode 100644 index 00000000000..d2cde6a4510 --- /dev/null +++ b/config/metrics/counts_7d/20230527152358_p_ci_templates_pages_zola_weekly.yml @@ -0,0 +1,24 @@ +--- +key_path: redis_hll_counters.ci_templates.p_ci_templates_pages_zola_weekly +description: Count of pipelines using the Zola Pages template +product_section: '' +product_stage: '' +product_group: '' +value_type: number +status: active +milestone: "16.1" +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121946 +time_frame: 7d +data_source: redis_hll +data_category: optional +instrumentation_class: RedisHLLMetric +distribution: +- ce +- ee +tier: +- free +- premium +- ultimate +options: + events: + - p_ci_templates_pages_zola diff --git a/db/fixtures/development/25_api_personal_access_token.rb b/db/fixtures/development/25_api_personal_access_token.rb index 1413f468be1..10f7d311419 100644 --- a/db/fixtures/development/25_api_personal_access_token.rb +++ b/db/fixtures/development/25_api_personal_access_token.rb @@ -12,6 +12,7 @@ Gitlab::Seeder.quiet do } user.personal_access_tokens.build(params).tap do |pat| + pat.expires_at = 365.days.from_now pat.set_token(token) pat.save! end diff --git a/db/post_migrate/20230522073230_add_not_null_constraint_to_personal_access_tokens_expires_at.rb b/db/post_migrate/20230522073230_add_not_null_constraint_to_personal_access_tokens_expires_at.rb new file mode 100644 index 00000000000..74dddb68d3b --- /dev/null +++ b/db/post_migrate/20230522073230_add_not_null_constraint_to_personal_access_tokens_expires_at.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class AddNotNullConstraintToPersonalAccessTokensExpiresAt < Gitlab::Database::Migration[2.1] + disable_ddl_transaction! + + def up + add_not_null_constraint :personal_access_tokens, :expires_at, validate: false + end + + def down + remove_not_null_constraint :personal_access_tokens, :expires_at + end +end diff --git a/db/schema_migrations/20230522073230 b/db/schema_migrations/20230522073230 new file mode 100644 index 00000000000..dee1babf25b --- /dev/null +++ b/db/schema_migrations/20230522073230 @@ -0,0 +1 @@ +d630b2bbfbb4ac030da8020745005bf7326b337ea9dbf4a57130e95d1824b780
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index d510a6ab9fb..d454f9d06cd 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -26899,6 +26899,9 @@ ALTER TABLE users ALTER TABLE vulnerability_scanners ADD CONSTRAINT check_37608c9db5 CHECK ((char_length(vendor) <= 255)) NOT VALID; +ALTER TABLE personal_access_tokens + ADD CONSTRAINT check_b8d60815eb CHECK ((expires_at IS NOT NULL)) NOT VALID; + ALTER TABLE sprints ADD CONSTRAINT check_ccd8a1eae0 CHECK ((start_date IS NOT NULL)) NOT VALID; diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 2547851dbb3..7661f2ec9a6 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -23733,7 +23733,7 @@ Represents a state transition of a vulnerability. | Name | Type | Description | | ---- | ---- | ----------- | -| <a id="vulnerabilitystatetransitiontypeauthor"></a>`author` | [`UserCore!`](#usercore) | User who changed the state of the vulnerability. | +| <a id="vulnerabilitystatetransitiontypeauthor"></a>`author` | [`UserCore`](#usercore) | User who changed the state of the vulnerability. | | <a id="vulnerabilitystatetransitiontypecomment"></a>`comment` | [`String`](#string) | Comment for the state change. | | <a id="vulnerabilitystatetransitiontypecreatedat"></a>`createdAt` | [`Time!`](#time) | Time of the state change of the vulnerability. | | <a id="vulnerabilitystatetransitiontypedismissalreason"></a>`dismissalReason` | [`VulnerabilityDismissalReason`](#vulnerabilitydismissalreason) | Reason for the dismissal. | diff --git a/doc/ci/jobs/index.md b/doc/ci/jobs/index.md index b9c2ee409b8..c446d89da41 100644 --- a/doc/ci/jobs/index.md +++ b/doc/ci/jobs/index.md @@ -342,7 +342,7 @@ In the example above: job log, but they are displayed in the raw job log. To see them, in the upper-right corner of the job log, select **Show complete raw** (**{doc-text}**). - `\r`: carriage return. - - `\e[0K`: clear line ANSI escape code. + - `\e[0K`: clear line ANSI escape sequence (`\e[K` does not work, the `0` must be included). Sample raw job log: diff --git a/doc/development/cicd/cicd_tables.md b/doc/development/cicd/cicd_tables.md index b246328a817..8cfb0faca00 100644 --- a/doc/development/cicd/cicd_tables.md +++ b/doc/development/cicd/cicd_tables.md @@ -29,7 +29,7 @@ Here is an example on how to use database helpers to create a new table and fore end add_concurrent_partitioned_foreign_key( - :p_ci_examples, :ci_builds, + :p_ci_examples, :p_ci_builds, column: [:partition_id, :build_id], target_column: [:partition_id, :id], on_update: :cascade, @@ -51,7 +51,7 @@ When creating the routing table: - The table name must start with the `p_` prefix. There are analyzers in place to ensure that all queries go through the routing tables and do not access the partitions directly. - Each new table needs a `partition_id` column and its value must equal - the value from the related association. In this example, that is `ci_builds`. All resources + the value from the related association. In this example, that is `p_ci_builds`. All resources belonging to a pipeline share the same `partition_id` value. - The primary key must have the columns ordered this way to allow efficient search only by `id`. @@ -74,7 +74,7 @@ the application runs: def up with_lock_retries do connection.execute(<<~SQL) - LOCK TABLE ci_builds IN SHARE UPDATE EXCLUSIVE MODE; + LOCK TABLE p_ci_builds IN SHARE ROW EXCLUSIVE MODE; LOCK TABLE ONLY p_ci_examples IN ACCESS EXCLUSIVE MODE; SQL @@ -92,7 +92,7 @@ Partitions are created in `gitlab_partitions_dynamic` schema. When creating a partition, remember: - Partition names do not use the `p_` prefix. -- The default value for `partition_id` is `100`. +- The starting value for `partition_id` is `100`. ## Cascade the partition value diff --git a/doc/development/documentation/styleguide/index.md b/doc/development/documentation/styleguide/index.md index ca6475566b3..e0fce2db84d 100644 --- a/doc/development/documentation/styleguide/index.md +++ b/doc/development/documentation/styleguide/index.md @@ -856,7 +856,7 @@ Sometimes they are more precise and will be maintained more actively. For each external link you add, weigh the customer benefit with the maintenance difficulties. -### Links requiring permissions +### Links that require permissions Don't link directly to: @@ -864,23 +864,26 @@ Don't link directly to: - Project features that require [special permissions](../../../user/permissions.md) to view. -These fail for: +These links fail for: - Those without sufficient permissions. - Automated link checkers. -Instead: +If you must use one of these links: -- To reduce confusion, mention in the text that the information is either: - - Contained in a confidential issue. - - Requires special permission to a project to view. -- Provide a link in back ticks (`` ` ``) so that those with access to the issue - can navigate to it. +- Mention that the information is confidential or requires specific permissions. +- Put the link in backticks, so that it does not cause link checkers to fail. -Example: +Examples: ```markdown -For more information, see the [confidential issue](../../../user/project/issues/confidential_issues.md) `https://gitlab.com/gitlab-org/gitlab-foss/-/issues/<issue_number>`. +GitLab team members can view more information in this confidential issue: +`https://gitlab.com/gitlab-org/gitlab/-/issues/<issue_number>` +``` + +```markdown +Users with the Maintainer role for the project can use the pipeline editor: +`https://gitlab.com/gitlab-org/gitlab/-/ci/editor` ``` ### Link to specific lines of code diff --git a/doc/user/project/repository/reducing_the_repo_size_using_git.md b/doc/user/project/repository/reducing_the_repo_size_using_git.md index d519fda764f..ce3a5ee9916 100644 --- a/doc/user/project/repository/reducing_the_repo_size_using_git.md +++ b/doc/user/project/repository/reducing_the_repo_size_using_git.md @@ -74,7 +74,7 @@ To purge files from a GitLab repository: 1. Clone a fresh copy of the repository from the bundle using `--bare` and `--mirror` options: ```shell - git clone --bare /path/to/project.bundle + git clone --bare --mirror /path/to/project.bundle ``` 1. Go to the `project.git` directory: @@ -134,6 +134,12 @@ To purge files from a GitLab repository: Repeat this step and all following steps (including the [repository cleanup](#repository-cleanup) step) every time you run any `git filter-repo` command. +1. To allow you to force push the changes you need to unset the mirror flag: + + ```shell + git config --unset remote.origin.mirror + ``` + 1. Force push your changes to overwrite all branches on GitLab: ```shell @@ -167,8 +173,6 @@ To purge files from a GitLab repository: ## Repository cleanup -> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/19376) in GitLab 11.6. - Repository cleanup allows you to upload a text file of objects and GitLab removes internal Git references to these objects. You can use [`git filter-repo`](https://github.com/newren/git-filter-repo) to produce a list of objects (in a @@ -180,6 +184,10 @@ of the operation. This happens automatically, but submitting the cleanup request fails if any writes are ongoing, so cancel any outstanding `git push` operations before continuing. +WARNING: +Removing internal Git references results in associated merge request commits, pipelines, and changes details +no longer being available. + To clean up a repository: 1. Go to the project for the repository. diff --git a/lib/api/resource_access_tokens.rb b/lib/api/resource_access_tokens.rb index b98ed5ec9ff..1ad5bc8d421 100644 --- a/lib/api/resource_access_tokens.rb +++ b/lib/api/resource_access_tokens.rb @@ -92,17 +92,30 @@ module API success Entities::ResourceAccessTokenWithToken end params do - requires :id, type: String, desc: "The #{source_type} ID", documentation: { example: 2 } - requires :name, type: String, desc: "Resource access token name", documentation: { example: 'test' } - requires :scopes, type: Array[String], values: ::Gitlab::Auth.resource_bot_scopes.map(&:to_s), - desc: "The permissions of the token", - documentation: { example: %w[api read_repository] } - optional :access_level, type: Integer, - values: ALLOWED_RESOURCE_ACCESS_LEVELS.values, - default: Gitlab::Access::MAINTAINER, - desc: "The access level of the token in the #{source_type}", - documentation: { example: 40 } - optional :expires_at, type: Date, desc: "The expiration date of the token", documentation: { example: '"2021-01-31' } + requires :id, + type: String, + desc: "The #{source_type} ID", + documentation: { example: 2 } + requires :name, + type: String, + desc: "Resource access token name", + documentation: { example: 'test' } + requires :scopes, + type: Array[String], + values: ::Gitlab::Auth.resource_bot_scopes.map(&:to_s), + desc: "The permissions of the token", + documentation: { example: %w[api read_repository] } + requires :expires_at, + type: Date, + desc: "The expiration date of the token", + default: PersonalAccessToken::MAX_PERSONAL_ACCESS_TOKEN_LIFETIME_IN_DAYS.days.from_now, + documentation: { example: '"2021-01-31' } + optional :access_level, + type: Integer, + values: ALLOWED_RESOURCE_ACCESS_LEVELS.values, + default: Gitlab::Access::MAINTAINER, + desc: "The access level of the token in the #{source_type}", + documentation: { example: 40 } end post ':id/access_tokens' do resource = find_source(source_type, params[:id]) diff --git a/lib/gitlab/ci/templates/Flutter.gitlab-ci.yml b/lib/gitlab/ci/templates/Flutter.gitlab-ci.yml index 7f81755348c..3d053d4d78c 100644 --- a/lib/gitlab/ci/templates/Flutter.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Flutter.gitlab-ci.yml @@ -8,9 +8,9 @@ code_quality: stage: test - image: "cirrusci/flutter:1.22.5" + image: "ghcr.io/cirruslabs/flutter:3.10.3" before_script: - - pub global activate dart_code_metrics + - flutter pub global activate dart_code_metrics - export PATH="$PATH:$HOME/.pub-cache/bin" script: - metrics lib -r codeclimate > gl-code-quality-report.json @@ -20,9 +20,9 @@ code_quality: test: stage: test - image: "cirrusci/flutter:1.22.5" + image: "ghcr.io/cirruslabs/flutter:3.10.3" before_script: - - pub global activate junitreport + - flutter pub global activate junitreport - export PATH="$PATH:$HOME/.pub-cache/bin" script: - flutter test --machine --coverage | tojunit -o report.xml diff --git a/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml index eebc1926432..f4a13d61ba2 100644 --- a/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml @@ -1,5 +1,5 @@ variables: - DAST_AUTO_DEPLOY_IMAGE_VERSION: 'v2.49.0' + DAST_AUTO_DEPLOY_IMAGE_VERSION: 'v2.50.0' .dast-auto-deploy: image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${DAST_AUTO_DEPLOY_IMAGE_VERSION}" diff --git a/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml index cd1e3a25b94..c1a3daa7f5b 100644 --- a/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml @@ -1,5 +1,5 @@ variables: - AUTO_DEPLOY_IMAGE_VERSION: 'v2.49.0' + AUTO_DEPLOY_IMAGE_VERSION: 'v2.50.0' .auto-deploy: image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${AUTO_DEPLOY_IMAGE_VERSION}" diff --git a/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml index 489a7aab22f..a3c7c6baf02 100644 --- a/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml @@ -1,5 +1,5 @@ variables: - AUTO_DEPLOY_IMAGE_VERSION: 'v2.49.0' + AUTO_DEPLOY_IMAGE_VERSION: 'v2.50.0' .auto-deploy: image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${AUTO_DEPLOY_IMAGE_VERSION}" diff --git a/lib/gitlab/ci/templates/Pages/Zola.gitlab-ci.yml b/lib/gitlab/ci/templates/Pages/Zola.gitlab-ci.yml new file mode 100644 index 00000000000..c2c890846b9 --- /dev/null +++ b/lib/gitlab/ci/templates/Pages/Zola.gitlab-ci.yml @@ -0,0 +1,30 @@ +# To contribute improvements to CI/CD templates, please follow the Development guide at: +# https://docs.gitlab.com/ee/development/cicd/templates.html +# This specific template is located at: +# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Pages/Zola.gitlab-ci.yml + +# Prefer to copy-paste this template instead of include it to ensure forward compatibility + +--- +# From: https://www.getzola.org/documentation/deployment/gitlab-pages/ +# Source template is slightly modified to be self-contained + +pages: + image: alpine:latest + variables: + # This variable will ensure that the CI runner pulls in your theme from the submodule + GIT_SUBMODULE_STRATEGY: recursive + before_script: + # Install the zola package from the alpine community repositories + - apk add --update-cache --repository http://dl-cdn.alpinelinux.org/alpine/edge/community/ zola + script: + # Execute zola build + - zola build --base-url "$CI_PAGES_URL" + artifacts: + paths: + # Path of our artifacts + - public + # This config will only publish changes that are pushed on the default branch + rules: + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + environment: production diff --git a/lib/gitlab/gitaly_client/commit_service.rb b/lib/gitlab/gitaly_client/commit_service.rb index 0c67b9fa078..9b2256a4a6e 100644 --- a/lib/gitlab/gitaly_client/commit_service.rb +++ b/lib/gitlab/gitaly_client/commit_service.rb @@ -123,8 +123,10 @@ module Gitlab end def tree_entries(repository, revision, path, recursive, skip_flat_paths, pagination_params) - pagination_params ||= {} - pagination_params[:limit] ||= TREE_ENTRIES_DEFAULT_LIMIT + unless pagination_params.nil? && recursive + pagination_params ||= {} + pagination_params[:limit] ||= TREE_ENTRIES_DEFAULT_LIMIT + end request = Gitaly::GetTreeEntriesRequest.new( repository: @gitaly_repo, diff --git a/lib/gitlab/usage_data_counters/known_events/ci_templates.yml b/lib/gitlab/usage_data_counters/known_events/ci_templates.yml index f685f0d65d9..c3e1c34151b 100644 --- a/lib/gitlab/usage_data_counters/known_events/ci_templates.yml +++ b/lib/gitlab/usage_data_counters/known_events/ci_templates.yml @@ -307,3 +307,5 @@ aggregation: weekly - name: p_ci_templates_terraform_module aggregation: weekly +- name: p_ci_templates_pages_zola + aggregation: weekly diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 9dd5593e9bb..9a6218e486a 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -1084,6 +1084,9 @@ msgid_plural "%{selectedProjectsCount} projects" msgstr[0] "" msgstr[1] "" +msgid "%{size} B" +msgstr "" + msgid "%{size} GiB" msgstr "" @@ -1093,9 +1096,6 @@ msgstr "" msgid "%{size} MiB" msgstr "" -msgid "%{size} bytes" -msgstr "" - msgid "%{sourceBranch} into %{targetBranch}" msgstr "" @@ -1538,7 +1538,7 @@ msgstr "" msgid "/day" msgstr "" -msgid "0 bytes" +msgid "0 B" msgstr "" msgid "1 Code quality finding" @@ -11483,6 +11483,9 @@ msgstr "" msgid "Compliance Report|Frameworks" msgstr "" +msgid "Compliance Report|Standards Adherence" +msgstr "" + msgid "Compliance Report|Violations" msgstr "" diff --git a/qa/qa/fixtures/package_managers/npm/npm_install_package_group.yaml.erb b/qa/qa/fixtures/package_managers/npm/npm_install_package_group.yaml.erb new file mode 100644 index 00000000000..a5ec4f298e2 --- /dev/null +++ b/qa/qa/fixtures/package_managers/npm/npm_install_package_group.yaml.erb @@ -0,0 +1,21 @@ +image: node:latest + +stages: + - install + +install: + stage: install + script: + - "npm config set @<%= registry_scope %>:registry <%= gitlab_address_with_port %>/api/v4/groups/<%= another_project.group.id %>/-/packages/npm/" + - "npm install <%= package.name %>" + cache: + key: ${CI_COMMIT_REF_NAME} + paths: + - node_modules/ + artifacts: + paths: + - node_modules/ + only: + - "<%= another_project.default_branch %>" + tags: + - "runner-for-<%= another_project.group.name %>"
\ No newline at end of file diff --git a/qa/qa/fixtures/package_managers/npm/npm_upload_package_group.yaml.erb b/qa/qa/fixtures/package_managers/npm/npm_upload_package_group.yaml.erb new file mode 100644 index 00000000000..13c00cd17c4 --- /dev/null +++ b/qa/qa/fixtures/package_managers/npm/npm_upload_package_group.yaml.erb @@ -0,0 +1,14 @@ +image: node:latest + +stages: + - deploy + +deploy: + stage: deploy + script: + - echo "//${CI_SERVER_HOST}/api/v4/projects/${CI_PROJECT_ID}/packages/npm/:_authToken=<%= auth_token %>">.npmrc + - npm publish + only: + - "<%= project.default_branch %>" + tags: + - "runner-for-<%= project.group.name %>"
\ No newline at end of file diff --git a/qa/qa/fixtures/package_managers/npm/package_instance.json.erb b/qa/qa/fixtures/package_managers/npm/package.json.erb index 46fecf97e2c..46fecf97e2c 100644 --- a/qa/qa/fixtures/package_managers/npm/package_instance.json.erb +++ b/qa/qa/fixtures/package_managers/npm/package.json.erb diff --git a/qa/qa/fixtures/package_managers/npm/package_project.json.erb b/qa/qa/fixtures/package_managers/npm/package_project.json.erb deleted file mode 100644 index 46fecf97e2c..00000000000 --- a/qa/qa/fixtures/package_managers/npm/package_project.json.erb +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "<%= package.name %>", - "version": "1.0.0", - "description": "Example package for GitLab npm registry", - "publishConfig": { - "@<%= registry_scope %>:registry": "<%= gitlab_address_with_port %>/api/v4/projects/<%= project.id %>/packages/npm/" - } -}
\ No newline at end of file diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_group_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_group_level_spec.rb new file mode 100644 index 00000000000..3f0696fd00c --- /dev/null +++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_group_level_spec.rb @@ -0,0 +1,175 @@ +# frozen_string_literal: true + +module QA + RSpec.describe 'Package' do + describe 'Package Registry', :skip_live_env, :orchestrated, :packages, :object_storage, + product_group: :package_registry do + describe 'npm group level endpoint' do + using RSpec::Parameterized::TableSyntax + include Runtime::Fixtures + include Support::Helpers::MaskToken + + let!(:registry_scope) { Runtime::Namespace.sandbox_name } + let!(:personal_access_token) do + Flow::Login.sign_in unless Page::Main::Menu.perform(&:signed_in?) + + Resource::PersonalAccessToken.fabricate!.token + end + + let(:project_deploy_token) do + Resource::ProjectDeployToken.fabricate_via_api! do |deploy_token| + deploy_token.name = 'npm-deploy-token' + deploy_token.project = project + deploy_token.scopes = %w[ + read_repository + read_package_registry + write_package_registry + ] + end + end + + let(:uri) { URI.parse(Runtime::Scenario.gitlab_address) } + let(:gitlab_address_with_port) { "#{uri.scheme}://#{uri.host}:#{uri.port}" } + let(:gitlab_host_with_port) { "#{uri.host}:#{uri.port}" } + + let!(:project) do + Resource::Project.fabricate_via_api! do |project| + project.name = 'npm-group-level-publish' + end + end + + let!(:another_project) do + Resource::Project.fabricate_via_api! do |another_project| + another_project.name = 'npm-group-level-install' + another_project.group = project.group + end + end + + let!(:runner) do + Resource::GroupRunner.fabricate! do |runner| + runner.name = "qa-runner-#{Time.now.to_i}" + runner.tags = ["runner-for-#{project.group.name}"] + runner.executor = :docker + runner.group = project.group + end + end + + let(:package) do + Resource::Package.init do |package| + package.name = "@#{registry_scope}/#{project.name}-#{SecureRandom.hex(8)}" + package.project = project + end + end + + after do + package.remove_via_api! + runner.remove_via_api! + project.remove_via_api! + another_project.remove_via_api! + end + + where(:case_name, :authentication_token_type, :token_name, :testcase) do + 'using personal access token' | :personal_access_token | 'Personal Access Token' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/413760' + 'using ci job token' | :ci_job_token | 'CI Job Token' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/413761' + 'using project deploy token' | :project_deploy_token | 'Deploy Token' | 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/413762' + end + + with_them do + let(:auth_token) do + case authentication_token_type + when :personal_access_token + use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token, project: project) + use_ci_variable(name: 'PERSONAL_ACCESS_TOKEN', value: personal_access_token, project: another_project) + when :ci_job_token + '${CI_JOB_TOKEN}' + when :project_deploy_token + use_ci_variable(name: 'PROJECT_DEPLOY_TOKEN', value: project_deploy_token.token, project: project) + use_ci_variable(name: 'PROJECT_DEPLOY_TOKEN', value: project_deploy_token.token, project: another_project) + end + end + + it 'push and pull a npm package via CI', testcase: params[:testcase] do + Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do + npm_upload_yaml = ERB.new(read_fixture('package_managers/npm', + 'npm_upload_package_group.yaml.erb')).result(binding) + package_json = ERB.new(read_fixture('package_managers/npm', 'package.json.erb')).result(binding) + + Resource::Repository::Commit.fabricate_via_api! do |commit| + commit.project = project + commit.commit_message = 'Add files' + commit.add_files([ + { + file_path: '.gitlab-ci.yml', + content: npm_upload_yaml + }, + { + file_path: 'package.json', + content: package_json + } + ]) + end + end + + project.visit! + Flow::Pipeline.visit_latest_pipeline + + Page::Project::Pipeline::Show.perform do |pipeline| + pipeline.click_job('deploy') + end + + Page::Project::Job::Show.perform do |job| + expect(job).to be_successful(timeout: 800) + end + + Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do + Resource::Repository::Commit.fabricate_via_api! do |commit| + npm_install_yaml = ERB.new(read_fixture('package_managers/npm', + 'npm_install_package_group.yaml.erb')).result(binding) + + commit.project = another_project + commit.commit_message = 'Add .gitlab-ci.yml' + commit.add_files([ + { + file_path: '.gitlab-ci.yml', + content: npm_install_yaml + } + ]) + end + end + + another_project.visit! + Flow::Pipeline.visit_latest_pipeline + + Page::Project::Pipeline::Show.perform do |pipeline| + pipeline.click_job('install') + end + + Page::Project::Job::Show.perform do |job| + expect(job).to be_successful(timeout: 800) + job.click_browse_button + end + + Page::Project::Artifact::Show.perform do |artifacts| + artifacts.go_to_directory('node_modules') + artifacts.go_to_directory("@#{registry_scope}") + expect(artifacts).to have_content(project.name.to_s) + end + + project.visit! + Page::Project::Menu.perform(&:go_to_package_registry) + + Page::Project::Packages::Index.perform do |index| + expect(index).to have_package(package.name) + + index.click_package(package.name) + end + + Page::Project::Packages::Show.perform do |show| + expect(show).to have_package_info(package.name, "1.0.0") + end + end + end + end + end + end +end diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_instance_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_instance_level_spec.rb index 4a8b95717d0..83abc030ada 100644 --- a/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_instance_level_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_instance_level_spec.rb @@ -90,7 +90,7 @@ module QA it 'push and pull a npm package via CI', testcase: params[:testcase] do Support::Retrier.retry_on_exception(max_attempts: 3, sleep_interval: 2) do npm_upload_yaml = ERB.new(read_fixture('package_managers/npm', 'npm_upload_package_instance.yaml.erb')).result(binding) - package_json = ERB.new(read_fixture('package_managers/npm', 'package_instance.json.erb')).result(binding) + package_json = ERB.new(read_fixture('package_managers/npm', 'package.json.erb')).result(binding) Resource::Repository::Commit.fabricate_via_api! do |commit| commit.project = project diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_project_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_project_level_spec.rb index e913df0957d..db68cc9ad2d 100644 --- a/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_project_level_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_project_level_spec.rb @@ -81,7 +81,7 @@ module QA it 'push and pull a npm package via CI', testcase: params[:testcase] do Resource::Repository::Commit.fabricate_via_api! do |commit| npm_upload_install_yaml = ERB.new(read_fixture('package_managers/npm', 'npm_upload_install_package_project.yaml.erb')).result(binding) - package_json = ERB.new(read_fixture('package_managers/npm', 'package_project.json.erb')).result(binding) + package_json = ERB.new(read_fixture('package_managers/npm', 'package.json.erb')).result(binding) commit.project = project commit.commit_message = 'Add .gitlab-ci.yml' diff --git a/spec/factories/personal_access_tokens.rb b/spec/factories/personal_access_tokens.rb index a140011941f..c7361b11633 100644 --- a/spec/factories/personal_access_tokens.rb +++ b/spec/factories/personal_access_tokens.rb @@ -5,7 +5,7 @@ FactoryBot.define do user sequence(:name) { |n| "PAT #{n}" } revoked { false } - expires_at { 5.days.from_now } + expires_at { 30.days.from_now } scopes { ['api'] } impersonation { false } diff --git a/spec/frontend/diffs/components/app_spec.js b/spec/frontend/diffs/components/app_spec.js index 29ade6514be..b69452069c0 100644 --- a/spec/frontend/diffs/components/app_spec.js +++ b/spec/frontend/diffs/components/app_spec.js @@ -43,7 +43,7 @@ describe('diffs/components/app', () => { let wrapper; let mock; - function createComponent(props = {}, extendStore = () => {}, provisions = {}) { + function createComponent(props = {}, extendStore = () => {}, provisions = {}, baseConfig = {}) { const provide = { ...provisions, glFeatures: { @@ -57,20 +57,24 @@ describe('diffs/components/app', () => { extendStore(store); + store.dispatch('diffs/setBaseConfig', { + endpoint: TEST_ENDPOINT, + endpointMetadata: `${TEST_HOST}/diff/endpointMetadata`, + endpointBatch: `${TEST_HOST}/diff/endpointBatch`, + endpointDiffForPath: TEST_ENDPOINT, + projectPath: 'namespace/project', + dismissEndpoint: '', + showSuggestPopover: true, + mrReviews: {}, + ...baseConfig, + }); + wrapper = shallowMount(App, { propsData: { - endpoint: TEST_ENDPOINT, - endpointMetadata: `${TEST_HOST}/diff/endpointMetadata`, - endpointBatch: `${TEST_HOST}/diff/endpointBatch`, - endpointDiffForPath: TEST_ENDPOINT, endpointCoverage: `${TEST_HOST}/diff/endpointCoverage`, endpointCodequality: '', - projectPath: 'namespace/project', currentUser: {}, changesEmptyStateIllustration: '', - dismissEndpoint: '', - showSuggestPopover: true, - fileByFileUserPreference: false, ...props, }, provide, @@ -653,13 +657,18 @@ describe('diffs/components/app', () => { describe('file-by-file', () => { it('renders a single diff', async () => { - createComponent({ fileByFileUserPreference: true }, ({ state }) => { - state.diffs.treeEntries = { - 123: { type: 'blob', fileHash: '123' }, - 312: { type: 'blob', fileHash: '312' }, - }; - state.diffs.diffFiles.push({ file_hash: '312' }); - }); + createComponent( + undefined, + ({ state }) => { + state.diffs.treeEntries = { + 123: { type: 'blob', fileHash: '123' }, + 312: { type: 'blob', fileHash: '312' }, + }; + state.diffs.diffFiles.push({ file_hash: '312' }); + }, + undefined, + { viewDiffsFileByFile: true }, + ); await nextTick(); @@ -671,12 +680,17 @@ describe('diffs/components/app', () => { const paginator = () => fileByFileNav().findComponent(GlPagination); it('sets previous button as disabled', async () => { - createComponent({ fileByFileUserPreference: true }, ({ state }) => { - state.diffs.treeEntries = { - 123: { type: 'blob', fileHash: '123' }, - 312: { type: 'blob', fileHash: '312' }, - }; - }); + createComponent( + undefined, + ({ state }) => { + state.diffs.treeEntries = { + 123: { type: 'blob', fileHash: '123' }, + 312: { type: 'blob', fileHash: '312' }, + }; + }, + undefined, + { viewDiffsFileByFile: true }, + ); await nextTick(); @@ -685,13 +699,18 @@ describe('diffs/components/app', () => { }); it('sets next button as disabled', async () => { - createComponent({ fileByFileUserPreference: true }, ({ state }) => { - state.diffs.treeEntries = { - 123: { type: 'blob', fileHash: '123' }, - 312: { type: 'blob', fileHash: '312' }, - }; - state.diffs.currentDiffFileId = '312'; - }); + createComponent( + undefined, + ({ state }) => { + state.diffs.treeEntries = { + 123: { type: 'blob', fileHash: '123' }, + 312: { type: 'blob', fileHash: '312' }, + }; + state.diffs.currentDiffFileId = '312'; + }, + undefined, + { viewDiffsFileByFile: true }, + ); await nextTick(); @@ -700,10 +719,15 @@ describe('diffs/components/app', () => { }); it("doesn't display when there's fewer than 2 files", async () => { - createComponent({ fileByFileUserPreference: true }, ({ state }) => { - state.diffs.treeEntries = { 123: { type: 'blob', fileHash: '123' } }; - state.diffs.currentDiffFileId = '123'; - }); + createComponent( + undefined, + ({ state }) => { + state.diffs.treeEntries = { 123: { type: 'blob', fileHash: '123' } }; + state.diffs.currentDiffFileId = '123'; + }, + undefined, + { viewDiffsFileByFile: true }, + ); await nextTick(); @@ -717,13 +741,18 @@ describe('diffs/components/app', () => { `( 'calls navigateToDiffFileIndex with $index when $link is clicked', async ({ currentDiffFileId, targetFile }) => { - createComponent({ fileByFileUserPreference: true }, ({ state }) => { - state.diffs.treeEntries = { - 123: { type: 'blob', fileHash: '123', filePaths: { old: '1234', new: '123' } }, - 312: { type: 'blob', fileHash: '312', filePaths: { old: '3124', new: '312' } }, - }; - state.diffs.currentDiffFileId = currentDiffFileId; - }); + createComponent( + undefined, + ({ state }) => { + state.diffs.treeEntries = { + 123: { type: 'blob', fileHash: '123', filePaths: { old: '1234', new: '123' } }, + 312: { type: 'blob', fileHash: '312', filePaths: { old: '3124', new: '312' } }, + }; + state.diffs.currentDiffFileId = currentDiffFileId; + }, + undefined, + { viewDiffsFileByFile: true }, + ); await nextTick(); diff --git a/spec/frontend/lib/utils/number_utility_spec.js b/spec/frontend/lib/utils/number_utility_spec.js index d2591cd2328..07e3e2f0422 100644 --- a/spec/frontend/lib/utils/number_utility_spec.js +++ b/spec/frontend/lib/utils/number_utility_spec.js @@ -109,8 +109,8 @@ describe('Number Utils', () => { describe('numberToHumanSize', () => { it('should return bytes', () => { - expect(numberToHumanSize(654)).toEqual('654 bytes'); - expect(numberToHumanSize(-654)).toEqual('-654 bytes'); + expect(numberToHumanSize(654)).toEqual('654 B'); + expect(numberToHumanSize(-654)).toEqual('-654 B'); }); it('should return KiB', () => { diff --git a/spec/frontend/packages_and_registries/harbor_registry/components/details/artifacts_list_row_spec.js b/spec/frontend/packages_and_registries/harbor_registry/components/details/artifacts_list_row_spec.js index 1e9b9b1ce47..d5a87945c16 100644 --- a/spec/frontend/packages_and_registries/harbor_registry/components/details/artifacts_list_row_spec.js +++ b/spec/frontend/packages_and_registries/harbor_registry/components/details/artifacts_list_row_spec.js @@ -132,7 +132,7 @@ describe('Harbor artifact list row', () => { }, }); - expect(findByTestId('size').text()).toBe('0 bytes'); + expect(findByTestId('size').text()).toBe('0 B'); }); }); }); diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/details_title_spec.js b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/details_title_spec.js index 148e87699f1..7f56d3e216c 100644 --- a/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/details_title_spec.js +++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/details/components/details_title_spec.js @@ -51,7 +51,7 @@ describe('PackageTitle', () => { it('correctly calculates the size', async () => { await createComponent(); - expect(packageSize().props('text')).toBe('300 bytes'); + expect(packageSize().props('text')).toBe('300 B'); }); }); diff --git a/spec/frontend/super_sidebar/components/help_center_spec.js b/spec/frontend/super_sidebar/components/help_center_spec.js index 4c3e6400daa..23903627f0a 100644 --- a/spec/frontend/super_sidebar/components/help_center_spec.js +++ b/spec/frontend/super_sidebar/components/help_center_spec.js @@ -25,6 +25,7 @@ describe('HelpCenter component', () => { }; const withinComponent = () => within(wrapper.element); const findButton = (name) => withinComponent().getByRole('button', { name }); + const findNotificationDot = () => wrapper.findByTestId('notification-dot'); // eslint-disable-next-line no-shadow const createWrapper = (sidebarData) => { @@ -203,8 +204,8 @@ describe('HelpCenter component', () => { createWrapper({ ...sidebarData, display_whats_new: false }); }); - it('is false', () => { - expect(wrapper.vm.showWhatsNewNotification).toBe(false); + it('does not render notification dot', () => { + expect(findNotificationDot().exists()).toBe(false); }); }); @@ -215,8 +216,8 @@ describe('HelpCenter component', () => { createWrapper({ ...sidebarData, display_whats_new: true }); }); - it('is true', () => { - expect(wrapper.vm.showWhatsNewNotification).toBe(true); + it('renders notification dot', () => { + expect(findNotificationDot().exists()).toBe(true); }); describe('when "What\'s new" drawer got opened', () => { @@ -224,8 +225,8 @@ describe('HelpCenter component', () => { findButton("What's new 5").click(); }); - it('is false', () => { - expect(wrapper.vm.showWhatsNewNotification).toBe(false); + it('does not render notification dot', () => { + expect(findNotificationDot().exists()).toBe(false); }); }); @@ -235,8 +236,8 @@ describe('HelpCenter component', () => { createWrapper({ ...sidebarData, display_whats_new: true }); }); - it('is false', () => { - expect(wrapper.vm.showWhatsNewNotification).toBe(false); + it('does not render notification dot', () => { + expect(findNotificationDot().exists()).toBe(false); }); }); }); diff --git a/spec/frontend_integration/diffs/diffs_interopability_spec.js b/spec/frontend_integration/diffs/diffs_interopability_spec.js index 5017fb8c49d..c5bd77adf8f 100644 --- a/spec/frontend_integration/diffs/diffs_interopability_spec.js +++ b/spec/frontend_integration/diffs/diffs_interopability_spec.js @@ -3,6 +3,7 @@ import setWindowLocation from 'helpers/set_window_location_helper'; import { TEST_HOST } from 'helpers/test_constants'; import { stubPerformanceWebAPI } from 'helpers/performance'; import initDiffsApp from '~/diffs'; +import { initMrStateLazyLoad } from '~/mr_notes/init'; import { createStore } from '~/mr_notes/stores'; import { getDiffCodePart, @@ -53,23 +54,35 @@ const startDiffsApp = () => { endpointBatch: `${TEST_BASE_URL}diffs_batch.json`, projectPath: TEST_PROJECT_PATH, helpPagePath: '/help', - currentUserData: 'null', + currentUserData: '{}', changesEmptyStateIllustration: '', isFluidLayout: 'false', dismissEndpoint: '', showSuggestPopover: 'false', showWhitespaceDefault: 'true', - viewDiffsFileByFile: 'false', + fileByFileDefault: 'false', defaultSuggestionCommitMessage: 'Lorem ipsum', }); - const store = createStore(); - - const vm = initDiffsApp(store); + const notesEl = document.createElement('div'); + notesEl.id = 'js-vue-mr-discussions'; + document.body.appendChild(notesEl); + Object.assign(notesEl.dataset, { + noteableData: '{ "current_user": {} }', + notesData: '{}', + currentUserData: '{}', + }); - store.dispatch('setActiveTab', 'diffs'); + window.mrTabs = { + getCurrentAction: () => 'diffs', + eventHub: { + $on() {}, + }, + }; + const store = createStore(); + initMrStateLazyLoad(store); - return vm; + return initDiffsApp(store); }; describe('diffs third party interoperability', () => { @@ -117,7 +130,7 @@ describe('diffs third party interoperability', () => { ${'parallel view right side'} | ${'parallel'} | ${'.diff-tr.line_holder'} | ${'.diff-td.line_content.right-side'} | ${EXPECT_PARALLEL_RIGHT_SIDE} `('$desc', ({ view, rowSelector, codeSelector, expectation }) => { beforeEach(async () => { - setWindowLocation(`${TEST_HOST}/${TEST_BASE_URL}/diffs?view=${view}`); + setWindowLocation(`${TEST_HOST}${TEST_BASE_URL}diffs?view=${view}`); vm = startDiffsApp(); diff --git a/spec/lib/api/entities/personal_access_token_spec.rb b/spec/lib/api/entities/personal_access_token_spec.rb index 7f79cc80573..039b5502231 100644 --- a/spec/lib/api/entities/personal_access_token_spec.rb +++ b/spec/lib/api/entities/personal_access_token_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' RSpec.describe API::Entities::PersonalAccessToken do describe '#as_json' do let_it_be(:user) { create(:user) } - let_it_be(:token) { create(:personal_access_token, user: user, expires_at: nil) } + let_it_be(:token) { create(:personal_access_token, user: user) } let(:entity) { described_class.new(token) } diff --git a/spec/lib/gitlab/ci/templates/Pages/zola_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/Pages/zola_gitlab_ci_yaml_spec.rb new file mode 100644 index 00000000000..4f80ae0054b --- /dev/null +++ b/spec/lib/gitlab/ci/templates/Pages/zola_gitlab_ci_yaml_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Pages/Zola.gitlab-ci.yml', feature_category: :pages do + subject(:template) { Gitlab::Template::GitlabCiYmlTemplate.find('Pages/Zola') } + + describe 'the created pipeline' do + let_it_be(:project) { create(:project, :repository) } + + let(:user) { project.first_owner } + let(:service) { Ci::CreatePipelineService.new(project, user, ref: project.default_branch) } + let(:pipeline) { service.execute(:push).payload } + let(:build_names) { pipeline.builds.pluck(:name) } + + before do + stub_ci_pipeline_yaml_file(template.content) + allow(Ci::BuildScheduleWorker).to receive(:perform).and_return(true) + end + + it 'creates "pages" job' do + expect(build_names).to include('pages') + end + end +end diff --git a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb index 05205ab6d6a..52652caa7f6 100644 --- a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb +++ b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb @@ -208,6 +208,19 @@ RSpec.describe Gitlab::GitalyClient::CommitService, feature_category: :gitaly do is_expected.to eq([[], nil]) end + context 'when recursive is "true"' do + let(:recursive) { true } + + it 'sends a get_tree_entries message without the limit' do + expect_any_instance_of(Gitaly::CommitService::Stub) + .to receive(:get_tree_entries) + .with(gitaly_request_with_params({ pagination_params: nil }), kind_of(Hash)) + .and_return([]) + + is_expected.to eq([[], nil]) + end + end + context 'with UTF-8 params strings' do let(:revision) { "branch\u011F" } let(:path) { "foo/\u011F.txt" } diff --git a/spec/models/concerns/token_authenticatable_spec.rb b/spec/models/concerns/token_authenticatable_spec.rb index 7367577914c..70123eaac26 100644 --- a/spec/models/concerns/token_authenticatable_spec.rb +++ b/spec/models/concerns/token_authenticatable_spec.rb @@ -130,7 +130,7 @@ RSpec.describe PersonalAccessToken, 'TokenAuthenticatable' do let(:token_digest) { Gitlab::CryptoHelper.sha256(token_value) } let(:user) { create(:user) } let(:personal_access_token) do - described_class.new(name: 'test-pat-01', user_id: user.id, scopes: [:api], token_digest: token_digest) + described_class.new(name: 'test-pat-01', user_id: user.id, scopes: [:api], token_digest: token_digest, expires_at: 30.days.from_now) end before do diff --git a/spec/models/personal_access_token_spec.rb b/spec/models/personal_access_token_spec.rb index 5ba9597a519..8e86518912c 100644 --- a/spec/models/personal_access_token_spec.rb +++ b/spec/models/personal_access_token_spec.rb @@ -259,6 +259,13 @@ RSpec.describe PersonalAccessToken, feature_category: :system_access do context 'validates expires_at' do let(:max_expiration_date) { described_class::MAX_PERSONAL_ACCESS_TOKEN_LIFETIME_IN_DAYS.days.from_now } + it "can't be blank" do + personal_access_token.expires_at = nil + + expect(personal_access_token).not_to be_valid + expect(personal_access_token.errors[:expires_at].first).to eq("can't be blank") + end + context 'when expires_in is less than MAX_PERSONAL_ACCESS_TOKEN_LIFETIME_IN_DAYS days' do it 'is valid' do personal_access_token.expires_at = max_expiration_date - 1.day @@ -285,11 +292,10 @@ RSpec.describe PersonalAccessToken, feature_category: :system_access do let_it_be(:not_revoked_nil_token) { create(:personal_access_token, revoked: nil) } let_it_be(:expired_token) { create(:personal_access_token, :expired) } let_it_be(:not_expired_token) { create(:personal_access_token) } - let_it_be(:never_expires_token) { create(:personal_access_token, expires_at: nil) } - it 'includes non-revoked and non-expired tokens' do + it 'includes non-revoked tokens' do expect(described_class.active) - .to match_array([not_revoked_false_token, not_revoked_nil_token, not_expired_token, never_expires_token]) + .to match_array([not_revoked_false_token, not_revoked_nil_token, not_expired_token]) end end @@ -414,22 +420,4 @@ RSpec.describe PersonalAccessToken, feature_category: :system_access do end end end - - describe '#expires_at=' do - let(:personal_access_token) { described_class.new } - - context 'expires_at set to empty value' do - [nil, ""].each do |expires_in_value| - it 'defaults to PersonalAccessToken::MAX_PERSONAL_ACCESS_TOKEN_LIFETIME_IN_DAYS' do - personal_access_token.expires_at = expires_in_value - - freeze_time do - expect(personal_access_token.expires_at).to eq( - PersonalAccessToken::MAX_PERSONAL_ACCESS_TOKEN_LIFETIME_IN_DAYS.days.from_now.to_date - ) - end - end - end - end - end end diff --git a/spec/requests/api/internal/base_spec.rb b/spec/requests/api/internal/base_spec.rb index 76172cf482d..619ffd8d41a 100644 --- a/spec/requests/api/internal/base_spec.rb +++ b/spec/requests/api/internal/base_spec.rb @@ -225,7 +225,8 @@ RSpec.describe API::Internal::Base, feature_category: :system_access do params: { key_id: key.id, name: 'newtoken', - scopes: %w(read_api read_repository) + scopes: %w(read_api read_repository), + expires_at: 365.days.from_now }, headers: gitlab_shell_internal_api_request_header diff --git a/spec/serializers/access_token_entity_base_spec.rb b/spec/serializers/access_token_entity_base_spec.rb index 8a92a53d0c1..f310a3d4a99 100644 --- a/spec/serializers/access_token_entity_base_spec.rb +++ b/spec/serializers/access_token_entity_base_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' RSpec.describe AccessTokenEntityBase do let_it_be(:user) { create(:user) } - let_it_be(:token) { create(:personal_access_token, user: user, expires_at: nil) } + let_it_be(:token) { create(:personal_access_token, user: user) } subject(:json) { described_class.new(token).as_json } diff --git a/spec/services/personal_access_tokens/create_service_spec.rb b/spec/services/personal_access_tokens/create_service_spec.rb index d80be5cccce..621211bc883 100644 --- a/spec/services/personal_access_tokens/create_service_spec.rb +++ b/spec/services/personal_access_tokens/create_service_spec.rb @@ -67,6 +67,13 @@ RSpec.describe PersonalAccessTokens::CreateService, feature_category: :system_ac end end + context 'with no expires_at set', :freeze_time do + let(:params) { { name: 'Test token', impersonation: false, scopes: [:no_valid] } } + let(:service) { described_class.new(current_user: user, target_user: user, params: params) } + + it { expect(subject.payload[:personal_access_token].expires_at).to eq PersonalAccessToken::MAX_PERSONAL_ACCESS_TOKEN_LIFETIME_IN_DAYS.days.from_now.to_date } + end + context 'when invalid scope' do let(:params) { { name: 'Test token', impersonation: false, scopes: [:no_valid], expires_at: Date.today + 1.month } } |