Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2024-01-16 00:08:29 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2024-01-16 00:08:29 +0300
commit2cfe59f72a03a796bb1cd262f337d2b6764ef1d5 (patch)
treece657730bc164f06c560b884d192a5c5b3b822d9
parent854a0164ea775b84f5ef2508926780144bbc981a (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/usage_quotas/storage/components/namespace_storage_app.vue67
-rw-r--r--app/assets/javascripts/usage_quotas/storage/components/storage_usage_overview_card.vue51
-rw-r--r--app/assets/javascripts/usage_quotas/storage/components/storage_usage_statistics.vue33
-rw-r--r--app/assets/javascripts/work_items/components/shared/work_item_link_child_contents.vue2
-rw-r--r--doc/development/permissions/custom_roles.md90
-rw-r--r--doc/development/permissions/predefined_roles.md4
-rw-r--r--doc/user/application_security/policies/scan-result-policies.md4
-rwxr-xr-xscripts/lint-doc.sh3
-rw-r--r--spec/frontend/usage_quotas/storage/components/namespace_storage_app_spec.js51
-rw-r--r--spec/frontend/usage_quotas/storage/components/storage_usage_overview_card_spec.js44
-rw-r--r--spec/frontend/usage_quotas/storage/components/storage_usage_statistics_spec.js43
-rw-r--r--spec/frontend/usage_quotas/storage/mock_data.js2
-rw-r--r--spec/tooling/lib/tooling/find_changes_spec.rb35
-rwxr-xr-xtooling/lib/tooling/find_changes.rb8
14 files changed, 425 insertions, 12 deletions
diff --git a/app/assets/javascripts/usage_quotas/storage/components/namespace_storage_app.vue b/app/assets/javascripts/usage_quotas/storage/components/namespace_storage_app.vue
new file mode 100644
index 00000000000..ddf240fcafa
--- /dev/null
+++ b/app/assets/javascripts/usage_quotas/storage/components/namespace_storage_app.vue
@@ -0,0 +1,67 @@
+<script>
+import { GlAlert } from '@gitlab/ui';
+import StorageUsageStatistics from 'ee_else_ce/usage_quotas/storage/components/storage_usage_statistics.vue';
+
+export default {
+ name: 'NamespaceStorageApp',
+ components: {
+ GlAlert,
+ StorageUsageStatistics,
+ },
+ props: {
+ namespaceLoadingError: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ projectsLoadingError: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ isNamespaceStorageStatisticsLoading: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ namespace: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
+ },
+ computed: {
+ usedStorage() {
+ return (
+ // This is the coefficient adjusted forked repo size, only used in EE
+ this.namespace.rootStorageStatistics?.costFactoredStorageSize ??
+ // This is the actual storage size value, used in CE or when the above is disabled
+ this.namespace.rootStorageStatistics?.storageSize
+ );
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <gl-alert
+ v-if="namespaceLoadingError || projectsLoadingError"
+ variant="danger"
+ :dismissible="false"
+ class="gl-mt-4"
+ >
+ {{
+ s__(
+ 'UsageQuota|An error occured while loading the storage usage details. Please refresh the page to try again.',
+ )
+ }}
+ </gl-alert>
+ <storage-usage-statistics
+ :additional-purchased-storage-size="namespace.additionalPurchasedStorageSize"
+ :used-storage="usedStorage"
+ :loading="isNamespaceStorageStatisticsLoading"
+ />
+
+ <slot name="ee-storage-app"></slot>
+ </div>
+</template>
diff --git a/app/assets/javascripts/usage_quotas/storage/components/storage_usage_overview_card.vue b/app/assets/javascripts/usage_quotas/storage/components/storage_usage_overview_card.vue
new file mode 100644
index 00000000000..6e73fc0ba69
--- /dev/null
+++ b/app/assets/javascripts/usage_quotas/storage/components/storage_usage_overview_card.vue
@@ -0,0 +1,51 @@
+<script>
+import { GlCard, GlSkeletonLoader } from '@gitlab/ui';
+import NumberToHumanSize from '~/vue_shared/components/number_to_human_size/number_to_human_size.vue';
+
+export default {
+ name: 'StorageUsageOverviewCard',
+ components: {
+ GlCard,
+ GlSkeletonLoader,
+ NumberToHumanSize,
+ },
+ props: {
+ usedStorage: {
+ type: Number,
+ required: false,
+ default: null,
+ },
+ loading: {
+ type: Boolean,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-card>
+ <gl-skeleton-loader v-if="loading" :height="64">
+ <rect width="140" height="30" x="5" y="0" rx="4" />
+ <rect width="240" height="10" x="5" y="40" rx="4" />
+ <rect width="340" height="10" x="5" y="54" rx="4" />
+ </gl-skeleton-loader>
+
+ <div v-else>
+ <div class="gl-font-weight-bold" data-testid="namespace-storage-card-title">
+ {{ s__('UsageQuota|Namespace storage used') }}
+ </div>
+ <div class="gl-font-size-h-display gl-font-weight-bold gl-line-height-ratio-1000 gl-my-3">
+ <number-to-human-size label-class="gl-font-lg" :value="Number(usedStorage)" plain-zero />
+ </div>
+ <hr class="gl-my-4" />
+ <p>
+ {{
+ s__(
+ 'UsageQuota|Namespace total storage represents the sum of storage consumed by all projects, Container Registry, and Dependency Proxy.',
+ )
+ }}
+ </p>
+ </div>
+ </gl-card>
+</template>
diff --git a/app/assets/javascripts/usage_quotas/storage/components/storage_usage_statistics.vue b/app/assets/javascripts/usage_quotas/storage/components/storage_usage_statistics.vue
new file mode 100644
index 00000000000..d7e550dd715
--- /dev/null
+++ b/app/assets/javascripts/usage_quotas/storage/components/storage_usage_statistics.vue
@@ -0,0 +1,33 @@
+<script>
+import StorageUsageOverviewCard from './storage_usage_overview_card.vue';
+
+export default {
+ name: 'StorageUsageStatistics',
+ components: {
+ StorageUsageOverviewCard,
+ },
+ props: {
+ usedStorage: {
+ type: Number,
+ required: false,
+ default: 0,
+ },
+ loading: {
+ type: Boolean,
+ required: true,
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <h3 data-testid="overview-subtitle">{{ s__('UsageQuota|Namespace overview') }}</h3>
+ <div class="gl-display-grid gl-md-grid-template-columns-2 gl-gap-5 gl-py-4">
+ <storage-usage-overview-card
+ :used-storage="usedStorage"
+ :loading="loading"
+ data-testid="namespace-usage-total"
+ />
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/work_items/components/shared/work_item_link_child_contents.vue b/app/assets/javascripts/work_items/components/shared/work_item_link_child_contents.vue
index 503328f7b03..78afb9a04ef 100644
--- a/app/assets/javascripts/work_items/components/shared/work_item_link_child_contents.vue
+++ b/app/assets/javascripts/work_items/components/shared/work_item_link_child_contents.vue
@@ -131,7 +131,7 @@ export default {
class="item-body work-item-link-child gl-relative gl-display-flex gl-flex-grow-1 gl-overflow-break-word gl-min-w-0 gl-pl-3 gl-pr-2 gl-py-2 gl-mx-n2 gl-rounded-base gl-gap-3"
data-testid="links-child"
>
- <div class="item-contents gl-display-flex gl-flex-grow-1 gl-flex-wrap gl-min-w-0">
+ <div class="gl-display-flex gl-flex-grow-1 gl-flex-wrap gl-min-w-0">
<div
class="gl-display-flex gl-flex-grow-1 gl-flex-wrap flex-xl-nowrap gl-align-items-center gl-justify-content-space-between gl-gap-3 gl-min-w-0"
>
diff --git a/doc/development/permissions/custom_roles.md b/doc/development/permissions/custom_roles.md
index d2986aa3a59..53589658f56 100644
--- a/doc/development/permissions/custom_roles.md
+++ b/doc/development/permissions/custom_roles.md
@@ -205,6 +205,95 @@ If you have any concerns, put the new ability behind a feature flag.
- When you enable the ability by default, add the `feature_flag_enabled_milestone` and `feature_flag_enabled_mr` attributes to the appropriate ability YAML file and regenerate the documentation.
- You do not have to include these attributes in the YAML file if the feature flag is enabled by default in the same release as the ability is introduced.
+#### Testing
+
+Unit tests are preferred to test out changes to any policies affected by the
+addition of new custom permissions. Custom Roles is an Ultimate tier feature so
+these tests can be found in the `ee/spec/policies` directory. The [spec file](https://gitlab.com/gitlab-org/gitlab/-/blob/13baa4e8c92a56260591a5bf0a58d3339890ee10/ee/spec/policies/project_policy_spec.rb#L2726-2740) for
+the `ProjectPolicy` contains shared examples that can be used to test out the
+following conditions:
+
+- when the `custom_roles` licensed feature is not enabled
+- when the `custom_roles` licensed feature is enabled
+ - when a user is a member of a custom role via an inherited group member
+ - when a user is a member of a custom role via a direct group member
+ - when a user is a member of a custom role via a direct project membership
+
+Below is an example for testing out `ProjectPolicy` related changes.
+
+```ruby
+ context 'for a role with `custom_permission` enabled' do
+ let(:member_role_abilities) { { custom_permission: true } }
+ let(:allowed_abilities) { [:custom_permission] }
+
+ it_behaves_like 'custom roles abilities'
+ end
+```
+
+Request specs are preferred to test out any endpoint that allow access via a custom role permission.
+This includes controllers, REST API, and GraphQL. Examples of request specs can be found in `ee/spec/requests/custom_roles/`. In this directory you will find a sub-directory named after each permission that can be enabled via a custom role.
+The `custom_roles` licensed feature must be enabled to test this functionality.
+
+Below is an example of the typical setup that is required to test out a
+Rails Controller endpoint.
+
+```ruby
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :repository, :in_group) }
+ let_it_be(:role) { create(:member_role, :guest, namespace: project.group, custom_permission: true) }
+ let_it_be(:membership) { create(:project_member, :guest, member_role: role, user: user, project: project) }
+
+ before do
+ stub_licensed_features(custom_roles: true)
+ sign_in(user)
+ end
+
+ describe MyController do
+ describe '#show' do
+ it 'allows access' do
+ get my_controller_path(project)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template(:show)
+ end
+ end
+ end
+```
+
+Below is an example of the typical setup that is required to test out a GraphQL
+mutation.
+
+```ruby
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :repository, :in_group) }
+ let_it_be(:role) { create(:member_role, :guest, namespace: project.group, custom_permission: true) }
+ let_it_be(:membership) { create(:project_member, :guest, member_role: role, user: user, project: project) }
+
+ before do
+ stub_licensed_features(custom_roles: true)
+ end
+
+ describe MyMutation do
+ include GraphqlHelpers
+
+ describe '#show' do
+ it 'allows access' do
+ post_graphql_mutation(graphql_mutation(:my_mutation, {
+ example: "Example"
+ }), current_user: user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ mutation_response = graphql_mutation_response(:my_mutation)
+ expect(mutation_response).to be_present
+ expect(mutation_response["errors"]).to be_empty
+ end
+ end
+ end
+```
+
+[`GITLAB_DEBUG_POLICIES=true`](#finding-existing-abilities-checks) can be used
+to troubleshoot runtime policy decisions.
+
## Custom abilities definition
All new custom abilities must have a type definition stored in `ee/config/custom_abilities` that contains a single source of truth for every ability that is part of custom roles feature.
@@ -217,6 +306,7 @@ To add a new custom ability:
- Use the `ee/bin/custom-ability` CLI to create the YAML definition automatically.
- Perform manual steps to create a new file in `ee/config/custom_abilities/` with the filename matching the name of the ability name.
1. Add contents to the file that conform to the [schema](#schema) defined in `ee/config/custom_abilities/types/type_schema.json`.
+1. Add [tests](#testing) for the new ability in `ee/spec/requests/custom_roles/` with a new directory named after the ability name.
### Schema
diff --git a/doc/development/permissions/predefined_roles.md b/doc/development/permissions/predefined_roles.md
index 7cb00977e1f..577cf6192c4 100644
--- a/doc/development/permissions/predefined_roles.md
+++ b/doc/development/permissions/predefined_roles.md
@@ -83,10 +83,10 @@ module):
- Maintainer (`40`)
- Owner (`50`)
-If a user is the member of both a project and the project parent groups, the
+If a user is a member of both a project and the project parent groups, the
highest permission is the applied access level for the project.
-If a user is the member of a project, but not the parent groups, they
+If a user is a member of a project, but not the parent groups, they
can still view the groups and their entities (like epics).
Project membership (where the group membership is already taken into account)
diff --git a/doc/user/application_security/policies/scan-result-policies.md b/doc/user/application_security/policies/scan-result-policies.md
index 7ddf4a52f01..e2ec6b8ae56 100644
--- a/doc/user/application_security/policies/scan-result-policies.md
+++ b/doc/user/application_security/policies/scan-result-policies.md
@@ -92,9 +92,6 @@ the following sections and tables provide an alternative.
> The `approval_settings` fields were [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/418752) in GitLab 16.4 [with flags](../../../administration/feature_flags.md) named `scan_result_policies_block_unprotecting_branches`, `scan_result_any_merge_request`, or `scan_result_policies_block_force_push`. See the `approval_settings` section below for more information.
-FLAG:
-On self-managed GitLab, by default the `approval_settings` field is available. To hide the feature, an administrator can [disable the feature flags](../../../administration/feature_flags.md) named `scan_result_policies_block_unprotecting_branches`, `scan_result_any_merge_request` and `scan_result_policies_block_force_push`. See the `approval_settings` section below for more information. On GitLab.com, the `approval_settings` field is available.
-
| Field | Type | Required | Possible values | Description |
|---------------------|--------------------|----------|-----------------|----------------------------------------------------------|
| `name` | `string` | true | | Name of the policy. Maximum of 255 characters. |
@@ -195,7 +192,6 @@ the defined policy.
FLAG:
On self-managed GitLab, by default the `block_branch_modification` field is available. To hide the feature, an administrator can [disable the feature flag](../../../administration/feature_flags.md) named `scan_result_policies_block_unprotecting_branches`. On GitLab.com, this feature is available.
-On self-managed GitLab, by default the `prevent_approval_by_author`, `prevent_approval_by_commit_author`, `remove_approvals_with_new_commit`, and `require_password_to_approve` fields are available. To hide the feature, an administrator can [disable the feature flag](../../../administration/feature_flags.md) named `scan_result_any_merge_request`. On GitLab.com, this feature is available.
On self-managed GitLab, by default the `prevent_pushing_and_force_pushing` field is available. To hide the feature, an administrator can [disable the feature flag](../../../administration/feature_flags.md) named `scan_result_policies_block_force_push`. On GitLab.com, this feature is available.
The settings set in the policy overwrite settings in the project.
diff --git a/scripts/lint-doc.sh b/scripts/lint-doc.sh
index 46d7159d71f..eccc5c0c748 100755
--- a/scripts/lint-doc.sh
+++ b/scripts/lint-doc.sh
@@ -143,7 +143,8 @@ then
ruby -r './tooling/lib/tooling/find_changes' -e "Tooling::FindChanges.new(
from: :api,
changed_files_pathname: '${DOC_CHANGES_FILE}',
- file_filter: ->(file) { !file['deleted_file'] && file['new_path'] =~ %r{doc/.*\.md|lint-doc\.sh|docs\.gitlab-ci\.yml} }
+ file_filter: ->(file) { !file['deleted_file'] && file['new_path'] =~ %r{doc/.*\.md|\.vale|\.markdownlint|lint-doc\.sh|docs\.gitlab-ci\.yml} },
+ only_new_paths: true
).execute"
if grep -E "\.vale|\.markdownlint|lint-doc\.sh|docs\.gitlab-ci\.yml" < $DOC_CHANGES_FILE
then
diff --git a/spec/frontend/usage_quotas/storage/components/namespace_storage_app_spec.js b/spec/frontend/usage_quotas/storage/components/namespace_storage_app_spec.js
new file mode 100644
index 00000000000..e4f99d401a2
--- /dev/null
+++ b/spec/frontend/usage_quotas/storage/components/namespace_storage_app_spec.js
@@ -0,0 +1,51 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import NamespaceStorageApp from '~/usage_quotas/storage/components/namespace_storage_app.vue';
+import StorageUsageStatistics from '~/usage_quotas/storage/components/storage_usage_statistics.vue';
+import { defaultNamespaceProvideValues } from '../mock_data';
+
+const defaultProps = {
+ namespaceLoadingError: false,
+ projectsLoadingError: false,
+ isNamespaceStorageStatisticsLoading: false,
+ // hardcoding object until we move test_fixtures from ee/ to here
+ namespace: {
+ rootStorageStatistics: {
+ storageSize: 1234,
+ },
+ },
+};
+
+describe('NamespaceStorageApp', () => {
+ /** @type {import('helpers/vue_test_utils_helper').ExtendedWrapper} */
+ let wrapper;
+
+ const findStorageUsageStatistics = () => wrapper.findComponent(StorageUsageStatistics);
+
+ const createComponent = ({ provide = {}, props = {} } = {}) => {
+ wrapper = shallowMountExtended(NamespaceStorageApp, {
+ provide: {
+ ...defaultNamespaceProvideValues,
+ ...provide,
+ },
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ });
+ };
+
+ describe('Namespace usage overview', () => {
+ describe('StorageUsageStatistics', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('passes the correct props to StorageUsageStatistics', () => {
+ expect(findStorageUsageStatistics().props()).toMatchObject({
+ usedStorage: defaultProps.namespace.rootStorageStatistics.storageSize,
+ loading: false,
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/usage_quotas/storage/components/storage_usage_overview_card_spec.js b/spec/frontend/usage_quotas/storage/components/storage_usage_overview_card_spec.js
new file mode 100644
index 00000000000..c79b6b94ac1
--- /dev/null
+++ b/spec/frontend/usage_quotas/storage/components/storage_usage_overview_card_spec.js
@@ -0,0 +1,44 @@
+import { GlSkeletonLoader } from '@gitlab/ui';
+import { numberToHumanSize } from '~/lib/utils/number_utils';
+import StorageUsageOverviewCard from '~/usage_quotas/storage/components/storage_usage_overview_card.vue';
+import NumberToHumanSize from '~/vue_shared/components/number_to_human_size/number_to_human_size.vue';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+
+describe('StorageUsageOverviewCard', () => {
+ /** @type {import('helpers/vue_test_utils_helper').ExtendedWrapper} */
+ let wrapper;
+ const defaultProps = {
+ purchasedStorage: 0,
+ // hardcoding value until we move test_fixtures from ee/ to here
+ usedStorage: 1234,
+ loading: false,
+ };
+
+ const createComponent = ({ props = {} } = {}) => {
+ wrapper = shallowMountExtended(StorageUsageOverviewCard, {
+ propsData: { ...defaultProps, ...props },
+ stubs: {
+ NumberToHumanSize,
+ },
+ });
+ };
+
+ const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
+
+ it('displays the used storage value', () => {
+ createComponent();
+ expect(wrapper.text()).toContain(numberToHumanSize(defaultProps.usedStorage, 1));
+ });
+
+ describe('skeleton loader', () => {
+ it('renders skeleton loader when loading prop is true', () => {
+ createComponent({ props: { loading: true } });
+ expect(findSkeletonLoader().exists()).toBe(true);
+ });
+
+ it('does not render skeleton loader when loading prop is false', () => {
+ createComponent({ props: { loading: false } });
+ expect(findSkeletonLoader().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/usage_quotas/storage/components/storage_usage_statistics_spec.js b/spec/frontend/usage_quotas/storage/components/storage_usage_statistics_spec.js
new file mode 100644
index 00000000000..73d02dc273f
--- /dev/null
+++ b/spec/frontend/usage_quotas/storage/components/storage_usage_statistics_spec.js
@@ -0,0 +1,43 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import StorageUsageStatistics from '~/usage_quotas/storage/components/storage_usage_statistics.vue';
+import StorageUsageOverviewCard from '~/usage_quotas/storage/components/storage_usage_overview_card.vue';
+
+const defaultProps = {
+ // hardcoding value until we move test_fixtures from ee/ to here
+ usedStorage: 1234,
+ loading: false,
+};
+
+describe('StorageUsageStatistics', () => {
+ /** @type {import('helpers/vue_test_utils_helper').ExtendedWrapper} */
+ let wrapper;
+
+ const createComponent = ({ props = {} } = {}) => {
+ wrapper = shallowMountExtended(StorageUsageStatistics, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ });
+ };
+
+ const findOverviewSubtitle = () => wrapper.findByTestId('overview-subtitle');
+ const findStorageUsageOverviewCard = () => wrapper.findComponent(StorageUsageOverviewCard);
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('shows the namespace storage overview subtitle', () => {
+ expect(findOverviewSubtitle().text()).toBe('Namespace overview');
+ });
+
+ describe('StorageStatisticsCard', () => {
+ it('passes the correct props to StorageUsageOverviewCard', () => {
+ expect(findStorageUsageOverviewCard().props()).toEqual({
+ usedStorage: defaultProps.usedStorage,
+ loading: false,
+ });
+ });
+ });
+});
diff --git a/spec/frontend/usage_quotas/storage/mock_data.js b/spec/frontend/usage_quotas/storage/mock_data.js
index 16c03a13028..266c1150815 100644
--- a/spec/frontend/usage_quotas/storage/mock_data.js
+++ b/spec/frontend/usage_quotas/storage/mock_data.js
@@ -6,3 +6,5 @@ export const mockEmptyResponse = { data: { project: null } };
export const defaultProjectProvideValues = {
projectPath: '/project-path',
};
+
+export const defaultNamespaceProvideValues = {};
diff --git a/spec/tooling/lib/tooling/find_changes_spec.rb b/spec/tooling/lib/tooling/find_changes_spec.rb
index 85e3eadac6f..be28b228edd 100644
--- a/spec/tooling/lib/tooling/find_changes_spec.rb
+++ b/spec/tooling/lib/tooling/find_changes_spec.rb
@@ -16,7 +16,8 @@ RSpec.describe Tooling::FindChanges, feature_category: :tooling do
predictive_tests_pathname: predictive_tests_pathname,
frontend_fixtures_mapping_pathname: frontend_fixtures_mapping_pathname,
from: from,
- file_filter: file_filter)
+ file_filter: file_filter,
+ only_new_paths: only_new_paths)
end
let(:changed_files_pathname) { changed_files_file.path }
@@ -25,6 +26,7 @@ RSpec.describe Tooling::FindChanges, feature_category: :tooling do
let(:from) { :api }
let(:gitlab_client) { double('GitLab') } # rubocop:disable RSpec/VerifiedDoubles
let(:file_filter) { ->(_) { true } }
+ let(:only_new_paths) { false }
around do |example|
self.changed_files_file = Tempfile.new('changed_files_file')
@@ -122,6 +124,37 @@ RSpec.describe Tooling::FindChanges, feature_category: :tooling do
expect(File.read(changed_files_file)).to eq('doc/index.md')
end
end
+
+ context 'when used with only_new_paths' do
+ let(:only_new_paths) { true }
+
+ let(:mr_changes_array) do
+ [
+ {
+ "new_path" => "scripts/test.js",
+ "old_path" => "scripts/test.js"
+ },
+ {
+ "new_path" => "doc/renamed_index.md",
+ "old_path" => "doc/index.md"
+ }
+ ]
+ end
+
+ before do
+ # rubocop:disable RSpec/VerifiedDoubles -- The class from the GitLab gem isn't public, so we cannot use verified doubles for it.
+ allow(gitlab_client).to receive(:merge_request_changes)
+ .with('dummy-project', '1234')
+ .and_return(double(changes: mr_changes_array))
+ # rubocop:enable RSpec/VerifiedDoubles
+ end
+
+ it 'only writes new file paths to output' do
+ subject
+
+ expect(File.read(changed_files_file)).to eq('doc/renamed_index.md scripts/test.js')
+ end
+ end
end
context 'when fetching changes from changed files' do
diff --git a/tooling/lib/tooling/find_changes.rb b/tooling/lib/tooling/find_changes.rb
index f6fdf042c15..8a92242e167 100755
--- a/tooling/lib/tooling/find_changes.rb
+++ b/tooling/lib/tooling/find_changes.rb
@@ -15,7 +15,8 @@ module Tooling
changed_files_pathname: nil,
predictive_tests_pathname: nil,
frontend_fixtures_mapping_pathname: nil,
- file_filter: ->(_) { true }
+ file_filter: ->(_) { true },
+ only_new_paths: false
)
raise ArgumentError, ':from can only be :api or :changed_files' unless
@@ -30,6 +31,7 @@ module Tooling
@frontend_fixtures_mapping_pathname = frontend_fixtures_mapping_pathname
@from = from
@file_filter = file_filter
+ @api_path_attributes = only_new_paths ? %w[new_path] : %w[new_path old_path]
end
def execute
@@ -53,7 +55,7 @@ module Tooling
attr_reader :gitlab_token, :gitlab_endpoint, :mr_project_path,
:mr_iid, :changed_files_pathname, :predictive_tests_pathname,
- :frontend_fixtures_mapping_pathname, :file_filter
+ :frontend_fixtures_mapping_pathname, :file_filter, :api_path_attributes
def gitlab
@gitlab ||= begin
@@ -86,7 +88,7 @@ module Tooling
case @from
when :api
mr_changes.changes.select(&file_filter).flat_map do |change|
- change.to_h.values_at('old_path', 'new_path')
+ change.to_h.values_at(*api_path_attributes)
end.uniq
else
read_array_from_file(changed_files_pathname)