Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2025-04-11 21:08:20 +00:00
parent a1eee0f284
commit 3351b23ded
47 changed files with 238 additions and 89 deletions

View File

@ -300,7 +300,10 @@ export default {
/>
<div v-else class="gl-pr-3"><gl-loading-icon size="sm" inline /></div>
<div class="gl-flex gl-min-w-0 gl-flex-1 gl-flex-col">
<span class="gl-whitespace-normal" data-testid="downstream-title-content">
<span
class="gl-whitespace-normal gl-wrap-anywhere"
data-testid="downstream-title-content"
>
{{ downstreamTitle }}
</span>
<div class="gl-truncate">

View File

@ -1,6 +1,6 @@
<script>
import { GlTabs, GlTab, GlBadge, GlFilteredSearchToken } from '@gitlab/ui';
import { isEqual, pick } from 'lodash';
import { isEqual, pick, get } from 'lodash';
import { __ } from '~/locale';
import { QUERY_PARAM_END_CURSOR, QUERY_PARAM_START_CURSOR } from '~/graphql_shared/constants';
import { numberToMetricPrefix } from '~/lib/utils/number_utils';
@ -9,7 +9,6 @@ import FilteredSearchAndSort from '~/groups_projects/components/filtered_search_
import { calculateGraphQLPaginationQueryParams } from '~/graphql_shared/utils';
import { OPERATORS_IS } from '~/vue_shared/components/filtered_search_bar/constants';
import { ACCESS_LEVEL_OWNER_INTEGER } from '~/access_level/constants';
import projectCountsQuery from '~/projects/your_work/graphql/queries/project_counts.query.graphql';
import * as Sentry from '~/sentry/sentry_browser_wrapper';
import { InternalEvents } from '~/tracking';
import {
@ -26,9 +25,6 @@ const trackingMixin = InternalEvents.mixin();
// Will be made more generic to work with groups and projects in future commits
export default {
name: 'TabsWithList',
i18n: {
projectCountError: __('An error occurred loading the project counts.'),
},
components: {
GlTabs,
GlTab,
@ -98,11 +94,23 @@ export default {
return {};
},
},
tabCountsQuery: {
type: Object,
required: false,
default() {
return {};
},
},
tabCountsQueryErrorMessage: {
type: String,
required: false,
default: __('An error occurred loading the tab counts.'),
},
},
data() {
return {
activeTabIndex: this.initActiveTabIndex(),
counts: this.tabs.reduce((accumulator, tab) => {
tabCounts: this.tabs.reduce((accumulator, tab) => {
return {
...accumulator,
[tab.value]: undefined,
@ -110,32 +118,6 @@ export default {
}, {}),
};
},
apollo: {
counts() {
return {
query: projectCountsQuery,
update(response) {
const {
currentUser: { contributed, starred },
personal,
member,
inactive,
} = response;
return {
contributed: contributed.count,
starred: starred.count,
personal: personal.count,
member: member.count,
inactive: inactive.count,
};
},
error(error) {
createAlert({ message: this.$options.i18n.projectCountError, error, captureError: true });
},
};
},
},
computed: {
activeTab() {
return this.tabs[this.activeTabIndex];
@ -233,6 +215,30 @@ export default {
return this.timestampTypeMap[this.activeSortOption.value];
},
},
async created() {
if (!Object.keys(this.tabCountsQuery).length) {
return;
}
try {
const { data } = await this.$apollo.query({ query: this.tabCountsQuery });
this.tabCounts = this.tabs.reduce((accumulator, tab) => {
const { count } = get(data, tab.countsQueryPath);
return {
...accumulator,
[tab.value]: count,
};
}, {});
} catch (error) {
createAlert({
message: this.tabCountsQueryErrorMessage,
error,
captureError: true,
});
}
},
methods: {
numberToMetricPrefix,
createSortQuery({ sortBy, isAscending }) {
@ -267,7 +273,7 @@ export default {
this.trackEvent(this.eventTracking.tabs, { label: tab.text });
},
tabCount(tab) {
return this.counts[tab.value];
return this.tabCounts[tab.value];
},
shouldShowCountBadge(tab) {
return this.tabCount(tab) !== undefined;

View File

@ -16,6 +16,7 @@ import {
TIMESTAMP_TYPE_CREATED_AT,
TIMESTAMP_TYPE_LAST_ACTIVITY_AT,
} from '~/vue_shared/components/resource_lists/constants';
import projectCountsQuery from '../graphql/queries/project_counts.query.graphql';
import { PROJECT_DASHBOARD_TABS, FIRST_TAB_ROUTE_NAMES } from '../constants';
export default {
@ -44,6 +45,7 @@ export default {
tabs: 'click_tab_on_your_work_projects',
sort: 'click_sort_on_your_work_projects',
},
tabCountsQuery: projectCountsQuery,
name: 'YourWorkProjectsApp',
components: {
TabsWithList,
@ -75,5 +77,7 @@ export default {
:initial-sort="initialSort"
:programming-languages="programmingLanguages"
:event-tracking="$options.eventTracking"
:tab-counts-query="$options.tabCountsQuery"
:tab-counts-query-error-message="__('An error occurred loading the project counts.')"
/>
</template>

View File

@ -27,6 +27,7 @@ export const CONTRIBUTED_TAB = {
query: userProjectsQuery,
variables: { contributed: true },
queryPath: 'currentUser.contributedProjects',
countsQueryPath: 'currentUser.contributed',
emptyStateComponentProps: {
title: s__("Projects|You haven't contributed to any projects yet."),
description: s__(
@ -43,6 +44,7 @@ export const STARRED_TAB = {
query: userProjectsQuery,
variables: { starred: true },
queryPath: 'currentUser.starredProjects',
countsQueryPath: 'currentUser.starred',
emptyStateComponentProps: {
title: s__("Projects|You haven't starred any projects yet."),
description: s__(
@ -59,6 +61,7 @@ export const PERSONAL_TAB = {
query: projectsQuery,
variables: { personal: true },
queryPath: 'projects',
countsQueryPath: 'personal',
emptyStateComponentProps: {
title: s__("Projects|You don't have any personal projects yet."),
},
@ -71,6 +74,7 @@ export const MEMBER_TAB = {
query: projectsQuery,
variables: { membership: true },
queryPath: 'projects',
countsQueryPath: 'member',
emptyStateComponentProps: {
title: s__("Projects|You aren't a member of any projects yet."),
},
@ -83,6 +87,7 @@ export const INACTIVE_TAB = {
query: projectsQuery,
variables: { archived: 'ONLY', membership: true },
queryPath: 'projects',
countsQueryPath: 'inactive',
emptyStateComponentProps: {
title: s__("Projects|You don't have any inactive projects."),
description: s__('Projects|Projects that are archived or pending deletion will appear here.'),

View File

@ -36,6 +36,7 @@
s_("CICD|Use separate caches for protected branches"),
help_text: (s_('CICD|Unprotected branches will not have access to the cache from protected branches.') + ' ' + help_link_separated_caches).html_safe
= render_if_exists 'projects/settings/ci_cd/composite_identities_pipelines', form: f
= render_if_exists 'projects/settings/ci_cd/pipeline_cancelation', form: f
.form-group

View File

@ -1,9 +1,9 @@
# frozen_string_literal: true
require_relative '../../tooling/danger/remote_development/desired_config_generator'
require_relative '../../tooling/danger/remote_development/desired_config_generator_suggestor'
module Danger
class RemoteDevelopment < ::Danger::Plugin
include Tooling::Danger::RemoteDevelopment::DesiredConfigGenerator
include Tooling::Danger::RemoteDevelopment::DesiredConfigGeneratorSuggestor
end
end

View File

@ -0,0 +1,28 @@
# frozen_string_literal: true
class CreateAiTroubleshootJobEventsTable < ClickHouse::Migration
def up
execute <<-SQL
CREATE TABLE IF NOT EXISTS troubleshoot_job_events
(
user_id UInt64 NOT NULL DEFAULT 0,
timestamp DateTime64(6, 'UTC') NOT NULL DEFAULT now64(),
job_id UInt64 NOT NULL DEFAULT 0,
project_id UInt64 NOT NULL DEFAULT 0,
event UInt8 NOT NULL DEFAULT 0,
namespace_path String DEFAULT '',
pipeline_id UInt64 DEFAULT 0,
merge_request_id UInt64 DEFAULT 0
)
ENGINE = ReplacingMergeTree
PARTITION BY toYear(timestamp)
ORDER BY (user_id, event, timestamp)
SQL
end
def down
execute <<-SQL
DROP TABLE IF EXISTS troubleshoot_job_events
SQL
end
end

View File

@ -44,7 +44,6 @@ This is a partial list of the [RSpec metadata](https://rspec.info/features/3-12/
| `:requires_admin` | The test requires an administrator account. Tests with the tag are excluded when run against Canary and Production environments. |
| `:requires_git_protocol_v2` | The test requires that Git protocol version 2 is enabled on the server. It's assumed to be enabled by default but if not the test can be skipped by setting `QA_CAN_TEST_GIT_PROTOCOL_V2` to `false`. |
| `:requires_praefect` | The test requires that the GitLab instance uses [Gitaly Cluster](../../../../administration/gitaly/praefect.md) (a.k.a. Praefect) as the repository storage. It's assumed to be used by default but if not the test can be skipped by setting `QA_CAN_TEST_PRAEFECT` to `false`. |
| `:runner` | The test depends on and sets up a GitLab Runner instance, typically to run a pipeline. |
| `:skip_live_env` | The test is excluded when run against live deployed environments such as Staging, Canary, and Production. |
| `:skip_fips_env` | The test is excluded when run against an environment in FIPS mode. |
| `:skip_signup_disabled` | The test uses UI to sign up a new user and is skipped in any environment that does not allow new user registration via the UI. |

View File

@ -52,13 +52,24 @@ Although this is not mandatory for populating the dependency list, the SBOM docu
- In GitLab 17.2, the `location` field no longer links to the commit where the dependency was last detected when the feature flag `skip_sbom_occurrences_update_on_pipeline_id_change` is enabled. The flag is disabled by default.
- In GitLab 17.3 the `location` field always links to the commit where the dependency was first detected. Feature flag `skip_sbom_occurrences_update_on_pipeline_id_change` removed.
- View dependency paths option [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/519965) in GitLab 17.11 [with a flag](../../../administration/feature_flags.md) named `dependency_paths`. Disabled by default.
{{< /history >}}
{{< alert type="flag" >}}
The availability of this feature is controlled by a feature flag.
For more information, see the history.
{{< /alert >}}
To view the dependencies of a project or all projects in a group:
1. On the left sidebar, select **Search or go to** and find your project or group.
1. Select **Secure > Dependency list**.
1. Optional. If there are transitive dependencies, you can also view all of the dependency paths:
- For a project, in the **Location** column, select **View dependency paths**.
- For a group, in the **Location** column, select the location, then select **View dependency paths**.
Details of each dependency are listed, sorted by decreasing severity of vulnerabilities (if any). You can sort the list instead by component name, packager, or license.
@ -66,7 +77,7 @@ Details of each dependency are listed, sorted by decreasing severity of vulnerab
|:----------|:-----------|
| Component | The dependency's name and version. |
| Packager | The packager used to install the dependency. |
| Location | For system dependencies, this lists the image that was scanned. For application dependencies, this shows a link to the packager-specific lock file in your project that declared the dependency. It also shows the [direct dependents](#dependency-paths) of the dependency, if any, and if supported. |
| Location | For system dependencies, this field lists the image that was scanned. For application dependencies, this field shows a link to the packager-specific lock file in your project that declared the dependency. It also shows the direct [dependents](#dependency-paths), if any. If there are transitive dependencies, selecting **View dependency paths** shows the full path of all dependents. Transitive dependencies are indirect dependents that have a direct dependent as an ancestor. |
| License (for projects only) | Links to dependency's software licenses. A warning badge that includes the number of vulnerabilities detected in the dependency. |
| Projects (for groups only) | Links to the project with the dependency. If multiple projects have the same dependency, the total number of these projects is shown. To go to a project with this dependency, select the **Projects** number, then search for and select its name. The project search feature is supported only on groups that have up to 600 occurrences in their group hierarchy. |

View File

@ -21,7 +21,7 @@ including:
- Available actions
- Linked issues
- Actions log
- Filename and line number of the vulnerability (if available)
- Location
- Severity
For vulnerabilities in the [Common Vulnerabilities and Exposures (CVE)](https://www.cve.org/)
@ -571,3 +571,29 @@ To view the security training for a vulnerability:
1. Select **Secure > Vulnerability report**.
1. Select the vulnerability for which you want to view security training.
1. Select **View training**.
## View the location of a vulnerability in transitive dependencies
{{< history >}}
- View dependency paths option [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/519965) in GitLab 17.11 [with a flag](../../../administration/feature_flags.md) named `dependency_paths`. Disabled by default.
{{< /history >}}
{{< alert type="flag" >}}
The availability of this feature is controlled by a feature flag.
For more information, see the history.
{{< /alert >}}
When managing vulnerabilities found in dependencies in the vulnerability details, under **Location**, you can view:
- The location of the direct dependency where the vulnerability was found.
- If available, the specific line number where the vulnerability occurs.
If the vulnerability occurs in one or more transitive dependencies, knowing only the direct dependency may not be enough. Transitive dependencies are indirect dependencies that have a direct dependent as an ancestor.
If any transitive dependencies exist, you can view the paths to all dependencies, including the transitive dependencies that contain the vulnerability.
- On the vulnerability details page, under **Location**, select **View dependency paths**. If **View dependency paths** doesn't appear, then there are no transitive dependencies.

View File

@ -6742,6 +6742,9 @@ msgstr ""
msgid "An error occurred loading the projects. Please refresh the page to try again."
msgstr ""
msgid "An error occurred loading the tab counts."
msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
@ -11552,6 +11555,9 @@ msgstr ""
msgid "CICD|Allow Git push requests to the repository"
msgstr ""
msgid "CICD|Allow composite identities to run pipelines"
msgstr ""
msgid "CICD|An error occurred while adding the authentication log entries. Please try again."
msgstr ""
@ -11609,6 +11615,9 @@ msgstr ""
msgid "CICD|Continuous deployment to production using timed incremental rollout"
msgstr ""
msgid "CICD|Controls whether AI agents can automatically run pipelines. When disabled, pipelines triggered by AI agents will require manual review and execution by a human user."
msgstr ""
msgid "CICD|Default (user membership and role)"
msgstr ""
@ -29623,6 +29632,9 @@ msgstr ""
msgid "GroupSAML|An error occurred resetting your SCIM token. Please try again."
msgstr ""
msgid "GroupSAML|Any Provider (Default)"
msgstr ""
msgid "GroupSAML|Are you sure you want to remove the SAML group link?"
msgstr ""
@ -29677,6 +29689,9 @@ msgstr ""
msgid "GroupSAML|Identifier"
msgstr ""
msgid "GroupSAML|Identity Provider"
msgstr ""
msgid "GroupSAML|Identity provider single sign-on URL"
msgstr ""
@ -29770,6 +29785,9 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
msgid "GroupSAML|When selected, group sync will only occur when both the SAML group name and provider match."
msgstr ""
msgid "GroupSAML|as %{access_level}"
msgstr ""
@ -71413,6 +71431,9 @@ msgstr ""
msgid "does not match dast_site_validation.project"
msgstr ""
msgid "does not match the name of the predefined control."
msgstr ""
msgid "does not support select options."
msgstr ""
@ -71753,6 +71774,9 @@ msgstr ""
msgid "is not part of the given organization"
msgstr ""
msgid "is not valid."
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
RSpec.describe 'Verify', product_group: :pipeline_authoring do
describe 'Pipeline API defined variable inheritance' do
include_context 'variable inheritance test prep'

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring,
RSpec.describe 'Verify', product_group: :pipeline_authoring,
only: { subdomain: 'staging-canary' } do
# Runs this test only in staging-canary to debug flakiness https://gitlab.com/gitlab-org/gitlab/-/issues/424903
# We need to collect failure data, please don't quarantine for the time being

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
RSpec.describe 'Verify', product_group: :pipeline_authoring do
describe 'Pipeline with project file variables' do
let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
let(:project) { create(:project, name: 'project-with-file-variables') }

View File

@ -24,7 +24,7 @@ module QA
end
end
RSpec.describe 'Manage', :orchestrated, :runner, :requires_admin, :smtp, product_group: :import_and_integrate do
RSpec.describe 'Manage', :orchestrated, :requires_admin, :smtp, product_group: :import_and_integrate do
describe 'Pipeline status emails' do
let(:executor) { "qa-runner-#{SecureRandom.hex(6)}" }
let(:emails) { %w[foo@bar.com baz@buzz.com] }

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Create', :runner, product_group: :code_review do
RSpec.describe 'Create', product_group: :code_review do
describe 'Merge request set to auto-merge' do
let(:runner_name) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
let(:project) { create(:project, name: 'set-to-auto-merge') }

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
RSpec.describe 'Verify', product_group: :pipeline_authoring do
describe 'CI component', :skip_live_env do
let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
let(:tag) { '1.0.0' }

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, product_group: :pipeline_execution do
RSpec.describe 'Verify', product_group: :pipeline_execution do
describe 'Job artifacts' do
context 'when exposed' do
let(:total_jobs_count) { 3 }

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, :requires_admin, product_group: :pipeline_execution do
RSpec.describe 'Verify', :requires_admin, product_group: :pipeline_execution do
describe 'Pipeline configuration access keyword' do
let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
let(:project) { create(:project, name: 'project-with-artifacts', initialize_with_readme: true) }

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, product_group: :pipeline_execution,
RSpec.describe 'Verify', product_group: :pipeline_execution,
quarantine: {
issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/422863',
type: :flaky

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, product_group: :pipeline_execution do
RSpec.describe 'Verify', product_group: :pipeline_execution do
describe "Unlocking job artifacts across pipelines" do
let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
let(:project) { create(:project, name: 'unlock-job-artifacts-project') }

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, product_group: :pipeline_execution do
RSpec.describe 'Verify', product_group: :pipeline_execution do
describe 'Project artifacts' do
context 'when user tries bulk deletion' do
let(:total_jobs_count) { 20 }

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring,
RSpec.describe 'Verify', product_group: :pipeline_authoring,
quarantine: {
issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/523094',
type: :investigating

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, :requires_admin, product_group: :pipeline_authoring do
RSpec.describe 'Verify', :requires_admin, product_group: :pipeline_authoring do
describe 'Pipeline with protected variable' do
let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
let(:protected_value) { Faker::Alphanumeric.alphanumeric(number: 8) }

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner do
RSpec.describe 'Verify' do
describe 'Pipeline with raw variables in YAML', product_group: :pipeline_authoring do
let(:executor) { "qa-runner-#{SecureRandom.hex(6)}" }
let(:pipeline_job_name) { 'rspec' }

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
RSpec.describe 'Verify', product_group: :pipeline_authoring do
describe 'UI defined variable' do
include_context 'variable inheritance test prep'

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
RSpec.describe 'Verify', product_group: :pipeline_authoring do
describe 'UI defined variable' do
include_context 'variable inheritance test prep'

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
RSpec.describe 'Verify', product_group: :pipeline_authoring do
describe 'Include multiple files from a project' do
let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
let(:expected_text) { Faker::Lorem.sentence }

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
RSpec.describe 'Verify', product_group: :pipeline_authoring do
describe 'Include multiple files from multiple projects' do
let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
let(:main_project) { create(:project, name: 'project-with-pipeline') }

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, product_group: :pipeline_execution,
RSpec.describe 'Verify', product_group: :pipeline_execution,
quarantine: {
issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/411510',
type: :flaky

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, product_group: :pipeline_execution do
RSpec.describe 'Verify', product_group: :pipeline_execution do
describe 'Parent-child pipelines independent relationship' do
let!(:project) { create(:project, name: 'pipeline-independent-relationship') }
let!(:runner) { create(:project_runner, project: project, name: project.name, tags: [project.name]) }

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
RSpec.describe 'Verify', product_group: :pipeline_authoring do
describe 'Pass dotenv variables to downstream via bridge' do
let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
let(:upstream_var) { Faker::Alphanumeric.alphanumeric(number: 8) }

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
RSpec.describe 'Verify', product_group: :pipeline_authoring do
describe 'Pipeline with image:pull_policy' do
let(:runner_name) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
let(:job_name) { "test-job-#{pull_policies.join('-')}" }

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, product_group: :pipeline_execution do
RSpec.describe 'Verify', product_group: :pipeline_execution do
describe 'Run pipeline with manual jobs' do
let(:executor) { "qa-runner-#{SecureRandom.hex(4)}" }

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, product_group: :pipeline_execution do
RSpec.describe 'Verify', product_group: :pipeline_execution do
describe "Trigger child pipeline with 'when:manual'" do
let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
let(:project) { create(:project, name: 'project-with-pipeline') }

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
RSpec.describe 'Verify', product_group: :pipeline_authoring do
describe 'Trigger matrix' do
let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
let(:project) { create(:project, name: 'project-with-pipeline') }

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, product_group: :runner do
RSpec.describe 'Verify', product_group: :runner do
describe 'Group runner with deprecated registration token' do
let(:executor) { "qa-runner-#{SecureRandom.hex(6)}" }
let!(:runner) do

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, product_group: :runner do
RSpec.describe 'Verify', product_group: :runner do
describe 'Group runner registration' do
let(:executor) { "qa-runner-#{SecureRandom.hex(6)}" }
let!(:runner) { create(:group_runner, name: executor) }

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, product_group: :runner,
RSpec.describe 'Verify', product_group: :runner,
feature_flag: { name: 'vue_project_runners_settings', scope: :project } do
describe 'Runner registration' do
let(:executor) { "qa-runner-#{SecureRandom.hex(6)}" }

View File

@ -9,7 +9,7 @@ module QA
# pipeline created (Sidekiq read/write) ->
# runner picks up pipeline (API read/write) ->
# User views pipeline succeeds (Web read)
RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
RSpec.describe 'Verify', product_group: :pipeline_authoring do
context 'Endpoint Coverage' do
let!(:project) { create(:project, name: 'endpoint-coverage') }
let!(:runner) { create(:project_runner, project: project, name: project.name, tags: [project.name]) }

View File

@ -3,7 +3,7 @@
require 'digest/sha1'
module QA
RSpec.describe 'Release', :runner, product_group: :environments do
RSpec.describe 'Release', product_group: :environments do
describe 'Git clone using a deploy key' do
let(:runner_name) { "qa-runner-#{SecureRandom.hex(4)}" }
let(:repository_location) { project.repository_ssh_location }

View File

@ -11,7 +11,7 @@
"name": "minimum_approvals_required_2",
"control_type": "internal",
"expression": {
"operator": "=",
"operator": ">=",
"field": "minimum_approvals_required",
"value": 2
}
@ -26,7 +26,7 @@
"name": "minimum_approvals_required_2",
"control_type": "internal",
"expression": {
"operator": "=",
"operator": ">=",
"field": "minimum_approvals_required",
"value": 2
}

View File

@ -47,6 +47,8 @@ describe('YourWorkGroupsApp', () => {
initialSort: defaultPropsData.initialSort,
programmingLanguages: [],
eventTracking: {},
tabCountsQuery: {},
tabCountsQueryErrorMessage: 'An error occurred loading the tab counts.',
});
});
});

View File

@ -88,6 +88,8 @@ const defaultPropsData = {
tabs: 'click_tab_on_your_work_projects',
sort: 'click_sort_on_your_work_projects',
},
tabCountsQuery: projectCountsQuery,
tabCountsQueryErrorMessage: 'An error occurred loading the project counts.',
};
const { bindInternalEventDocument } = useMockInternalEventsTracking();
@ -143,6 +145,7 @@ describe('TabsWithList', () => {
extendedWrapper(findTabByName(tabName)).findByTestId('tab-counter-badge').text();
const findFilteredSearchAndSort = () => wrapper.findComponent(FilteredSearchAndSort);
const findTabView = () => wrapper.findComponent(TabView);
const findBadge = () => wrapper.findComponent(GlBadge);
afterEach(() => {
router = null;
@ -150,14 +153,14 @@ describe('TabsWithList', () => {
});
describe('template', () => {
describe('when project counts are loading', () => {
describe('when tab counts are loading', () => {
it('does not show count badges', async () => {
await createComponent();
expect(wrapper.findComponent(GlBadge).exists()).toBe(false);
expect(findBadge().exists()).toBe(false);
});
});
describe('when project counts are successfully retrieved', () => {
describe('when tab counts are successfully retrieved', () => {
beforeEach(async () => {
await createComponent();
await waitForPromises();
@ -172,24 +175,58 @@ describe('TabsWithList', () => {
});
});
describe('when project counts are not successfully retrieved', () => {
describe('when tab counts are not successfully retrieved', () => {
const error = new Error();
beforeEach(async () => {
await createComponent({ projectsCountHandler: jest.fn().mockRejectedValue(error) });
await waitForPromises();
});
describe('when tabCountsQueryErrorMessage prop is passed', () => {
beforeEach(async () => {
await createComponent({ projectsCountHandler: jest.fn().mockRejectedValue(error) });
await waitForPromises();
});
it('displays error alert', () => {
expect(createAlert).toHaveBeenCalledWith({
message: 'An error occurred loading the project counts.',
error,
captureError: true,
it('displays error alert with message', () => {
expect(createAlert).toHaveBeenCalledWith({
message: defaultPropsData.tabCountsQueryErrorMessage,
error,
captureError: true,
});
});
});
it('does not show count badges', () => {
expect(wrapper.findComponent(GlBadge).exists()).toBe(false);
describe('when tabCountsQueryErrorMessage prop is not passed', () => {
beforeEach(async () => {
await createComponent({
projectsCountHandler: jest.fn().mockRejectedValue(error),
propsData: { tabCountsQueryErrorMessage: undefined },
});
await waitForPromises();
});
it('displays error alert with default message', () => {
expect(createAlert).toHaveBeenCalledWith({
message: 'An error occurred loading the tab counts.',
error,
captureError: true,
});
});
});
it('does not show tab count badges', async () => {
await createComponent({ projectsCountHandler: jest.fn().mockRejectedValue(error) });
await waitForPromises();
expect(findBadge().exists()).toBe(false);
});
});
describe('when tabCountsQuery prop is not passed', () => {
beforeEach(async () => {
await createComponent({ propsData: { tabCountsQuery: {} } });
await waitForPromises();
});
it('does not make GraphQL query or show tab count badges', () => {
expect(findBadge().exists()).toBe(false);
});
});

View File

@ -14,6 +14,7 @@ import {
FILTERED_SEARCH_TERM_KEY,
FILTERED_SEARCH_NAMESPACE,
} from '~/projects/filtered_search_and_sort/constants';
import projectCountsQuery from '~/projects/your_work/graphql/queries/project_counts.query.graphql';
import {
TIMESTAMP_TYPE_CREATED_AT,
TIMESTAMP_TYPE_LAST_ACTIVITY_AT,
@ -65,6 +66,8 @@ describe('YourWorkProjectsApp', () => {
tabs: 'click_tab_on_your_work_projects',
sort: 'click_sort_on_your_work_projects',
},
tabCountsQuery: projectCountsQuery,
tabCountsQueryErrorMessage: 'An error occurred loading the project counts.',
});
});
});

View File

@ -3,10 +3,10 @@
require 'fast_spec_helper'
require 'gitlab/dangerfiles/spec_helper'
require_relative '../../../../tooling/danger/remote_development/desired_config_generator'
require_relative '../../../../tooling/danger/remote_development/desired_config_generator_suggestor'
require_relative '../../../../tooling/danger/project_helper'
RSpec.describe Tooling::Danger::RemoteDevelopment::DesiredConfigGenerator, feature_category: :tooling do
RSpec.describe Tooling::Danger::RemoteDevelopment::DesiredConfigGeneratorSuggestor, feature_category: :workspaces do
subject(:remote_development) { fake_danger.new(helper: fake_helper) }
let(:fake_danger) { DangerSpecHelper.fake_danger.include(described_class) }

View File

@ -5,7 +5,7 @@ require_relative '../suggestor'
module Tooling
module Danger
module RemoteDevelopment
module DesiredConfigGenerator
module DesiredConfigGeneratorSuggestor
include ::Tooling::Danger::Suggestor
WORKSPACE_LIB = 'ee/lib/remote_development/workspace_operations'