diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-09-14 00:11:27 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-09-14 00:11:27 +0300 |
commit | 79ccfc9873583adba5ef73a36e9183176c9a0530 (patch) | |
tree | ef616803b9292d2f562f12f538eddef14348595a | |
parent | a5c9ef1929e2b7c1b1beb964d36f9e782ed01e8b (diff) |
Add latest changes from gitlab-org/gitlab@master
62 files changed, 480 insertions, 324 deletions
@@ -362,7 +362,6 @@ gem 'gitlab-labkit', '~> 0.34.0' gem 'thrift', '>= 0.16.0' # I18n -gem 'ruby_parser', '~> 3.20.3', require: false gem 'rails-i18n', '~> 7.0' gem 'gettext_i18n_rails', '~> 1.11.0' gem 'gettext_i18n_rails_js', '~> 1.3' @@ -545,7 +544,7 @@ gem 'flipper', '~> 0.26.2' gem 'flipper-active_record', '~> 0.26.2' gem 'flipper-active_support_cache_store', '~> 0.26.2' gem 'unleash', '~> 3.2.2' -gem 'gitlab-experiment', '~> 0.7.1' +gem 'gitlab-experiment', '~> 0.8.0' # Structured logging gem 'lograge', '~> 0.5' diff --git a/Gemfile.checksum b/Gemfile.checksum index 99e2820cadd..8b2406b8cb3 100644 --- a/Gemfile.checksum +++ b/Gemfile.checksum @@ -209,7 +209,7 @@ {"name":"gitlab","version":"4.19.0","platform":"ruby","checksum":"3f645e3e195dbc24f0834fbf83e8ccfb2056d8e9712b01a640aad418a6949679"}, {"name":"gitlab-chronic","version":"0.10.5","platform":"ruby","checksum":"f80f18dc699b708870a80685243331290bc10cfeedb6b99c92219722f729c875"}, {"name":"gitlab-dangerfiles","version":"3.13.0","platform":"ruby","checksum":"2081eac7fe1f538427f8ebec1e8cd7c143a30d50e1470348cdec4f2d273ea1ad"}, -{"name":"gitlab-experiment","version":"0.7.1","platform":"ruby","checksum":"166dddb3aa83428bcaa93c35684ed01dc4d61f321fd2ae40b020806dc54a7824"}, +{"name":"gitlab-experiment","version":"0.8.0","platform":"ruby","checksum":"b4e2f73e0af19cdd899a745f5a846c1318d44054e068a8f4ac887f6b1017d3f9"}, {"name":"gitlab-fog-azure-rm","version":"1.8.0","platform":"ruby","checksum":"e4f24b174b273b88849d12fbcfecb79ae1c09f56cbd614998714c7f0a81e6c28"}, {"name":"gitlab-labkit","version":"0.34.0","platform":"ruby","checksum":"ca5c504201390cd07ba1029e6ca3059f4e2e6005eb121ba8a103af1e166a3ecd"}, {"name":"gitlab-license","version":"2.3.0","platform":"ruby","checksum":"60cae3871c46607dde58994faf761c6755adc61133a92e5ab59ab26a8b9b4157"}, @@ -555,7 +555,6 @@ {"name":"ruby-saml","version":"1.15.0","platform":"ruby","checksum":"3a9dda2b448310f4f90d5cf0967d4b668530fa7994d2a4d9cbfdfa62e35f76a3"}, {"name":"ruby-statistics","version":"3.0.0","platform":"ruby","checksum":"610301370346931cb701e3a8d3d3e28eb65681162cae6066c0c11abf20efdc81"}, {"name":"ruby2_keywords","version":"0.0.5","platform":"ruby","checksum":"ffd13740c573b7301cf7a2e61fc857b2a8e3d3aff32545d6f8300d8bae10e3ef"}, -{"name":"ruby_parser","version":"3.20.3","platform":"ruby","checksum":"8d2289a695dc81ffddcdd5a56e80c9a109806bc0d0b1239a1c852b0c71251c49"}, {"name":"rubyntlm","version":"0.6.3","platform":"ruby","checksum":"5b321456dba3130351f7451f8669f1afa83a0d26fd63cdec285b7b88e667102d"}, {"name":"rubypants","version":"0.2.0","platform":"ruby","checksum":"f07e38eac793655a0323fe91946081052341b9e69807026fcf102346589eedee"}, {"name":"rubyzip","version":"2.3.2","platform":"ruby","checksum":"3f57e3935dc2255c414484fbf8d673b4909d8a6a57007ed754dde39342d2373f"}, @@ -578,7 +577,6 @@ {"name":"sentry-ruby","version":"5.8.0","platform":"ruby","checksum":"caeb121433be379fb94e991a45265a287b13a9a9083e7264f539752369d37110"}, {"name":"sentry-sidekiq","version":"5.8.0","platform":"ruby","checksum":"90d1123d16a9fc5fd99dbad190b766dd189eaf9e2baddad641f1334e1877c779"}, {"name":"set","version":"1.0.2","platform":"ruby","checksum":"02ffa4de1f2621495e05b72326040dd014d7abbcb02fea698bc600a389992c02"}, -{"name":"sexp_processor","version":"4.17.0","platform":"ruby","checksum":"4daa4874ce1838cd801c65e66ed5d4f140024404a3de7482c36d4ef2604dff6f"}, {"name":"shellany","version":"0.0.1","platform":"ruby","checksum":"0e127a9132698766d7e752e82cdac8250b6adbd09e6c0a7fbbb6f61964fedee7"}, {"name":"shoulda-matchers","version":"5.1.0","platform":"ruby","checksum":"a01d20589989e9653ab4a28c67d9db2b82bcf0a2496cf01d5e1a95a4aaaf5b07"}, {"name":"sidekiq","version":"6.5.7","platform":"ruby","checksum":"7d966fd84d42a942615d6874be31e40f8bece841fdd9b96fc53cad22a590555c"}, diff --git a/Gemfile.lock b/Gemfile.lock index 72181fed7c9..d06d2295961 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -647,7 +647,7 @@ GEM danger (>= 8.4.5) danger-gitlab (>= 8.0.0) rake - gitlab-experiment (0.7.1) + gitlab-experiment (0.8.0) activesupport (>= 3.0) request_store (>= 1.0) gitlab-fog-azure-rm (1.8.0) @@ -1428,8 +1428,6 @@ GEM rexml ruby-statistics (3.0.0) ruby2_keywords (0.0.5) - ruby_parser (3.20.3) - sexp_processor (~> 4.16) rubyntlm (0.6.3) rubypants (0.2.0) rubyzip (2.3.2) @@ -1479,7 +1477,6 @@ GEM sentry-ruby (~> 5.8.0) sidekiq (>= 3.0) set (1.0.2) - sexp_processor (4.17.0) shellany (0.0.1) shoulda-matchers (5.1.0) activesupport (>= 5.2.0) @@ -1821,7 +1818,7 @@ DEPENDENCIES gitaly (~> 16.3.0.pre.rc1) gitlab-chronic (~> 0.10.5) gitlab-dangerfiles (~> 3.13.0) - gitlab-experiment (~> 0.7.1) + gitlab-experiment (~> 0.8.0) gitlab-fog-azure-rm (~> 1.8.0) gitlab-labkit (~> 0.34.0) gitlab-license (~> 2.3) @@ -1989,7 +1986,6 @@ DEPENDENCIES ruby-openai (~> 3.7) ruby-progressbar (~> 1.10) ruby-saml (~> 1.15.0) - ruby_parser (~> 3.20.3) rubyzip (~> 2.3.2) rugged (~> 1.6) sanitize (~> 6.0.2) diff --git a/app/assets/javascripts/admin/users/components/actions/approve.vue b/app/assets/javascripts/admin/users/components/actions/approve.vue index 5b13bd177ae..bcd17570b95 100644 --- a/app/assets/javascripts/admin/users/components/actions/approve.vue +++ b/app/assets/javascripts/admin/users/components/actions/approve.vue @@ -44,7 +44,7 @@ export default { }, actionPrimary: { text: I18N_USER_ACTIONS.approve, - attributes: { variant: 'confirm', 'data-qa-selector': 'approve_user_confirm_button' }, + attributes: { variant: 'confirm', 'data-testid': 'approve-user-confirm-button' }, }, messageHtml, }, @@ -55,7 +55,7 @@ export default { </script> <template> - <gl-disclosure-dropdown-item data-qa-selector="approve_user_button" @action="onClick"> + <gl-disclosure-dropdown-item @action="onClick"> <template #list-item> <slot></slot> </template> diff --git a/app/assets/javascripts/admin/users/components/user_actions.vue b/app/assets/javascripts/admin/users/components/user_actions.vue index 38c7d3f9b90..a9482d479b6 100644 --- a/app/assets/javascripts/admin/users/components/user_actions.vue +++ b/app/assets/javascripts/admin/users/components/user_actions.vue @@ -116,8 +116,7 @@ export default { category="tertiary" :toggle-text="$options.i18n.userAdministration" text-sr-only - data-testid="dropdown-toggle" - data-qa-selector="user_actions_dropdown_toggle" + data-testid="user-actions-dropdown-toggle" :data-qa-username="user.username" no-caret > diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/commit_block.vue b/app/assets/javascripts/ci/job_details/components/sidebar/commit_block.vue index 7f25ca8a94d..95616a4c706 100644 --- a/app/assets/javascripts/ci/job_details/components/sidebar/commit_block.vue +++ b/app/assets/javascripts/ci/job_details/components/sidebar/commit_block.vue @@ -22,25 +22,32 @@ export default { </script> <template> <div> - <span class="gl-font-weight-bold">{{ __('Commit') }}</span> + <p class="gl-display-flex gl-flex-wrap gl-align-items-baseline gl-gap-2 gl-mb-0"> + <span class="gl-display-flex gl-font-weight-bold">{{ __('Commit') }}</span> - <gl-link :href="commit.commit_path" class="gl-text-blue-600!" data-testid="commit-sha"> - {{ commit.short_id }} - </gl-link> + <gl-link + :href="commit.commit_path" + class="gl-text-blue-500! gl-font-monospace" + data-testid="commit-sha" + > + {{ commit.short_id }} + </gl-link> - <clipboard-button - :text="commit.id" - :title="__('Copy commit SHA')" - category="tertiary" - size="small" - /> + <clipboard-button + :text="commit.id" + :title="__('Copy commit SHA')" + category="tertiary" + size="small" + class="gl-align-self-center" + /> - <span v-if="mergeRequest"> - {{ __('in') }} - <gl-link :href="mergeRequest.path" class="gl-text-blue-600!" data-testid="link-commit" - >!{{ mergeRequest.iid }}</gl-link - > - </span> + <span v-if="mergeRequest"> + {{ __('in') }} + <gl-link :href="mergeRequest.path" class="gl-text-blue-500!" data-testid="link-commit" + >!{{ mergeRequest.iid }}</gl-link + > + </span> + </p> <p class="gl-mb-0">{{ commit.title }}</p> </div> diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/job_container_item.vue b/app/assets/javascripts/ci/job_details/components/sidebar/job_container_item.vue index 572544db526..8e87f118fa4 100644 --- a/app/assets/javascripts/ci/job_details/components/sidebar/job_container_item.vue +++ b/app/assets/javascripts/ci/job_details/components/sidebar/job_container_item.vue @@ -40,7 +40,7 @@ export default { }, classes() { return { - retried: this.job.retried, + 'retried gl-text-secondary': this.job.retried, 'gl-font-weight-bold': this.isActive, }; }, @@ -57,7 +57,7 @@ export default { v-gl-tooltip.left.viewport :href="job.status.details_path" :title="tooltipText" - class="gl-display-flex gl-align-items-center" + class="gl-display-flex gl-align-items-center gl-py-3 gl-pl-7" :data-testid="dataTestId" > <gl-icon @@ -67,11 +67,11 @@ export default { :size="14" /> - <ci-icon :status="job.status" class="gl-mr-2" :size="14" /> + <ci-icon :status="job.status" class="gl-mr-3" :size="14" /> <span class="gl-text-truncate gl-w-full">{{ jobName }}</span> - <gl-icon v-if="job.retried" name="retry" /> + <gl-icon v-if="job.retried" name="retry" class="gl-mr-4" /> </gl-link> </div> </template> diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/jobs_container.vue b/app/assets/javascripts/ci/job_details/components/sidebar/jobs_container.vue index df64b6422c7..18bd2593c2a 100644 --- a/app/assets/javascripts/ci/job_details/components/sidebar/jobs_container.vue +++ b/app/assets/javascripts/ci/job_details/components/sidebar/jobs_container.vue @@ -24,7 +24,8 @@ export default { }; </script> <template> - <div class="builds-container"> + <div class="block builds-container"> + <b class="gl-display-flex gl-mb-2 gl-font-weight-semibold">{{ __('Related jobs') }}</b> <job-container-item v-for="job in jobs" :key="job.id" diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/sidebar.vue b/app/assets/javascripts/ci/job_details/components/sidebar/sidebar.vue index 305d7004357..7f2f4fc0331 100644 --- a/app/assets/javascripts/ci/job_details/components/sidebar/sidebar.vue +++ b/app/assets/javascripts/ci/job_details/components/sidebar/sidebar.vue @@ -16,7 +16,6 @@ import TriggerBlock from './trigger_block.vue'; export default { name: 'JobSidebar', - borderTopClass: ['gl-border-t-solid', 'gl-border-t-1', 'gl-border-t-gray-100'], forwardDeploymentFailureModalId, components: { ArtifactsBlock, @@ -80,56 +79,44 @@ export default { <template> <aside class="right-sidebar build-sidebar" data-offset-top="101" data-spy="affix"> <div class="sidebar-container"> - <div class="blocks-container"> + <div class="blocks-container gl-p-4"> <sidebar-header + class="block gl-pb-4! gl-mb-2" :rest-job="job" :job-id="job.id" @updateVariables="$emit('updateVariables')" /> - <job-sidebar-details-container class="gl-py-4" :class="$options.borderTopClass" /> + <job-sidebar-details-container class="block gl-mb-2" /> <artifacts-block v-if="hasArtifact" - class="gl-py-4" - :class="$options.borderTopClass" + class="block gl-mb-2" :artifact="job.artifact" :help-url="artifactHelpUrl" /> <external-links-block v-if="hasExternalLinks" - class="gl-py-4" - :class="$options.borderTopClass" + class="block gl-mb-2" :external-links="externalLinks" /> - <trigger-block - v-if="hasTriggers" - class="gl-py-4" - :class="$options.borderTopClass" - :trigger="job.trigger" - /> + <trigger-block v-if="hasTriggers" class="block gl-mb-2" :trigger="job.trigger" /> - <commit-block - :commit="commit" - class="gl-py-4" - :class="$options.borderTopClass" - :merge-request="job.merge_request" - /> + <commit-block class="block gl-mb-2" :commit="commit" :merge-request="job.merge_request" /> <stages-dropdown v-if="job.pipeline" - class="gl-py-4" - :class="$options.borderTopClass" + class="block gl-mb-2" :pipeline="job.pipeline" :selected-stage="selectedStage" :stages="stages" @requestSidebarStageDropdown="fetchJobsForStage" /> - </div> - <jobs-container v-if="jobs.length" :job-id="job.id" :jobs="jobs" /> + <jobs-container v-if="jobs.length" :job-id="job.id" :jobs="jobs" /> + </div> </div> <job-retry-forward-deployment-modal v-if="shouldShowJobRetryForwardDeploymentModal" diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_detail_row.vue b/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_detail_row.vue index 0ba34eafa58..5b1bf354fd4 100644 --- a/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_detail_row.vue +++ b/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_detail_row.vue @@ -39,21 +39,26 @@ export default { }; </script> <template> - <p class="gl-display-flex gl-justify-content-space-between gl-mb-2"> - <span v-if="hasTitle"> - <b>{{ title }}:</b> + <p class="build-sidebar-item gl-mb-2"> + <b v-if="hasTitle" class="gl-display-flex">{{ title }}:</b> + <gl-link + v-if="path" + :href="path" + class="gl-text-blue-600!" + data-testid="job-sidebar-value-link" + > + {{ value }} + </gl-link> + <span v-else + >{{ value }} <gl-link - v-if="path" - :href="path" - class="gl-text-blue-600!" - data-testid="job-sidebar-value-link" + v-if="hasHelpURL" + :href="helpUrl" + target="_blank" + data-testid="job-sidebar-help-link" > - {{ value }} + <gl-icon name="question-o" class="gl-ml-2 gl-text-blue-500" /> </gl-link> - <span v-else>{{ value }}</span> </span> - <gl-link v-if="hasHelpURL" :href="helpUrl" target="_blank" data-testid="job-sidebar-help-link"> - <gl-icon name="question-o" /> - </gl-link> </p> </template> diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_header.vue b/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_header.vue index d4de53f9807..77e3ecb9b3c 100644 --- a/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_header.vue +++ b/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_header.vue @@ -93,7 +93,7 @@ export default { </script> <template> - <div class="gl-py-4"> + <div> <tooltip-on-truncate :title="job.name" truncate-target="child" ><h4 class="gl-mt-0 gl-mb-3 gl-text-truncate" data-testid="job-name">{{ job.name }}</h4> </tooltip-on-truncate> @@ -158,7 +158,7 @@ export default { /> <gl-button :aria-label="$options.i18n.toggleSidebar" - category="tertiary" + category="secondary" class="gl-md-display-none gl-ml-2" icon="chevron-double-lg-right" @click="toggleSidebar" diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_job_details_container.vue b/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_job_details_container.vue index 09335476008..ebef3ecaa3f 100644 --- a/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_job_details_container.vue +++ b/app/assets/javascripts/ci/job_details/components/sidebar/sidebar_job_details_container.vue @@ -44,10 +44,14 @@ export default { this.job.finished_at || this.job.erased_at || this.job.queued_duration || + this.job.id || this.job.runner || this.job.coverage, ); }, + jobId() { + return this.job?.id ? `#${this.job.id}` : ''; + }, runnerId() { const { id, short_sha: token, description } = this.job.runner; @@ -81,8 +85,9 @@ export default { ERASED: __('Erased'), QUEUED: __('Queued'), RUNNER: __('Runner'), - TAGS: __('Tags:'), + TAGS: __('Tags'), TIMEOUT: __('Timeout'), + ID: __('Job ID'), }, TIMEOUT_HELP_URL: helpPagePath('/ci/pipelines/settings.md', { anchor: 'set-a-limit-for-how-long-jobs-can-run', @@ -108,6 +113,7 @@ export default { data-testid="job-timeout" :title="$options.i18n.TIMEOUT" /> + <detail-row v-if="job.id" :value="jobId" :title="$options.i18n.ID" /> <detail-row v-if="job.runner" :value="runnerId" @@ -117,8 +123,8 @@ export default { <detail-row v-if="job.coverage" :value="coverage" :title="$options.i18n.COVERAGE" /> <p v-if="hasTags" class="build-detail-row" data-testid="job-tags"> - <span class="font-weight-bold">{{ $options.i18n.TAGS }}</span> - <gl-badge v-for="(tag, i) in job.tags" :key="i" variant="info">{{ tag }}</gl-badge> + <span class="font-weight-bold">{{ $options.i18n.TAGS }}:</span> + <gl-badge v-for="(tag, i) in job.tags" :key="i" variant="info" size="sm">{{ tag }}</gl-badge> </p> </div> </template> diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/stages_dropdown.vue b/app/assets/javascripts/ci/job_details/components/sidebar/stages_dropdown.vue index 3fee1427256..4ccd949e754 100644 --- a/app/assets/javascripts/ci/job_details/components/sidebar/stages_dropdown.vue +++ b/app/assets/javascripts/ci/job_details/components/sidebar/stages_dropdown.vue @@ -1,20 +1,20 @@ <script> import { GlLink, GlDisclosureDropdown, GlSprintf } from '@gitlab/ui'; import { isEmpty } from 'lodash'; +import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue'; import { Mousetrap } from '~/lib/mousetrap'; import { s__ } from '~/locale'; -import CiIcon from '~/vue_shared/components/ci_icon.vue'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import { clickCopyToClipboardButton } from '~/behaviors/copy_to_clipboard'; import { keysFor, MR_COPY_SOURCE_BRANCH_NAME } from '~/behaviors/shortcuts/keybindings'; export default { components: { - CiIcon, ClipboardButton, GlDisclosureDropdown, GlLink, GlSprintf, + CiBadgeLink, }, props: { pipeline: { @@ -51,13 +51,13 @@ export default { }, pipelineInfo() { if (!this.hasRef) { - return s__('Job|%{boldStart}Pipeline%{boldEnd} %{id}'); + return s__('Job|%{boldStart}Pipeline%{boldEnd} %{id} %{status}'); } if (!this.isTriggeredByMergeRequest) { - return s__('Job|%{boldStart}Pipeline%{boldEnd} %{id} for %{ref}'); + return s__('Job|%{boldStart}Pipeline%{boldEnd} %{id} %{status} for %{ref}'); } if (!this.isMergeRequestPipeline) { - return s__('Job|%{boldStart}Pipeline%{boldEnd} %{id} for %{mrId} with %{source}'); + return s__('Job|%{boldStart}Pipeline%{boldEnd} %{id} %{status} for %{mrId} with %{source}'); } return s__( @@ -94,24 +94,30 @@ export default { </script> <template> <div class="dropdown"> - <div class="js-pipeline-info" data-testid="pipeline-info"> - <ci-icon :status="pipeline.details.status" /> + <div class="gl-display-flex gl-flex-wrap gl-gap-2 js-pipeline-info" data-testid="pipeline-info"> <gl-sprintf :message="pipelineInfo"> <template #bold="{ content }"> - <span class="font-weight-bold">{{ content }}</span> + <span class="gl-display-flex gl-font-weight-bold">{{ content }}</span> </template> <template #id> <gl-link :href="pipeline.path" - class="js-pipeline-path link-commit" + class="js-pipeline-path link-commit gl-text-blue-500!" data-testid="pipeline-path" >#{{ pipeline.id }}</gl-link > </template> + <template #status> + <ci-badge-link + :status="pipeline.details.status" + badge-size="sm" + data-testid="pipeline-status-link" + /> + </template> <template #mrId> <gl-link :href="pipeline.merge_request.path" - class="link-commit ref-name" + class="link-commit ref-name gl-text-blue-500!" data-testid="mr-link" >!{{ pipeline.merge_request.iid }}</gl-link > @@ -119,7 +125,7 @@ export default { <template #ref> <gl-link :href="pipeline.ref.path" - class="link-commit ref-name" + class="link-commit ref-name gl-mt-1" data-testid="source-ref-link" >{{ pipeline.ref.name }}</gl-link ><clipboard-button @@ -134,7 +140,7 @@ export default { <template #source> <gl-link :href="pipeline.merge_request.source_branch_path" - class="link-commit ref-name" + class="link-commit ref-name gl-mt-1" data-testid="source-branch-link" >{{ pipeline.merge_request.source_branch }}</gl-link ><clipboard-button @@ -149,7 +155,7 @@ export default { <template #target> <gl-link :href="pipeline.merge_request.target_branch_path" - class="link-commit ref-name" + class="link-commit ref-name gl-mt-1" data-testid="target-branch-link" >{{ pipeline.merge_request.target_branch }}</gl-link ><clipboard-button @@ -167,7 +173,7 @@ export default { :toggle-text="selectedStage" :items="dropdownItems" block - class="gl-mt-3" + class="gl-mt-2" /> </div> </template> diff --git a/app/assets/javascripts/ci/job_details/components/sidebar/trigger_block.vue b/app/assets/javascripts/ci/job_details/components/sidebar/trigger_block.vue index c9172fe0322..315587a3376 100644 --- a/app/assets/javascripts/ci/job_details/components/sidebar/trigger_block.vue +++ b/app/assets/javascripts/ci/job_details/components/sidebar/trigger_block.vue @@ -68,7 +68,7 @@ export default { <template v-if="hasVariables"> <p class="gl-display-flex gl-justify-content-space-between gl-align-items-center"> - <span class="gl-font-weight-bold">{{ __('Trigger variables:') }}</span> + <span class="gl-display-flex gl-font-weight-bold">{{ __('Trigger variables') }}</span> <gl-button v-if="hasValues" diff --git a/app/assets/javascripts/commit/pipelines/pipelines_table_wrapper.vue b/app/assets/javascripts/ci/merge_requests/components/pipelines_table_wrapper.vue index f9b95c233ad..ee911d716e4 100644 --- a/app/assets/javascripts/commit/pipelines/pipelines_table_wrapper.vue +++ b/app/assets/javascripts/ci/merge_requests/components/pipelines_table_wrapper.vue @@ -1,10 +1,10 @@ <script> import { GlLoadingIcon } from '@gitlab/ui'; -import getMergeRequestPipelines from '~/ci/merge_requests/graphql/queries/get_merge_request_pipelines.query.graphql'; import { createAlert } from '~/alert'; import { __ } from '~/locale'; import { getQueryHeaders } from '~/ci/pipeline_details/graph/utils'; import { graphqlEtagMergeRequestPipelines } from '~/ci/pipeline_details/utils'; +import getMergeRequestPipelines from '../graphql/queries/get_merge_request_pipelines.query.graphql'; export default { components: { diff --git a/app/assets/javascripts/commit/pipelines/pipelines_table.vue b/app/assets/javascripts/commit/pipelines/legacy_pipelines_table_wrapper.vue index 5e84dcbe48e..5e84dcbe48e 100644 --- a/app/assets/javascripts/commit/pipelines/pipelines_table.vue +++ b/app/assets/javascripts/commit/pipelines/legacy_pipelines_table_wrapper.vue diff --git a/app/assets/javascripts/commit/pipelines/pipelines_bundle.js b/app/assets/javascripts/commit/pipelines/pipelines_bundle.js index 96c274225d8..beeb9b9ada4 100644 --- a/app/assets/javascripts/commit/pipelines/pipelines_bundle.js +++ b/app/assets/javascripts/commit/pipelines/pipelines_bundle.js @@ -26,7 +26,8 @@ export default () => { if (pipelineTableViewEl.dataset.disableInitialization === undefined) { const table = new Vue({ components: { - CommitPipelinesTable: () => import('~/commit/pipelines/pipelines_table.vue'), + CommitPipelinesTable: () => + import('~/commit/pipelines/legacy_pipelines_table_wrapper.vue'), }, apolloProvider, provide: { diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js index 9279e7ca935..1bc67522e82 100644 --- a/app/assets/javascripts/merge_request_tabs.js +++ b/app/assets/javascripts/merge_request_tabs.js @@ -95,8 +95,8 @@ function mountPipelines() { components: { CommitPipelinesTable: () => { return gon.features.mrPipelinesGraphql - ? import('~/commit/pipelines/pipelines_table_wrapper.vue') - : import('~/commit/pipelines/pipelines_table.vue'); + ? import('~/ci/merge_requests/components/pipelines_table_wrapper.vue') + : import('~/commit/pipelines/legacy_pipelines_table_wrapper.vue'); }, }, apolloProvider, diff --git a/app/assets/javascripts/search/sidebar/components/archived_filter/data.js b/app/assets/javascripts/search/sidebar/components/archived_filter/data.js index d765a821116..831e253a0b6 100644 --- a/app/assets/javascripts/search/sidebar/components/archived_filter/data.js +++ b/app/assets/javascripts/search/sidebar/components/archived_filter/data.js @@ -8,6 +8,7 @@ export const TRACKING_LABEL_CHECKBOX = 'checkbox'; const scopes = { PROJECTS: 'projects', ISSUES: 'issues', + MERGE_REQUESTS: 'merge_requests', }; const filterParam = 'include_archived'; diff --git a/app/assets/javascripts/search/sidebar/components/merge_requests_filters.vue b/app/assets/javascripts/search/sidebar/components/merge_requests_filters.vue index bc5b797dd56..2845eb2049b 100644 --- a/app/assets/javascripts/search/sidebar/components/merge_requests_filters.vue +++ b/app/assets/javascripts/search/sidebar/components/merge_requests_filters.vue @@ -1,18 +1,49 @@ <script> +// eslint-disable-next-line no-restricted-imports +import { mapGetters, mapState } from 'vuex'; +import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; +import { HR_DEFAULT_CLASSES, SEARCH_TYPE_ADVANCED } from '../constants'; +import { statusFilterData } from './status_filter/data'; import StatusFilter from './status_filter/index.vue'; import FiltersTemplate from './filters_template.vue'; +import { archivedFilterData } from './archived_filter/data'; +import ArchivedFilter from './archived_filter/index.vue'; export default { name: 'MergeRequestsFilters', components: { StatusFilter, FiltersTemplate, + ArchivedFilter, + }, + mixins: [glFeatureFlagsMixin()], + computed: { + ...mapGetters(['currentScope']), + ...mapState(['useSidebarNavigation', 'searchType']), + showArchivedFilter() { + return ( + Object.values(archivedFilterData.scopes).includes(this.currentScope) && + this.glFeatures.searchMergeRequestsHideArchivedProjects && + this.searchType === SEARCH_TYPE_ADVANCED + ); + }, + showStatusFilter() { + return Object.values(statusFilterData.scopes).includes(this.currentScope); + }, + showDivider() { + return !this.useSidebarNavigation; + }, + hrClasses() { + return [...HR_DEFAULT_CLASSES, 'gl-display-none', 'gl-md-display-block']; + }, }, }; </script> <template> <filters-template> - <status-filter class="gl-mb-5" /> + <status-filter v-if="showStatusFilter" class="gl-mb-5" /> + <hr v-if="showArchivedFilter && showDivider" :class="hrClasses" /> + <archived-filter v-if="showArchivedFilter" class="gl-mb-5" /> </filters-template> </template> diff --git a/app/assets/javascripts/vue_shared/components/ci_badge_link.vue b/app/assets/javascripts/vue_shared/components/ci_badge_link.vue index 9a3f1672d01..d25f40b1af9 100644 --- a/app/assets/javascripts/vue_shared/components/ci_badge_link.vue +++ b/app/assets/javascripts/vue_shared/components/ci_badge_link.vue @@ -120,13 +120,12 @@ export default { <template> <gl-badge v-gl-tooltip - :class="{ 'gl-pl-0!': isSmallBadgeSize }" + :class="{ 'gl-pl-2': isSmallBadgeSize }" :title="title" :href="detailsPath" :size="badgeSize" :variant="badgeStyles.variant" data-testid="ci-badge-link" - data-qa-selector="status_badge_link" @click="$emit('ciStatusBadgeClick')" > <ci-icon :status="status" /> diff --git a/app/assets/stylesheets/page_bundles/build.scss b/app/assets/stylesheets/page_bundles/build.scss index 5d84b6004ee..09c4d184f3f 100644 --- a/app/assets/stylesheets/page_bundles/build.scss +++ b/app/assets/stylesheets/page_bundles/build.scss @@ -89,8 +89,6 @@ } .right-sidebar.build-sidebar { - padding: 0; - &.right-sidebar-collapsed { display: none; } @@ -103,29 +101,6 @@ -webkit-overflow-scrolling: touch; } - .blocks-container { - padding: 0 $gl-padding; - width: 289px; - } - - .trigger-variables-btn-container { - justify-content: space-between; - align-items: center; - - .trigger-variables-btn { - margin-top: -5px; - margin-bottom: -5px; - } - } - - .trigger-build-variables { - margin: 0; - overflow-x: auto; - width: 100%; - -ms-overflow-style: scrollbar; - -webkit-overflow-scrolling: touch; - } - .trigger-build-variable { font-weight: $gl-font-weight-normal; color: var(--gray-950, $gray-950); @@ -145,38 +120,20 @@ vertical-align: top; } - .badge.badge-pill { - margin-left: 2px; + .blocks-container { + width: 289px; } - .stage-item { - cursor: pointer; - - &:hover { - color: var(--gl-text-color, $gl-text-color); - } + .block { + width: 262px; } .builds-container { - background-color: var(--white, $white); - border-top: 1px solid var(--border-color, $border-color); - border-bottom: 1px solid var(--border-color, $border-color); - max-height: 300px; - width: 289px; overflow: auto; - a { - padding: $gl-padding 10px $gl-padding 40px; - width: 270px; - - &:hover { - color: var(--gl-text-color, $gl-text-color); - } - } - .icon-arrow-right { - left: 15px; - top: 20px; + left: 8px; + top: 12px; } .build-job { @@ -195,9 +152,15 @@ .container-fluid.container-limited { max-width: 100%; } +} + +.build-sidebar-item { + display: grid; + grid-template-columns: 1fr 2fr; + grid-gap: $gl-padding-8; - .content-wrapper { - padding-bottom: 6px; + &:last-of-type { + @include gl-mb-0; } } diff --git a/app/experiments/ios_specific_templates_experiment.rb b/app/experiments/ios_specific_templates_experiment.rb index 1731fa87be8..5bd4a3d0287 100644 --- a/app/experiments/ios_specific_templates_experiment.rb +++ b/app/experiments/ios_specific_templates_experiment.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class IosSpecificTemplatesExperiment < ApplicationExperiment + control + before_run(if: :skip_experiment) { throw(:abort) } # rubocop:disable Cop/BanCatchThrow private diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb index ac279904fd2..30f8f6fdfe5 100644 --- a/app/helpers/users_helper.rb +++ b/app/helpers/users_helper.rb @@ -164,7 +164,7 @@ module UsersHelper messageHtml: message, actionPrimary: { text: s_('AdminUsers|Confirm user'), - attributes: [{ variant: 'confirm', 'data-qa-selector': 'confirm_user_confirm_button' }] + attributes: [{ variant: 'confirm', 'data-testid': 'confirm-user-confirm-button' }] }, actionSecondary: { text: _('Cancel'), @@ -176,7 +176,7 @@ module UsersHelper path: confirm_admin_user_path(user), method: 'put', modal_attributes: modal_attributes, - qa_selector: 'confirm_user_button' + testid: 'confirm-user-button' } end diff --git a/app/models/hooks/web_hook_log.rb b/app/models/hooks/web_hook_log.rb index 2846c970d53..3e0c8e7c472 100644 --- a/app/models/hooks/web_hook_log.rb +++ b/app/models/hooks/web_hook_log.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true class WebHookLog < ApplicationRecord - include SafeUrl include Presentable include DeleteWithLimit include CreatedAtFilterable @@ -69,7 +68,7 @@ class WebHookLog < ApplicationRecord private def obfuscate_basic_auth - self.url = safe_url + self.url = Gitlab::UrlSanitizer.sanitize_masked_url(url) end def redact_user_emails diff --git a/app/views/admin/groups/_form.html.haml b/app/views/admin/groups/_form.html.haml index b708564e23a..2da28910af3 100644 --- a/app/views/admin/groups/_form.html.haml +++ b/app/views/admin/groups/_form.html.haml @@ -41,6 +41,6 @@ - else .gl-mt-5 - = f.submit _('Save changes'), data: { qa_selector: 'save_changes_button' }, pajamas_button: true + = f.submit _('Save changes'), data: { testid: 'save-changes-button' }, pajamas_button: true = render Pajamas::ButtonComponent.new(href: admin_group_path(@group)) do = _('Cancel') diff --git a/app/views/admin/groups/_group.html.haml b/app/views/admin/groups/_group.html.haml index 20d24161c57..0c4bf91f545 100644 --- a/app/views/admin/groups/_group.html.haml +++ b/app/views/admin/groups/_group.html.haml @@ -1,11 +1,11 @@ - group = local_assigns.fetch(:group) -%li.group-row.gl-py-3.gl-align-items-center{ class: 'gl-display-flex!', data: { qa_selector: 'group_row_content' } } +%li.group-row.gl-py-3.gl-align-items-center{ class: 'gl-display-flex!', data: { testid: 'group-row-content' } } = render Pajamas::AvatarComponent.new(group, size: 32, alt: '') .gl-min-w-0.gl-flex-grow-1.gl-ml-3 .title - = link_to [:admin, group], class: 'group-name', data: { qa_selector: 'group_name_link' } do + = link_to [:admin, group], class: 'group-name', data: { testid: 'group-name-link' } do = group.full_name - if group.description.present? diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml index 2a49b9c5ad8..9f42897d1da 100644 --- a/app/views/admin/groups/index.html.haml +++ b/app/views/admin/groups/index.html.haml @@ -7,7 +7,7 @@ = hidden_field_tag :sort, @sort .search-holder .search-field-holder - = search_field_tag :name, params[:name].presence, class: "form-control search-text-input js-search-input", autofocus: true, spellcheck: false, placeholder: 'Search by name', data: { qa_selector: 'group_search_field' } + = search_field_tag :name, params[:name].presence, class: "form-control search-text-input js-search-input", autofocus: true, spellcheck: false, placeholder: 'Search by name', data: { testid: 'group-search-field' } = sprite_icon('search', css_class: 'search-icon') = render "shared/groups/dropdown", options_hash: admin_groups_sort_options_hash = render Pajamas::ButtonComponent.new(variant: :confirm, href: new_admin_group_path) do diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml index 5f5f6c98663..f7a49c88d78 100644 --- a/app/views/admin/groups/show.html.haml +++ b/app/views/admin/groups/show.html.haml @@ -8,7 +8,7 @@ = _('Group: %{group_name}') % { group_name: @group.full_name } = render Pajamas::ButtonComponent.new(href: admin_group_edit_path(@group), - button_options: { class: 'gl-float-right', data: { qa_selector: 'edit_group_link' }}, + button_options: { class: 'gl-float-right', data: { testid: 'edit-group-link' }}, icon: 'pencil') do = _('Edit') %hr diff --git a/app/views/admin/users/_head.html.haml b/app/views/admin/users/_head.html.haml index 8f7741b8a32..f6b7db2032f 100644 --- a/app/views/admin/users/_head.html.haml +++ b/app/views/admin/users/_head.html.haml @@ -31,7 +31,7 @@ - if impersonation_enabled? .gl-p-2 %span.btn-group{ class: !@can_impersonate ? 'has-tooltip' : nil, title: @impersonation_error_text } - = render Pajamas::ButtonComponent.new(disabled: !@can_impersonate, method: :post, href: impersonate_admin_user_path(@user), button_options: { data: { qa_selector: 'impersonate_user_link', testid: 'impersonate_user_link' } }) do + = render Pajamas::ButtonComponent.new(disabled: !@can_impersonate, method: :post, href: impersonate_admin_user_path(@user), button_options: { data: { testid: 'impersonate-user-link' } }) do = _('Impersonate') - if can_force_email_confirmation?(@user) .gl-p-2 @@ -48,5 +48,5 @@ = gl_tab_link_to _("SSH keys"), keys_admin_user_path(@user) = gl_tab_link_to _("Identities"), admin_user_identities_path(@user) - if impersonation_enabled? - = gl_tab_link_to _("Impersonation Tokens"), admin_user_impersonation_tokens_path(@user), data: { qa_selector: 'impersonation_tokens_tab' } + = gl_tab_link_to _("Impersonation Tokens"), admin_user_impersonation_tokens_path(@user), data: { testid: 'impersonation-tokens-tab' } .gl-mb-3 diff --git a/app/views/admin/users/_users.html.haml b/app/views/admin/users/_users.html.haml index 213d5847986..d4a9009a0cf 100644 --- a/app/views/admin/users/_users.html.haml +++ b/app/views/admin/users/_users.html.haml @@ -35,7 +35,7 @@ = gl_tab_link_to admin_users_path(filter: "banned"), { item_active: active_when(params[:filter] == 'banned'), class: 'gl-border-0!' } do = s_('AdminUsers|Banned') = gl_tab_counter_badge(limited_counter_with_delimiter(User.banned)) - = gl_tab_link_to admin_users_path(filter: "blocked_pending_approval"), { item_active: active_when(params[:filter] == 'blocked_pending_approval'), class: 'filter-blocked-pending-approval gl-border-0!', data: { qa_selector: 'pending_approval_tab' } } do + = gl_tab_link_to admin_users_path(filter: "blocked_pending_approval"), { item_active: active_when(params[:filter] == 'blocked_pending_approval'), class: 'filter-blocked-pending-approval gl-border-0!', data: { testid: 'pending-approval-tab' } } do = s_('AdminUsers|Pending approval') = gl_tab_counter_badge(limited_counter_with_delimiter(User.blocked_pending_approval)) = gl_tab_link_to admin_users_path(filter: "deactivated"), { item_active: active_when(params[:filter] == 'deactivated'), class: 'gl-border-0!' } do @@ -56,7 +56,7 @@ = hidden_field_tag "filter", h(params[:filter]) .search-holder .search-field-holder.gl-mb-4 - = search_field_tag :search_query, params[:search_query], placeholder: s_('AdminUsers|Search by name, email, or username'), class: 'form-control search-text-input js-search-input', spellcheck: false, data: { qa_selector: 'user_search_field' } + = search_field_tag :search_query, params[:search_query], placeholder: s_('AdminUsers|Search by name, email, or username'), class: 'form-control search-text-input js-search-input', spellcheck: false, data: { testid: 'user-search-field' } - if @sort.present? = hidden_field_tag :sort, @sort = sprite_icon('search', css_class: 'search-icon') diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index 8ab81fa862c..4cc3e12a8ad 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -45,7 +45,7 @@ = link_button_to nil, remove_email_admin_user_path(@user, email), data: { confirm: _("Are you sure you want to remove %{email}?") % { email: email.email }, 'confirm-btn-variant': 'danger' }, method: :delete, class: 'float-right', title: _('Remove secondary email'), id: "remove_email_#{email.id}", variant: :danger, size: :small, icon: 'close' %li %span.light ID: - %strong{ data: { qa_selector: 'user_id_content' } } + %strong{ data: { testid: 'user-id-content' } } = @user.id %li %span.light= _('Namespace ID:') diff --git a/config/feature_flags/development/introduce_ci_max_total_yaml_size_bytes.yml b/config/feature_flags/development/introduce_ci_max_total_yaml_size_bytes.yml deleted file mode 100644 index e52eac5d748..00000000000 --- a/config/feature_flags/development/introduce_ci_max_total_yaml_size_bytes.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: introduce_ci_max_total_yaml_size_bytes -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123129 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/419561 -milestone: '16.3' -type: development -group: group::pipeline authoring -default_enabled: false diff --git a/config/locales/doorkeeper.en.yml b/config/locales/doorkeeper.en.yml index 9325316c80c..d2a93a7cf9d 100644 --- a/config/locales/doorkeeper.en.yml +++ b/config/locales/doorkeeper.en.yml @@ -77,7 +77,7 @@ en: email: Allows read-only access to the user's primary email address using OpenID Connect admin_mode: Admin Mode is a functionality designed to limit the access level of administrator's personal access tokens. create_runner: Grants create access to the runners - k8s_proxy: Grants permissions to perform Kubernetes API calls using the agent for Kubernetes. + k8s_proxy: Grants permission to perform Kubernetes API calls using the agent for Kubernetes. scope_desc: api: Grants complete read/write access to the API, including all groups and projects, the container registry, and the package registry. @@ -110,7 +110,7 @@ en: create_runner: Grants create access to the runners. k8s_proxy: - Grants access to a Kubernetes cluster. + Grants permission to perform Kubernetes API calls using the agent for Kubernetes. project_access_token_scope_desc: api: Grants complete read and write access to the scoped project API, including the Package Registry. @@ -126,6 +126,8 @@ en: Grants write access (push) to the Container Registry. create_runner: Grants create access to the runners. + k8s_proxy: + Grants permission to perform Kubernetes API calls using the agent for Kubernetes. flash: applications: create: diff --git a/doc/user/clusters/agent/user_access.md b/doc/user/clusters/agent/user_access.md index 7d6060fb44e..c0805b5e84a 100644 --- a/doc/user/clusters/agent/user_access.md +++ b/doc/user/clusters/agent/user_access.md @@ -141,6 +141,64 @@ subjects: kind: Group ``` +## Access a cluster with the Kubernetes API + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131144) in GitLab 16.4. + +You can [configure an agent](#configure-kubernetes-access) to allow GitLab users to access a cluster with the Kubernetes API. + +Use a [personal access token](../../profile/personal_access_tokens.md) +with the `k8s_proxy` scope to access the cluster via `kubectl`: + +1. Configure the agent with the [`user_access` entry](user_access.md). +1. On the left sidebar, select **Search or go to** and find your project. +1. Select **Operate > Kubernetes clusters** and retrieve the numerical ID of the agent you want to access. You need the ID to construct the full API token. +1. Create a [personal access token](../../profile/personal_access_tokens.md) with the `k8s_proxy` scope. You need the access token to construct the full API token. +1. Construct `kube config` entries to access the cluster: + 1. Make sure that the proper `kube config` is selected. + For example, you can set the `KUBECONFIG` environment variable. + 1. Add the GitLab KAS proxy cluster to the `kube config`: + + ```shell + kubectl config set-cluster gitlab --server "https://kas.gitlab.com/k8s-proxy" + ``` + + The `server` argument points to the KAS address of your GitLab instance. + On GitLab.com, this is `https://kas.gitlab.com/k8s-proxy`. + You can get the KAS address of your instance when you register an agent. + + If needed, change `gitlab` to the name of your cluster. + 1. Use your numerical agent ID and personal access token to construct an API token: + + ```shell + kubectl config set-credentials gitlab-user --token "pat:<agent-id>:<token>" + ``` + + If needed, change `gitlab-user` to your credentials name. + 1. Add the context to combine the cluster and the user: + + ```shell + kubectl config set-context gitlab-agent --cluster gitlab --user gitlab-user + ``` + + If needed, change the arguments to `cluster` and `user`. The arguments must match the cluster name and user from the previous steps. + + You can customize the context name. + 1. Activate the new context: + + ```shell + kubectl config use-context gitlab-agent + ``` + + If needed, change `gitlab-agent` to the context name you set in the last step. +1. Check that the configuration works: + + ```shell + kubectl get nodes + ``` + +The configured user can access your cluster with the Kubernetes API. + ## Related topics - [Architectural blueprint](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/blob/master/doc/kubernetes_user_access.md) diff --git a/doc/user/group/access_and_permissions.md b/doc/user/group/access_and_permissions.md index b42d36e5380..2483df148bb 100644 --- a/doc/user/group/access_and_permissions.md +++ b/doc/user/group/access_and_permissions.md @@ -102,6 +102,7 @@ Keep in mind that restricting group access by IP address has the following impli IP access restrictions applied to self-managed instances are possible with [`gitlab-sshd`](../../administration/operations/gitlab_sshd.md) with [PROXY protocol](../../administration/operations/gitlab_sshd.md#proxy-protocol-support) enabled. - IP restriction is not applicable to shared resources belonging to a group. Any shared resource is accessible to a user even if that user is not able to access the group. +- While IP restrictions apply to public projects, they aren't a complete firewall and cached files for a project may still be accessible to users not in the IP block ### GitLab.com access restrictions diff --git a/lib/gitlab/ci/config/external/mapper/verifier.rb b/lib/gitlab/ci/config/external/mapper/verifier.rb index 580cae8a207..0e296aa0b5b 100644 --- a/lib/gitlab/ci/config/external/mapper/verifier.rb +++ b/lib/gitlab/ci/config/external/mapper/verifier.rb @@ -40,7 +40,7 @@ module Gitlab file.validate_content! if file.valid? file.load_and_validate_expanded_hash! if file.valid? - next unless Feature.enabled?(:introduce_ci_max_total_yaml_size_bytes, context.project) && file.valid? + next unless file.valid? # We are checking the file.content.to_s because that is returning the actual content of the file, # whereas file.content would return the BatchLoader. diff --git a/lib/gitlab/url_sanitizer.rb b/lib/gitlab/url_sanitizer.rb index 79e124a58f5..20cbde0e700 100644 --- a/lib/gitlab/url_sanitizer.rb +++ b/lib/gitlab/url_sanitizer.rb @@ -26,6 +26,12 @@ module Gitlab #{URI::REGEXP::PATTERN::HOSTPORT} ) }x + # This expression is derived from `URI::REGEXP::PATTERN::USERINFO` but with the + # addition of `{` and `}` in the list of allowed characters to account for the + # possibility of the userinfo portion of a URL containing masked segments. + # e.g. + # http://myuser:{masked_password}@{masked_domain}.com/{masked_hook} + MASKED_USERINFO_REGEX = %r{(?:[\\-_.!~*'()a-zA-Z\d;:&=+$,{}]|%[a-fA-F\d]{2})*} def self.sanitize(content) content.gsub(URI_REGEXP) do |url| @@ -50,6 +56,14 @@ module Gitlab valid?(url, allowed_schemes: ALLOWED_WEB_SCHEMES) end + # The url associated with records like `WebHookLog` may contain masked + # portions represented by paired curly brackets in the URL. As this + # prohibits straightforward parsing of the URL, we can use a variation of + # the existing USERINFO regex for these cases. + def self.sanitize_masked_url(url) + url.gsub(%r{//#{MASKED_USERINFO_REGEX}@}o, '//*****:*****@') + end + def initialize(url, credentials: nil) %i[user password].each do |symbol| credentials[symbol] = credentials[symbol].presence if credentials&.key?(symbol) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index a4bab13d02a..0f20955e733 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -26683,6 +26683,9 @@ msgstr "" msgid "Job Failed #%{build_id}" msgstr "" +msgid "Job ID" +msgstr "" + msgid "Job artifacts" msgstr "" @@ -26878,16 +26881,16 @@ msgstr "" msgid "Jobs|You're about to retry a job that failed because it attempted to deploy code that is older than the latest deployment. Retrying this job could result in overwriting the environment with the older source code." msgstr "" -msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id}" +msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id} %{status}" msgstr "" -msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id} for %{mrId} with %{source}" +msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id} %{status} for %{mrId} with %{source}" msgstr "" -msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id} for %{mrId} with %{source} into %{target}" +msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id} %{status} for %{ref}" msgstr "" -msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id} for %{ref}" +msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id} for %{mrId} with %{source} into %{target}" msgstr "" msgid "Job|%{searchLength} results found for %{searchTerm}" @@ -38834,6 +38837,9 @@ msgstr "" msgid "Related issues" msgstr "" +msgid "Related jobs" +msgstr "" + msgid "Related merge request %{link_to_merge_request} to merge %{link_to_merge_request_source_branch}" msgstr "" @@ -46478,9 +46484,6 @@ msgstr "" msgid "Tags this commit to %{tag_name}." msgstr "" -msgid "Tags:" -msgstr "" - msgid "TagsPage|Are you sure you want to delete this tag?" msgstr "" @@ -49933,7 +49936,7 @@ msgstr "" msgid "Trigger token:" msgstr "" -msgid "Trigger variables:" +msgid "Trigger variables" msgstr "" msgid "Trigger was created successfully." diff --git a/qa/qa/page/admin/overview/groups/edit.rb b/qa/qa/page/admin/overview/groups/edit.rb index 8e4650a1232..c096f1c862e 100644 --- a/qa/qa/page/admin/overview/groups/edit.rb +++ b/qa/qa/page/admin/overview/groups/edit.rb @@ -7,11 +7,11 @@ module QA module Groups class Edit < QA::Page::Base view 'app/views/admin/groups/_form.html.haml' do - element :save_changes_button, required: true + element 'save-changes-button', required: true end def click_save_changes_button - click_element :save_changes_button, Groups::Show + click_element 'save-changes-button', Groups::Show end end end diff --git a/qa/qa/page/admin/overview/groups/index.rb b/qa/qa/page/admin/overview/groups/index.rb index c9417bd01b1..6157e7a5e4d 100644 --- a/qa/qa/page/admin/overview/groups/index.rb +++ b/qa/qa/page/admin/overview/groups/index.rb @@ -7,21 +7,21 @@ module QA module Groups class Index < QA::Page::Base view 'app/views/admin/groups/index.html.haml' do - element :group_search_field, required: true + element 'group-search-field', required: true end view 'app/views/admin/groups/_group.html.haml' do - element :group_row_content - element :group_name_link + element 'group-row-content' + element 'group-name-link' end def search_group(group_name) - find_element(:group_search_field).set(group_name).send_keys(:return) + find_element('group-search-field').set(group_name).send_keys(:return) end def click_group(group_name) - within_element(:group_row_content, text: group_name) do - click_element(:group_name_link) + within_element('group-row-content', text: group_name) do + click_element('group-name-link') end end end diff --git a/qa/qa/page/admin/overview/groups/show.rb b/qa/qa/page/admin/overview/groups/show.rb index 6744b0c1e70..c7f2760857f 100644 --- a/qa/qa/page/admin/overview/groups/show.rb +++ b/qa/qa/page/admin/overview/groups/show.rb @@ -7,11 +7,11 @@ module QA module Groups class Show < QA::Page::Base view 'app/views/admin/groups/show.html.haml' do - element :edit_group_link, required: true + element 'edit-group-link', required: true end def click_edit_group_link - click_element :edit_group_link, Groups::Edit + click_element 'edit-group-link', Groups::Edit end end end diff --git a/qa/qa/page/admin/overview/users/index.rb b/qa/qa/page/admin/overview/users/index.rb index 6f1134b751a..c444b728f5a 100644 --- a/qa/qa/page/admin/overview/users/index.rb +++ b/qa/qa/page/admin/overview/users/index.rb @@ -7,8 +7,8 @@ module QA module Users class Index < QA::Page::Base view 'app/views/admin/users/_users.html.haml' do - element :user_search_field - element :pending_approval_tab + element 'user-search-field' + element 'pending-approval-tab' end view 'app/assets/javascripts/admin/users/components/users_table.vue' do @@ -16,11 +16,11 @@ module QA end def search_user(username) - find_element(:user_search_field).set(username).send_keys(:return) + find_element('user-search-field').set(username).send_keys(:return) end def click_pending_approval_tab - click_element :pending_approval_tab + click_element 'pending-approval-tab' end def click_user(username) diff --git a/qa/qa/page/admin/overview/users/show.rb b/qa/qa/page/admin/overview/users/show.rb index 2fde3ac2c6d..1087ef723a5 100644 --- a/qa/qa/page/admin/overview/users/show.rb +++ b/qa/qa/page/admin/overview/users/show.rb @@ -7,54 +7,53 @@ module QA module Users class Show < QA::Page::Base view 'app/views/admin/users/_head.html.haml' do - element :impersonate_user_link - element :impersonation_tokens_tab + element 'impersonate-user-link' + element 'impersonation-tokens-tab' end view 'app/views/admin/users/show.html.haml' do - element :user_id_content + element 'user-id-content' end view 'app/assets/javascripts/admin/users/components/actions/approve.vue' do - element :approve_user_button - element :approve_user_confirm_button + element 'approve-user-confirm-button' end view 'app/assets/javascripts/admin/users/components/user_actions.vue' do - element :user_actions_dropdown_toggle + element 'user-actions-dropdown-toggle' end view 'app/helpers/users_helper.rb' do - element :confirm_user_button - element :confirm_user_confirm_button + element 'confirm-user-button' + element 'confirm-user-confirm-button' end def open_user_actions_dropdown(user) - click_element(:user_actions_dropdown_toggle, username: user.username) + click_element('user-actions-dropdown-toggle', username: user.username) end def go_to_impersonation_tokens(&block) - navigate_to_tab(:impersonation_tokens_tab) + navigate_to_tab('impersonation-tokens-tab') Users::Components::ImpersonationTokens.perform(&block) end def click_impersonate_user - click_element(:impersonate_user_link) + click_element('impersonate-user-link') end def user_id - find_element(:user_id_content).text + find_element('user-id-content').text end def confirm_user - click_element :confirm_user_button - click_element :confirm_user_confirm_button + click_element 'confirm-user-button' + click_element 'confirm-user-confirm-button' end def approve_user(user) open_user_actions_dropdown(user) - click_element :approve_user_button - click_element :approve_user_confirm_button + click_element 'approve' + click_element 'approve-user-confirm-button' end private diff --git a/qa/qa/page/component/ci_badge_link.rb b/qa/qa/page/component/ci_badge_link.rb index 485e363d960..0fddd1cbf12 100644 --- a/qa/qa/page/component/ci_badge_link.rb +++ b/qa/qa/page/component/ci_badge_link.rb @@ -32,12 +32,12 @@ module QA super base.view 'app/assets/javascripts/vue_shared/components/ci_badge_link.vue' do - element :status_badge_link + element 'ci-badge-link' end end def status_badge - find_element(:status_badge_link).text + find_element('ci-badge-link').text end def completed?(timeout: 60) diff --git a/spec/experiments/application_experiment_spec.rb b/spec/experiments/application_experiment_spec.rb index 461a6390a33..8a65c219f5d 100644 --- a/spec/experiments/application_experiment_spec.rb +++ b/spec/experiments/application_experiment_spec.rb @@ -211,7 +211,7 @@ RSpec.describe ApplicationExperiment, :experiment, feature_category: :experiment application_experiment.variant(:variant1) {} application_experiment.variant(:variant2) {} - expect(application_experiment.assigned.name).to eq('variant2') + expect(application_experiment.assigned.name).to eq(:variant2) end end @@ -248,7 +248,7 @@ RSpec.describe ApplicationExperiment, :experiment, feature_category: :experiment end it "caches the variant determined by the variant resolver" do - expect(application_experiment.assigned.name).to eq('candidate') # we should be in the experiment + expect(application_experiment.assigned.name).to eq(:candidate) # we should be in the experiment application_experiment.run @@ -263,7 +263,7 @@ RSpec.describe ApplicationExperiment, :experiment, feature_category: :experiment # the control. stub_feature_flags(namespaced_stub: false) # simulate being not rolled out - expect(application_experiment.assigned.name).to eq('control') # if we ask, it should be control + expect(application_experiment.assigned.name).to eq(:control) # if we ask, it should be control application_experiment.run @@ -299,29 +299,4 @@ RSpec.describe ApplicationExperiment, :experiment, feature_category: :experiment end end end - - context "with deprecation warnings" do - before do - Gitlab::Experiment::Configuration.instance_variable_set(:@__dep_versions, nil) # clear the internal memoization - - allow(ActiveSupport::Deprecation).to receive(:new).and_call_original - end - - it "doesn't warn on non dev/test environments" do - allow(Gitlab).to receive(:dev_or_test_env?).and_return(false) - - expect { experiment(:example) { |e| e.use {} } }.not_to raise_error - expect(ActiveSupport::Deprecation).not_to have_received(:new).with(anything, 'Gitlab::Experiment') - end - - it "warns on dev and test environments" do - allow(Gitlab).to receive(:dev_or_test_env?).and_return(true) - - # This will eventually raise an ActiveSupport::Deprecation exception, - # it's ok to change it when that happens. - expect { experiment(:example) { |e| e.use {} } }.not_to raise_error - - expect(ActiveSupport::Deprecation).to have_received(:new).with(anything, 'Gitlab::Experiment') - end - end end diff --git a/spec/features/admin/users/user_spec.rb b/spec/features/admin/users/user_spec.rb index ed355e4ada4..7dc329e6909 100644 --- a/spec/features/admin/users/user_spec.rb +++ b/spec/features/admin/users/user_spec.rb @@ -156,7 +156,7 @@ RSpec.describe 'Admin::Users::User', feature_category: :user_management do it 'disables impersonate button' do subject - impersonate_btn = find('[data-testid="impersonate_user_link"]') + impersonate_btn = find('[data-testid="impersonate-user-link"]') expect(impersonate_btn).not_to be_nil expect(impersonate_btn['disabled']).not_to be_nil @@ -174,7 +174,7 @@ RSpec.describe 'Admin::Users::User', feature_category: :user_management do subject expect(page).to have_content('Impersonate') - impersonate_btn = find('[data-testid="impersonate_user_link"]') + impersonate_btn = find('[data-testid="impersonate-user-link"]') expect(impersonate_btn['disabled']).to be_nil end end diff --git a/spec/features/admin/users/users_spec.rb b/spec/features/admin/users/users_spec.rb index 8e80ce5edd9..8ee30c50a7d 100644 --- a/spec/features/admin/users/users_spec.rb +++ b/spec/features/admin/users/users_spec.rb @@ -350,7 +350,8 @@ RSpec.describe 'Admin::Users', feature_category: :user_management do let_it_be(:ghost_user) { create(:user, :ghost) } it 'does not render actions dropdown' do - expect(page).not_to have_css("[data-testid='user-actions-#{ghost_user.id}'] [data-testid='dropdown-toggle']") + expect(page).not_to have_css( + "[data-testid='user-actions-#{ghost_user.id}'] [data-testid='user-actions-dropdown-toggle']") end end @@ -358,7 +359,8 @@ RSpec.describe 'Admin::Users', feature_category: :user_management do let_it_be(:bot_user) { create(:user, user_type: :alert_bot) } it 'does not render actions dropdown' do - expect(page).not_to have_css("[data-testid='user-actions-#{bot_user.id}'] [data-testid='dropdown-toggle']") + expect(page).not_to have_css( + "[data-testid='user-actions-#{bot_user.id}'] [data-testid='user-actions-dropdown-toggle']") end end end diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index ecb8a8e6f17..1bee4cc5081 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -93,7 +93,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state, feature_category: :grou visit project_job_path(project, job) within '.js-pipeline-info' do - expect(page).to have_content("Pipeline ##{pipeline.id} for #{pipeline.ref}") + expect(page).to have_content("Pipeline ##{pipeline.id} #{pipeline.status} for #{pipeline.ref}") end end @@ -239,7 +239,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state, feature_category: :grou href = new_project_issue_path(project, options) - page.within('.build-sidebar') do + page.within('aside.right-sidebar') do expect(find('[data-testid="job-new-issue"]')['href']).to include(href) end end diff --git a/spec/frontend/admin/users/components/user_actions_spec.js b/spec/frontend/admin/users/components/user_actions_spec.js index 69755c6142a..b44986ea7de 100644 --- a/spec/frontend/admin/users/components/user_actions_spec.js +++ b/spec/frontend/admin/users/components/user_actions_spec.js @@ -18,7 +18,7 @@ describe('AdminUserActions component', () => { const findUserActions = (id) => wrapper.findByTestId(`user-actions-${id}`); const findEditButton = (id = user.id) => findUserActions(id).find('[data-testid="edit"]'); const findActionsDropdown = (id = user.id) => - findUserActions(id).find('[data-testid="dropdown-toggle"]'); + findUserActions(id).find('[data-testid="user-actions-dropdown-toggle"]'); const findDisclosureGroup = () => wrapper.findComponent(GlDisclosureDropdownGroup); const initComponent = ({ actions = [], showButtonLabels } = {}) => { diff --git a/spec/frontend/ci/job_details/components/sidebar/sidebar_job_details_container_spec.js b/spec/frontend/ci/job_details/components/sidebar/sidebar_job_details_container_spec.js index 37a2ca75df0..e188d99b8b1 100644 --- a/spec/frontend/ci/job_details/components/sidebar/sidebar_job_details_container_spec.js +++ b/spec/frontend/ci/job_details/components/sidebar/sidebar_job_details_container_spec.js @@ -53,6 +53,7 @@ describe('Job Sidebar Details Container', () => { ['erased_at', 'Erased: 3 weeks ago'], ['finished_at', 'Finished: 3 weeks ago'], ['queued_duration', 'Queued: 9 seconds'], + ['id', 'Job ID: #4757'], ['runner', 'Runner: #1 (ABCDEFGH) local ci runner'], ['coverage', 'Coverage: 20%'], ])('uses %s to render job-%s', async (detail, value) => { @@ -77,7 +78,7 @@ describe('Job Sidebar Details Container', () => { createWrapper(); await store.dispatch('receiveJobSuccess', job); - expect(findAllDetailsRow()).toHaveLength(7); + expect(findAllDetailsRow()).toHaveLength(8); }); describe('duration row', () => { diff --git a/spec/frontend/ci/job_details/components/sidebar/stages_dropdown_spec.js b/spec/frontend/ci/job_details/components/sidebar/stages_dropdown_spec.js index 44a6f7db385..4d00ead31cf 100644 --- a/spec/frontend/ci/job_details/components/sidebar/stages_dropdown_spec.js +++ b/spec/frontend/ci/job_details/components/sidebar/stages_dropdown_spec.js @@ -3,7 +3,7 @@ import { shallowMount } from '@vue/test-utils'; import { Mousetrap } from '~/lib/mousetrap'; import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import StagesDropdown from '~/ci/job_details/components/sidebar/stages_dropdown.vue'; -import CiIcon from '~/vue_shared/components/ci_icon.vue'; +import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue'; import * as copyToClipboard from '~/behaviors/copy_to_clipboard'; import { mockPipelineWithoutRef, @@ -15,7 +15,7 @@ import { describe('Stages Dropdown', () => { let wrapper; - const findStatus = () => wrapper.findComponent(CiIcon); + const findStatus = () => wrapper.findComponent(CiBadgeLink); const findDropdown = () => wrapper.findComponent(GlDisclosureDropdown); const findSelectedStageText = () => findDropdown().props('toggleText'); diff --git a/spec/frontend/commit/pipelines/pipelines_table_wrapper_spec.js b/spec/frontend/ci/merge_requests/components/pipelines_table_wrapper_spec.js index 78e303bd6aa..df9bf2a4235 100644 --- a/spec/frontend/commit/pipelines/pipelines_table_wrapper_spec.js +++ b/spec/frontend/ci/merge_requests/components/pipelines_table_wrapper_spec.js @@ -7,7 +7,7 @@ import createMockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; import { createAlert } from '~/alert'; -import PipelinesTableWrapper from '~/commit/pipelines/pipelines_table_wrapper.vue'; +import PipelinesTableWrapper from '~/ci/merge_requests/components/pipelines_table_wrapper.vue'; import getMergeRequestsPipelines from '~/ci/merge_requests/graphql/queries/get_merge_request_pipelines.query.graphql'; import { mergeRequestPipelinesResponse } from '../mock_data'; diff --git a/spec/frontend/ci/merge_requests/mock_data.js b/spec/frontend/ci/merge_requests/mock_data.js new file mode 100644 index 00000000000..1d8fdb88aa3 --- /dev/null +++ b/spec/frontend/ci/merge_requests/mock_data.js @@ -0,0 +1,30 @@ +const createMergeRequestPipelines = (count = 30) => { + const pipelines = []; + + for (let i = 0; i < count; i += 1) { + pipelines.push({ + id: i, + iid: i + 10, + path: `/project/pipelines/${i}`, + }); + } + + return { + count, + nodes: pipelines, + }; +}; + +export const mergeRequestPipelinesResponse = { + data: { + project: { + __typename: 'Project', + id: 'gid://gitlab/Project/1', + mergeRequest: { + __typename: 'MergeRequest', + id: 'gid://gitlab/MergeRequest/1', + pipelines: createMergeRequestPipelines(), + }, + }, + }, +}; diff --git a/spec/frontend/commit/mock_data.js b/spec/frontend/commit/mock_data.js index eb9e2e84149..2a618e08c50 100644 --- a/spec/frontend/commit/mock_data.js +++ b/spec/frontend/commit/mock_data.js @@ -291,34 +291,3 @@ export const refsListPropsMock = { urlPart: '/some/project/-/commits/', refType: 'heads', }; - -const createMergeRequestPipelines = (count = 30) => { - const pipelines = []; - - for (let i = 0; i < count; i += 1) { - pipelines.push({ - id: i, - iid: i + 10, - path: `/project/pipelines/${i}`, - }); - } - - return { - count, - nodes: pipelines, - }; -}; - -export const mergeRequestPipelinesResponse = { - data: { - project: { - __typename: 'Project', - id: 'gid://gitlab/Project/1', - mergeRequest: { - __typename: 'MergeRequest', - id: 'gid://gitlab/MergeRequest/1', - pipelines: createMergeRequestPipelines(), - }, - }, - }, -}; diff --git a/spec/frontend/commit/pipelines/pipelines_table_spec.js b/spec/frontend/commit/pipelines/legacy_pipelines_table_wrapper_spec.js index 21677d94b20..4af292e3588 100644 --- a/spec/frontend/commit/pipelines/pipelines_table_spec.js +++ b/spec/frontend/commit/pipelines/legacy_pipelines_table_wrapper_spec.js @@ -7,7 +7,7 @@ import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import { stubComponent } from 'helpers/stub_component'; import waitForPromises from 'helpers/wait_for_promises'; import Api from '~/api'; -import PipelinesTable from '~/commit/pipelines/pipelines_table.vue'; +import LegacyPipelinesTableWraper from '~/commit/pipelines/legacy_pipelines_table_wrapper.vue'; import { HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_INTERNAL_SERVER_ERROR, @@ -42,7 +42,7 @@ describe('Pipelines table in Commits and Merge requests', () => { const createComponent = ({ props = {} } = {}) => { wrapper = extendedWrapper( - mount(PipelinesTable, { + mount(LegacyPipelinesTableWraper, { propsData: { endpoint: 'endpoint.json', emptyStateSvgPath: 'foo', diff --git a/spec/frontend/search/sidebar/components/merge_requests_filters_spec.js b/spec/frontend/search/sidebar/components/merge_requests_filters_spec.js index 0932f8e47d2..72f93680675 100644 --- a/spec/frontend/search/sidebar/components/merge_requests_filters_spec.js +++ b/spec/frontend/search/sidebar/components/merge_requests_filters_spec.js @@ -1,28 +1,131 @@ import { shallowMount } from '@vue/test-utils'; +import Vue from 'vue'; +// eslint-disable-next-line no-restricted-imports +import Vuex from 'vuex'; +import { MOCK_QUERY } from 'jest/search/mock_data'; import MergeRequestsFilters from '~/search/sidebar/components/merge_requests_filters.vue'; import StatusFilter from '~/search/sidebar/components/status_filter/index.vue'; -import FiltersTemplate from '~/search/sidebar/components/filters_template.vue'; +import ArchivedFilter from '~/search/sidebar/components/archived_filter/index.vue'; +import { SEARCH_TYPE_ADVANCED, SEARCH_TYPE_BASIC } from '~/search/sidebar/constants'; + +Vue.use(Vuex); describe('GlobalSearch MergeRequestsFilters', () => { let wrapper; - const findStatusFilter = () => wrapper.findComponent(StatusFilter); - const findFiltersTemplate = () => wrapper.findComponent(FiltersTemplate); + const defaultGetters = { + currentScope: () => 'merge_requests', + }; - const createComponent = () => { - wrapper = shallowMount(MergeRequestsFilters); + const createComponent = ({ + initialState = {}, + searchMergeRequestsHideArchivedProjects = true, + } = {}) => { + const store = new Vuex.Store({ + state: { + urlQuery: MOCK_QUERY, + useSidebarNavigation: false, + searchType: SEARCH_TYPE_ADVANCED, + ...initialState, + }, + getters: defaultGetters, + }); + + wrapper = shallowMount(MergeRequestsFilters, { + store, + provide: { + glFeatures: { + searchMergeRequestsHideArchivedProjects, + }, + }, + }); }; - describe('Renders correctly', () => { + const findStatusFilter = () => wrapper.findComponent(StatusFilter); + const findArchivedFilter = () => wrapper.findComponent(ArchivedFilter); + const findDividers = () => wrapper.findAll('hr'); + + describe.each` + description | searchMergeRequestsHideArchivedProjects + ${'Renders correctly with Archived Filter disabled'} | ${false} + ${'Renders correctly with Archived Filter enabled'} | ${true} + `('$description', ({ searchMergeRequestsHideArchivedProjects }) => { beforeEach(() => { - createComponent(); + createComponent({ + searchMergeRequestsHideArchivedProjects, + }); + }); + + it('renders StatusFilter', () => { + expect(findStatusFilter().exists()).toBe(true); + }); + + it(`renders correctly ArchivedFilter when searchMergeRequestsHideArchivedProjects is ${searchMergeRequestsHideArchivedProjects}`, () => { + expect(findArchivedFilter().exists()).toBe(searchMergeRequestsHideArchivedProjects); }); - it('renders ConfidentialityFilter', () => { + + it('renders divider correctly', () => { + const dividersCount = searchMergeRequestsHideArchivedProjects ? 1 : 0; + expect(findDividers()).toHaveLength(dividersCount); + }); + }); + + describe('Renders correctly with basic search', () => { + beforeEach(() => { + createComponent({ initialState: { searchType: SEARCH_TYPE_BASIC } }); + }); + + it('renders StatusFilter', () => { expect(findStatusFilter().exists()).toBe(true); }); - it('renders FiltersTemplate', () => { - expect(findFiltersTemplate().exists()).toBe(true); + it("doesn't render ArchivedFilter", () => { + expect(findArchivedFilter().exists()).toBe(false); + }); + + it('renders 1 divider', () => { + expect(findDividers()).toHaveLength(0); + }); + }); + + describe('Renders correctly in new nav', () => { + beforeEach(() => { + createComponent({ + initialState: { + searchType: SEARCH_TYPE_ADVANCED, + useSidebarNavigation: true, + }, + searchMergeRequestsHideArchivedProjects: true, + }); + }); + it('renders StatusFilter', () => { + expect(findStatusFilter().exists()).toBe(true); + }); + + it('renders ArchivedFilter', () => { + expect(findArchivedFilter().exists()).toBe(true); + }); + + it("doesn't render divider", () => { + expect(findDividers()).toHaveLength(0); + }); + }); + + describe('Renders correctly with wrong scope', () => { + beforeEach(() => { + defaultGetters.currentScope = () => 'blobs'; + createComponent(); + }); + it("doesn't render StatusFilter", () => { + expect(findStatusFilter().exists()).toBe(false); + }); + + it("doesn't render ArchivedFilter", () => { + expect(findArchivedFilter().exists()).toBe(false); + }); + + it("doesn't render dividers", () => { + expect(findDividers()).toHaveLength(0); }); }); }); diff --git a/spec/lib/gitlab/ci/config/external/mapper/verifier_spec.rb b/spec/lib/gitlab/ci/config/external/mapper/verifier_spec.rb index 69b0524be9e..f542c0485e0 100644 --- a/spec/lib/gitlab/ci/config/external/mapper/verifier_spec.rb +++ b/spec/lib/gitlab/ci/config/external/mapper/verifier_spec.rb @@ -409,32 +409,6 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper::Verifier, feature_category: expect { process }.to raise_error(expected_error_class) end end - - context 'when introduce_ci_max_total_yaml_size_bytes is disabled' do - before do - stub_feature_flags(introduce_ci_max_total_yaml_size_bytes: false) - end - - context 'when pipeline tree size is within the limit' do - before do - stub_application_setting(ci_max_total_yaml_size_bytes: 10000) - end - - it 'passes the verification' do - expect(process.all?(&:valid?)).to be_truthy - end - end - - context 'when pipeline tree size is larger then the limit' do - before do - stub_application_setting(ci_max_total_yaml_size_bytes: 100) - end - - it 'passes the verification' do - expect(process.all?(&:valid?)).to be_truthy - end - end - end end end end diff --git a/spec/lib/gitlab/experiment/rollout/feature_spec.rb b/spec/lib/gitlab/experiment/rollout/feature_spec.rb index a66f4fea207..cd46e7b3386 100644 --- a/spec/lib/gitlab/experiment/rollout/feature_spec.rb +++ b/spec/lib/gitlab/experiment/rollout/feature_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe Gitlab::Experiment::Rollout::Feature, :experiment do - subject { described_class.new.for(subject_experiment) } + subject { described_class.new(subject_experiment) } let(:subject_experiment) { experiment('namespaced/stub') } diff --git a/spec/lib/gitlab/url_sanitizer_spec.rb b/spec/lib/gitlab/url_sanitizer_spec.rb index 5f76c1de5b1..2c2ef8f13fb 100644 --- a/spec/lib/gitlab/url_sanitizer_spec.rb +++ b/spec/lib/gitlab/url_sanitizer_spec.rb @@ -91,6 +91,25 @@ RSpec.describe Gitlab::UrlSanitizer do end end + describe '.sanitize_masked_url' do + where(:original_url, :masked_url) do + 'http://{domain}.com' | 'http://{domain}.com' + 'http://{domain}/{hook}' | 'http://{domain}/{hook}' + 'http://user:pass@{domain}/hook' | 'http://*****:*****@{domain}/hook' + 'http://user:pass@{domain}:{port}/hook' | 'http://*****:*****@{domain}:{port}/hook' + 'http://user:@{domain}:{port}/hook' | 'http://*****:*****@{domain}:{port}/hook' + 'http://:pass@{domain}:{port}/hook' | 'http://*****:*****@{domain}:{port}/hook' + 'http://user@{domain}:{port}/hook' | 'http://*****:*****@{domain}:{port}/hook' + 'http://u:p@{domain}/hook?email=james@example.com' | 'http://*****:*****@{domain}/hook?email=james@example.com' + 'http://{domain}/hook?email=james@example.com' | 'http://{domain}/hook?email=james@example.com' + 'http://user:{pass}@example.com' | 'http://*****:*****@example.com' + end + + with_them do + it { expect(described_class.sanitize_masked_url(original_url)).to eq(masked_url) } + end + end + describe '#sanitized_url' do context 'credentials in hash' do where(username: ['foo', '', nil], password: ['bar', '', nil]) diff --git a/spec/models/hooks/web_hook_log_spec.rb b/spec/models/hooks/web_hook_log_spec.rb index fd811d4845e..e9a2635bf28 100644 --- a/spec/models/hooks/web_hook_log_spec.rb +++ b/spec/models/hooks/web_hook_log_spec.rb @@ -46,6 +46,20 @@ RSpec.describe WebHookLog, feature_category: :webhooks do end end + context 'with basic auth credentials and masked components' do + let(:web_hook_log) { build(:web_hook_log, web_hook: hook, url: 'http://test:123@{domain}.com:{port}') } + + subject { web_hook_log.save! } + + it { is_expected.to eq(true) } + + it 'obfuscates the basic auth credentials' do + subject + + expect(web_hook_log.url).to eq('http://*****:*****@{domain}.com:{port}') + end + end + context "with users' emails" do let(:author) { build(:user) } let(:user) { build(:user) } diff --git a/spec/support/helpers/features/admin_users_helpers.rb b/spec/support/helpers/features/admin_users_helpers.rb index 9a87ccf113a..b4477537a40 100644 --- a/spec/support/helpers/features/admin_users_helpers.rb +++ b/spec/support/helpers/features/admin_users_helpers.rb @@ -4,7 +4,7 @@ module Features module AdminUsersHelpers def click_user_dropdown_toggle(user_id) page.within("[data-testid='user-actions-#{user_id}']") do - find("[data-testid='dropdown-toggle']").click + find("[data-testid='user-actions-dropdown-toggle']").click end end |