diff --git a/.graphqlrc b/.graphqlrc
index 1debc7ab4d3..19c8f2112fa 100644
--- a/.graphqlrc
+++ b/.graphqlrc
@@ -4,4 +4,5 @@ schema:
documents:
- ./app/assets/javascripts/**/*.graphql
- ./ee/app/assets/javascripts/**/*.graphql
+ - ./jh/app/assets/javascripts/**/*.graphql
- ./app/graphql/queries/**/*.graphql
diff --git a/app/assets/javascripts/work_items/components/work_item_attributes_wrapper.vue b/app/assets/javascripts/work_items/components/work_item_attributes_wrapper.vue
index 409436ca6fa..e5e42998efd 100644
--- a/app/assets/javascripts/work_items/components/work_item_attributes_wrapper.vue
+++ b/app/assets/javascripts/work_items/components/work_item_attributes_wrapper.vue
@@ -12,8 +12,10 @@ import {
WIDGET_TYPE_PROGRESS,
WIDGET_TYPE_START_AND_DUE_DATE,
WIDGET_TYPE_TIME_TRACKING,
+ WIDGET_TYPE_ROLLEDUP_DATES,
WIDGET_TYPE_WEIGHT,
WIDGET_TYPE_COLOR,
+ WORK_ITEM_TYPE_VALUE_EPIC,
} from '../constants';
import WorkItemAssigneesInline from './work_item_assignees_inline.vue';
import WorkItemAssigneesWithEdit from './work_item_assignees_with_edit.vue';
@@ -61,6 +63,8 @@ export default {
import('ee_component/work_items/components/work_item_color_inline.vue'),
WorkItemColorWithEdit: () =>
import('ee_component/work_items/components/work_item_color_with_edit.vue'),
+ WorkItemRolledupDates: () =>
+ import('ee_component/work_items/components/work_item_rolledup_dates.vue'),
},
mixins: [glFeatureFlagMixin()],
props: {
@@ -92,6 +96,9 @@ export default {
workItemDueDate() {
return this.isWidgetPresent(WIDGET_TYPE_START_AND_DUE_DATE);
},
+ workItemRolledupDates() {
+ return this.isWidgetPresent(WIDGET_TYPE_ROLLEDUP_DATES);
+ },
workItemWeight() {
return this.isWidgetPresent(WIDGET_TYPE_WEIGHT);
},
@@ -113,6 +120,11 @@ export default {
workItemMilestone() {
return this.isWidgetPresent(WIDGET_TYPE_MILESTONE);
},
+ showRolledupDates() {
+ return (
+ this.glFeatures.workItemsRolledupDates && this.workItemType === WORK_ITEM_TYPE_VALUE_EPIC
+ );
+ },
workItemParent() {
return this.isWidgetPresent(WIDGET_TYPE_HIERARCHY)?.parent;
},
@@ -211,6 +223,20 @@ export default {
@error="$emit('error', $event)"
/>
+
+
+
-
+
0
+ return if changes.length <= process_limit
+
+ # We don't know for sure whether the project has CI enabled or CI rules
+ # that might excluded pipelines from being created.
+ omitted_refs = possible_omitted_pipeline_refs(changes)
+
+ return unless omitted_refs.present?
+
+ # This notification only lets the admin know that we might have skipped some refs.
+ Gitlab::AppJsonLogger.info(
+ message: "Some pipelines may not have been created because ref count exceeded limit",
+ ref_limit: process_limit,
+ total_ref_count: changes.length,
+ possible_omitted_refs: omitted_refs,
+ possible_omitted_ref_count: omitted_refs.length,
+ **Gitlab::ApplicationContext.current
+ )
+ end
+
+ def possible_omitted_pipeline_refs(changes)
+ # Pipelines can only be created on pushed for branch creation or updates
+ omitted_changes = changes.select do |change|
+ change[:index] >= process_limit &&
+ change_action(change) != :removed
+ end
+
+ # rubocop:disable CodeReuse/ActiveRecord -- not an ActiveRecord model
+ # rubocop:disable Database/AvoidUsingPluckWithoutLimit -- not an ActiveRecord model
+ omitted_changes.pluck(:ref).sort
+ # rubocop:enable CodeReuse/ActiveRecord
+ # rubocop:enable Database/AvoidUsingPluckWithoutLimit
end
def create_bulk_push_event(ref_type, action, changes)
diff --git a/app/services/resource_access_tokens/create_service.rb b/app/services/resource_access_tokens/create_service.rb
index c36cc981341..d68b715b850 100644
--- a/app/services/resource_access_tokens/create_service.rb
+++ b/app/services/resource_access_tokens/create_service.rb
@@ -84,7 +84,8 @@ module ResourceAccessTokens
email: username_and_email_generator.email,
username: username_and_email_generator.username,
user_type: :project_bot,
- skip_confirmation: true # Bot users should always have their emails confirmed.
+ skip_confirmation: true, # Bot users should always have their emails confirmed.
+ organization_id: resource.organization_id
}
end
diff --git a/app/workers/members_destroyer/unassign_issuables_worker.rb b/app/workers/members_destroyer/unassign_issuables_worker.rb
index 843789d52f3..41d108d80d7 100644
--- a/app/workers/members_destroyer/unassign_issuables_worker.rb
+++ b/app/workers/members_destroyer/unassign_issuables_worker.rb
@@ -15,9 +15,7 @@ module MembersDestroyer
idempotent!
- # Remove the default value `nil` for `requesting_user_id` after 16.10.
- # TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/442878
- def perform(user_id, entity_id, entity_type, requesting_user_id = nil)
+ def perform(user_id, entity_id, entity_type, requesting_user_id)
unless ENTITY_TYPES.include?(entity_type)
logger.error(
message: "#{entity_type} is not a supported entity.",
@@ -42,9 +40,7 @@ module MembersDestroyer
return
end
- # Remove the condition requesting_user_id after 16.10.
- # TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/442878
- requesting_user = requesting_user_id && User.find(requesting_user_id)
+ requesting_user = User.find(requesting_user_id)
user = User.find(user_id)
entity = entity_type.constantize.find(entity_id)
diff --git a/config/webpack.config.js b/config/webpack.config.js
index 64d82e714c4..52cca8fa6de 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -42,9 +42,8 @@ const {
WEBPACK_OUTPUT_PATH,
WEBPACK_PUBLIC_PATH,
SOURCEGRAPH_PUBLIC_PATH,
- SOURCEGRAPH_OUTPUT_PATH,
- GITLAB_WEB_IDE_OUTPUT_PATH,
GITLAB_WEB_IDE_PUBLIC_PATH,
+ copyFilesPatterns,
} = require('./webpack.constants');
const createIncrementalWebpackCompiler = require('./helpers/incremental_webpack_compiler');
@@ -89,9 +88,6 @@ if (WEBPACK_REPORT) {
NO_HASHED_CHUNKS = true;
}
-const SOURCEGRAPH_PACKAGE = '@sourcegraph/code-host-integration';
-const GITLAB_WEB_IDE_PACKAGE = '@gitlab/web-ide';
-
const devtool = IS_PRODUCTION ? 'source-map' : 'cheap-module-eval-source-map';
let autoEntriesCount = 0;
@@ -711,34 +707,7 @@ module.exports = {
}),
new CopyWebpackPlugin({
- patterns: [
- {
- from: path.join(ROOT_PATH, 'node_modules/pdfjs-dist/cmaps/'),
- to: path.join(WEBPACK_OUTPUT_PATH, 'pdfjs/cmaps/'),
- },
- {
- from: path.join(ROOT_PATH, 'node_modules/pdfjs-dist/legacy/build/pdf.worker.min.js'),
- to: path.join(WEBPACK_OUTPUT_PATH, 'pdfjs/'),
- },
- {
- from: path.join(ROOT_PATH, 'node_modules', SOURCEGRAPH_PACKAGE, '/'),
- to: SOURCEGRAPH_OUTPUT_PATH,
- globOptions: {
- ignore: ['package.json'],
- },
- },
- {
- from: path.join(ROOT_PATH, 'node_modules', GITLAB_WEB_IDE_PACKAGE, 'dist', 'public'),
- to: GITLAB_WEB_IDE_OUTPUT_PATH,
- },
- {
- from: path.join(
- ROOT_PATH,
- 'node_modules/@gitlab/visual-review-tools/dist/visual_review_toolbar.js',
- ),
- to: WEBPACK_OUTPUT_PATH,
- },
- ],
+ patterns: copyFilesPatterns,
}),
// compression can require a lot of compute time and is disabled in CI
diff --git a/config/webpack.constants.js b/config/webpack.constants.js
index 0eb2ac70c82..fd9dd40a4c2 100644
--- a/config/webpack.constants.js
+++ b/config/webpack.constants.js
@@ -18,14 +18,45 @@ const GITLAB_WEB_IDE_PUBLIC_PATH = path.join(WEBPACK_PUBLIC_PATH, GITLAB_WEB_IDE
const IS_EE = require('./helpers/is_ee_env');
const IS_JH = require('./helpers/is_jh_env');
+const SOURCEGRAPH_PACKAGE = '@sourcegraph/code-host-integration';
+const GITLAB_WEB_IDE_PACKAGE = '@gitlab/web-ide';
+
+const copyFilesPatterns = [
+ {
+ from: path.join(ROOT_PATH, 'node_modules/pdfjs-dist/cmaps/'),
+ to: path.join(WEBPACK_OUTPUT_PATH, 'pdfjs/cmaps/'),
+ },
+ {
+ from: path.join(ROOT_PATH, 'node_modules/pdfjs-dist/legacy/build/pdf.worker.min.js'),
+ to: path.join(WEBPACK_OUTPUT_PATH, 'pdfjs/'),
+ },
+ {
+ from: path.join(ROOT_PATH, 'node_modules', SOURCEGRAPH_PACKAGE, '/'),
+ to: SOURCEGRAPH_OUTPUT_PATH,
+ globOptions: {
+ ignore: ['package.json'],
+ },
+ },
+ {
+ from: path.join(ROOT_PATH, 'node_modules', GITLAB_WEB_IDE_PACKAGE, 'dist', 'public'),
+ to: GITLAB_WEB_IDE_OUTPUT_PATH,
+ },
+ {
+ from: path.join(
+ ROOT_PATH,
+ 'node_modules/@gitlab/visual-review-tools/dist/visual_review_toolbar.js',
+ ),
+ to: WEBPACK_OUTPUT_PATH,
+ },
+];
+
module.exports = {
IS_EE,
IS_JH,
ROOT_PATH,
WEBPACK_OUTPUT_PATH,
WEBPACK_PUBLIC_PATH,
- SOURCEGRAPH_OUTPUT_PATH,
SOURCEGRAPH_PUBLIC_PATH,
- GITLAB_WEB_IDE_OUTPUT_PATH,
GITLAB_WEB_IDE_PUBLIC_PATH,
+ copyFilesPatterns,
};
diff --git a/db/docs/batched_background_migrations/purge_security_scans_with_empty_finding_data.yml b/db/docs/batched_background_migrations/purge_security_scans_with_empty_finding_data.yml
index 6b89194939f..c3950095225 100644
--- a/db/docs/batched_background_migrations/purge_security_scans_with_empty_finding_data.yml
+++ b/db/docs/batched_background_migrations/purge_security_scans_with_empty_finding_data.yml
@@ -7,4 +7,4 @@ milestone: '16.10'
queued_migration_version: 20240209153920
# Replace with the approximate date you think it's best to ensure the completion of this BBM.
finalize_after: '2024-03-15'
-finalized_by: # version of the migration that finalized this BBM
+finalized_by: 20240320102510
diff --git a/db/post_migrate/20240320102510_finalize_purge_security_scans_with_empty_finding_data.rb b/db/post_migrate/20240320102510_finalize_purge_security_scans_with_empty_finding_data.rb
new file mode 100644
index 00000000000..2bc6caecf2c
--- /dev/null
+++ b/db/post_migrate/20240320102510_finalize_purge_security_scans_with_empty_finding_data.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+class FinalizePurgeSecurityScansWithEmptyFindingData < Gitlab::Database::Migration[2.2]
+ disable_ddl_transaction!
+
+ milestone '16.11'
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ def up
+ return if Gitlab.com? || !Gitlab.ee?
+
+ ensure_batched_background_migration_is_finished(
+ job_class_name: 'PurgeSecurityScansWithEmptyFindingData',
+ table_name: :security_scans,
+ column_name: :id,
+ job_arguments: [],
+ finalize: true
+ )
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/schema_migrations/20240320102510 b/db/schema_migrations/20240320102510
new file mode 100644
index 00000000000..0a5b3967137
--- /dev/null
+++ b/db/schema_migrations/20240320102510
@@ -0,0 +1 @@
+9cf0040ec4eb9f9baa7bdef04e8afe07bcac0091053ae7810440993609d0f1bc
\ No newline at end of file
diff --git a/doc/administration/geo/secondary_proxy/index.md b/doc/administration/geo/secondary_proxy/index.md
index 61d6369c56c..5dd20db041b 100644
--- a/doc/administration/geo/secondary_proxy/index.md
+++ b/doc/administration/geo/secondary_proxy/index.md
@@ -76,31 +76,6 @@ a single URL used by all Geo sites, including the primary.
In Kubernetes, you can [use the same domain under `global.hosts.domain` as for the primary site](https://docs.gitlab.com/charts/advanced/geo/index.html).
-## Geo proxying with Separate URLs
-
-> - Geo secondary proxying for separate URLs is [enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/346112) in GitLab 15.1.
-
-NOTE:
-The feature flag described in this section is planned to be deprecated and removed in a future release. Support for read-only Geo secondary sites is proposed in [issue 366810](https://gitlab.com/gitlab-org/gitlab/-/issues/366810), you can upvote and share your use cases in that issue.
-
-If you run into issues, to disable this feature, disable the `geo_secondary_proxy_separate_urls` feature flag.
-
-1. SSH into one node running Rails on your primary Geo site and run:
-
- ```shell
- sudo gitlab-rails runner "Feature.disable(:geo_secondary_proxy_separate_urls)"
- ```
-
-1. Restart Puma on all of the nodes running Rails on your secondary Geo site:
-
- ```shell
- sudo gitlab-ctl restart puma
- ```
-
-In Kubernetes, you can run the same command in the toolbox pod. Refer to the
-[Kubernetes cheat sheet](https://docs.gitlab.com/charts/troubleshooting/kubernetes_cheat_sheet.html#gitlab-specific-kubernetes-information)
-for details.
-
## Limitations
- When secondary proxying is used, the asynchronous Geo replication can cause unexpected issues for accelerated
@@ -204,3 +179,30 @@ gitlab:
extraEnv:
GEO_SECONDARY_PROXY: "0"
```
+
+## Geo proxying with Separate URLs
+
+> - Geo secondary proxying for separate URLs is [enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/346112) in GitLab 15.1.
+
+NOTE:
+The feature flag described in this section is planned to be deprecated and removed in a future release. Support for read-only Geo secondary sites is proposed in [issue 366810](https://gitlab.com/gitlab-org/gitlab/-/issues/366810), you can upvote and share your use cases in that issue.
+
+Geo proxying for seperate URLs is enabled by default from GitLab 15.1. This allows secondary sites to proxy actions to the primary site even if the URLS are different.
+
+If you run into issues, disable the `geo_secondary_proxy_separate_urls` feature flag to disable the feature.
+
+1. SSH into one node running Rails on your primary Geo site and run:
+
+ ```shell
+ sudo gitlab-rails runner "Feature.disable(:geo_secondary_proxy_separate_urls)"
+ ```
+
+1. Restart Puma on all of the nodes running Rails on your secondary Geo site:
+
+ ```shell
+ sudo gitlab-ctl restart puma
+ ```
+
+In Kubernetes, you can run the same command in the toolbox pod. Refer to the
+[Kubernetes cheat sheet](https://docs.gitlab.com/charts/troubleshooting/kubernetes_cheat_sheet.html#gitlab-specific-kubernetes-information)
+for details.
diff --git a/doc/development/cloud_connector/index.md b/doc/development/cloud_connector/index.md
index 5162b14b191..c705e106e9b 100644
--- a/doc/development/cloud_connector/index.md
+++ b/doc/development/cloud_connector/index.md
@@ -104,8 +104,8 @@ To add a new feature bound to a scope:
services:
new_feature_scope:
service_start_time: 2024-02-15 00:00:00 UTC
- min_gitlab_version: '16.8'
- bundled_with: 'duo_pro'
+ min_gitlab_version: '16.8'
+ bundled_with: 'duo_pro'
```
1. **Optional:** If the backend service the token is used for requires additional claims to be embedded in the
diff --git a/lib/gitlab/content_security_policy/directives.rb b/lib/gitlab/content_security_policy/directives.rb
index 3df0ec76839..09500ec623d 100644
--- a/lib/gitlab/content_security_policy/directives.rb
+++ b/lib/gitlab/content_security_policy/directives.rb
@@ -16,7 +16,7 @@ module Gitlab
end
def self.script_src
- "'strict-dynamic' 'self' 'unsafe-inline' 'unsafe-eval' https://www.google.com/recaptcha/ https://www.recaptcha.net"
+ "'strict-dynamic' 'self' 'unsafe-eval' https://www.google.com/recaptcha/ https://www.recaptcha.net"
end
def self.style_src
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 2566813f707..02e7e3c519f 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -57339,12 +57339,18 @@ msgstr ""
msgid "WorkItem|Existing task"
msgstr ""
+msgid "WorkItem|Fixed"
+msgstr ""
+
msgid "WorkItem|History only"
msgstr ""
msgid "WorkItem|Incident"
msgstr ""
+msgid "WorkItem|Inherited"
+msgstr ""
+
msgid "WorkItem|Issue"
msgstr ""
diff --git a/package.json b/package.json
index cf465cf008b..91922a91e98 100644
--- a/package.json
+++ b/package.json
@@ -267,6 +267,7 @@
"gettext-extractor": "^3.7.0",
"gettext-extractor-vue": "^5.1.0",
"glob": "^7.1.6",
+ "globby": "^11.0.1",
"jest": "^28.1.3",
"jest-canvas-mock": "^2.4.0",
"jest-diff": "^28.1.3",
diff --git a/scripts/review_apps/base-config.yaml b/scripts/review_apps/base-config.yaml
index f6931196235..9748e5d98c3 100644
--- a/scripts/review_apps/base-config.yaml
+++ b/scripts/review_apps/base-config.yaml
@@ -91,10 +91,10 @@ gitlab:
# Based on https://console.cloud.google.com/monitoring/metrics-explorer;duration=P14D?pageState=%7B%22xyChart%22:%7B%22constantLines%22:%5B%5D,%22dataSets%22:%5B%7B%22plotType%22:%22LINE%22,%22targetAxis%22:%22Y1%22,%22timeSeriesFilter%22:%7B%22aggregations%22:%5B%7B%22crossSeriesReducer%22:%22REDUCE_NONE%22,%22groupByFields%22:%5B%5D,%22perSeriesAligner%22:%22ALIGN_RATE%22%7D,%7B%22crossSeriesReducer%22:%22REDUCE_NONE%22,%22groupByFields%22:%5B%5D,%22perSeriesAligner%22:%22ALIGN_MEAN%22%7D%5D,%22apiSource%22:%22DEFAULT_CLOUD%22,%22crossSeriesReducer%22:%22REDUCE_NONE%22,%22filter%22:%22metric.type%3D%5C%22kubernetes.io%2Fcontainer%2Fcpu%2Fcore_usage_time%5C%22%20resource.type%3D%5C%22k8s_container%5C%22%20resource.label.%5C%22container_name%5C%22%3D%5C%22sidekiq%5C%22%22,%22groupByFields%22:%5B%5D,%22minAlignmentPeriod%22:%2260s%22,%22perSeriesAligner%22:%22ALIGN_RATE%22,%22secondaryCrossSeriesReducer%22:%22REDUCE_NONE%22,%22secondaryGroupByFields%22:%5B%5D%7D%7D%5D,%22options%22:%7B%22mode%22:%22STATS%22%7D,%22y1Axis%22:%7B%22label%22:%22%22,%22scale%22:%22LINEAR%22%7D%7D%7D&project=gitlab-review-apps
cpu: 400m
# Based on https://console.cloud.google.com/monitoring/metrics-explorer;duration=P14D?pageState=%7B%22xyChart%22:%7B%22constantLines%22:%5B%5D,%22dataSets%22:%5B%7B%22plotType%22:%22LINE%22,%22targetAxis%22:%22Y1%22,%22timeSeriesFilter%22:%7B%22aggregations%22:%5B%7B%22crossSeriesReducer%22:%22REDUCE_NONE%22,%22groupByFields%22:%5B%5D,%22perSeriesAligner%22:%22ALIGN_MEAN%22%7D%5D,%22apiSource%22:%22DEFAULT_CLOUD%22,%22crossSeriesReducer%22:%22REDUCE_NONE%22,%22filter%22:%22metric.type%3D%5C%22kubernetes.io%2Fcontainer%2Fmemory%2Fused_bytes%5C%22%20resource.type%3D%5C%22k8s_container%5C%22%20resource.label.%5C%22container_name%5C%22%3D%5C%22sidekiq%5C%22%22,%22groupByFields%22:%5B%5D,%22minAlignmentPeriod%22:%2260s%22,%22perSeriesAligner%22:%22ALIGN_MEAN%22%7D%7D%5D,%22options%22:%7B%22mode%22:%22STATS%22%7D,%22y1Axis%22:%7B%22label%22:%22%22,%22scale%22:%22LINEAR%22%7D%7D%7D&project=gitlab-review-apps
- memory: 2000Mi
+ memory: 1500Mi
limits:
cpu: 700m
- memory: 2400Mi
+ memory: 2800Mi
hpa:
cpu:
targetAverageValue: 650m
diff --git a/spec/frontend/work_items/mock_data.js b/spec/frontend/work_items/mock_data.js
index a2994874070..1127331677b 100644
--- a/spec/frontend/work_items/mock_data.js
+++ b/spec/frontend/work_items/mock_data.js
@@ -635,6 +635,7 @@ export const workItemResponseFactory = ({
allowsMultipleAssignees = true,
assigneesWidgetPresent = true,
datesWidgetPresent = true,
+ rolledupDatesWidgetPresent = false,
weightWidgetPresent = true,
timeTrackingWidgetPresent = true,
participantsWidgetPresent = true,
@@ -738,6 +739,18 @@ export const workItemResponseFactory = ({
startDate: '2022-01-01',
}
: { type: 'MOCK TYPE' },
+ rolledupDatesWidgetPresent
+ ? {
+ __typename: 'WorkItemWidgetRolledupDates',
+ type: 'ROLLEDUP_DATES',
+ dueDate: null,
+ dueDateFixed: null,
+ dueDateIsFixed: false,
+ startDate: null,
+ startDateFixed: null,
+ startDateIsFixed: false,
+ }
+ : { type: 'MOCK TYPE' },
weightWidgetPresent
? {
__typename: 'WorkItemWidgetWeight',
diff --git a/spec/services/git/process_ref_changes_service_spec.rb b/spec/services/git/process_ref_changes_service_spec.rb
index c117988f0a1..d96fedaf531 100644
--- a/spec/services/git/process_ref_changes_service_spec.rb
+++ b/spec/services/git/process_ref_changes_service_spec.rb
@@ -134,6 +134,8 @@ RSpec.describe Git::ProcessRefChangesService, feature_category: :source_code_man
it "creates exactly #{described_class::PIPELINE_PROCESS_LIMIT} pipelines" do
stub_const("#{described_class}::PIPELINE_PROCESS_LIMIT", changes.count - 1)
+ expect(Gitlab::AppJsonLogger).not_to receive(:info)
+
expect { subject.execute }.to change { Ci::Pipeline.count }.by(described_class::PIPELINE_PROCESS_LIMIT)
end
end
@@ -216,7 +218,7 @@ RSpec.describe Git::ProcessRefChangesService, feature_category: :source_code_man
context 'when there are merge requests associated with branches' do
let(:tag_changes) do
[
- { index: 0, oldrev: Gitlab::Git::SHA1_BLANK_SHA, newrev: '789012', ref: "refs/tags/v10.0.0" }
+ { index: 7, oldrev: Gitlab::Git::SHA1_BLANK_SHA, newrev: '789012', ref: "refs/tags/v10.0.0" }
]
end
@@ -232,7 +234,9 @@ RSpec.describe Git::ProcessRefChangesService, feature_category: :source_code_man
]
end
- let(:git_changes) { double(branch_changes: branch_changes, tag_changes: tag_changes) }
+ let(:git_changes) do
+ double(branch_changes: branch_changes, tag_changes: tag_changes)
+ end
before do
allow(MergeRequests::PushedBranchesService).to receive(:new).and_return(
@@ -277,6 +281,26 @@ RSpec.describe Git::ProcessRefChangesService, feature_category: :source_code_man
subject.execute
end
+
+ context 'when git_push_create_all_pipelines is disabled' do
+ before do
+ stub_feature_flags(git_push_create_all_pipelines: false)
+ end
+
+ it 'logs a warning' do
+ expect(Gitlab::AppJsonLogger).to receive(:info).with(
+ hash_including(
+ message: "Some pipelines may not have been created because ref count exceeded limit",
+ ref_limit: described_class::PIPELINE_PROCESS_LIMIT,
+ total_ref_count: branch_changes.count + tag_changes.count,
+ possible_omitted_refs: ["#{ref_prefix}/changed2", "refs/tags/v10.0.0"],
+ possible_omitted_ref_count: 2
+ )
+ )
+
+ subject.execute
+ end
+ end
end
end
diff --git a/spec/services/resource_access_tokens/create_service_spec.rb b/spec/services/resource_access_tokens/create_service_spec.rb
index 940d9858cdd..e0f3f9e6109 100644
--- a/spec/services/resource_access_tokens/create_service_spec.rb
+++ b/spec/services/resource_access_tokens/create_service_spec.rb
@@ -5,9 +5,10 @@ require 'spec_helper'
RSpec.describe ResourceAccessTokens::CreateService, feature_category: :system_access do
subject { described_class.new(user, resource, params).execute }
+ let_it_be(:organization) { create(:organization) }
let_it_be(:user) { create(:user) }
- let_it_be(:project) { create(:project, :private) }
- let_it_be(:group) { create(:group, :private) }
+ let_it_be(:project) { create(:project, :private, organization: organization) }
+ let_it_be(:group) { create(:group, :private, organization: organization) }
let_it_be(:params) { {} }
let_it_be(:max_pat_access_token_lifetime) do
PersonalAccessToken::MAX_PERSONAL_ACCESS_TOKEN_LIFETIME_IN_DAYS.days.from_now.to_date.freeze
@@ -19,7 +20,7 @@ RSpec.describe ResourceAccessTokens::CreateService, feature_category: :system_ac
describe '#execute' do
shared_examples 'token creation fails' do
- let(:resource) { create(:project) }
+ let_it_be(:resource) { create(:project, organization: organization) }
it 'does not add the project bot as a member' do
expect { subject }.not_to change { resource.members.count }
@@ -47,6 +48,7 @@ RSpec.describe ResourceAccessTokens::CreateService, feature_category: :system_ac
expect(access_token.user.reload.user_type).to eq("project_bot")
expect(access_token.user.created_by_id).to eq(user.id)
+ expect(access_token.user.namespace.organization.id).to eq(resource.organization.id)
end
context 'email confirmation status' do
@@ -363,5 +365,20 @@ RSpec.describe ResourceAccessTokens::CreateService, feature_category: :system_ac
end
end
end
+
+ context 'when resource organization is not set', :enable_admin_mode do
+ let_it_be(:resource) { create(:project, :private, organization: nil) }
+ let_it_be(:default_organization) { Organizations::Organization.default_organization }
+ let(:user) { create(:admin) }
+
+ it 'uses database default' do
+ response = subject
+
+ access_token = response.payload[:access_token]
+ expect(access_token.user.namespace.organization).to eq(
+ default_organization
+ )
+ end
+ end
end
end
diff --git a/spec/support/shared_examples/features/work_items_shared_examples.rb b/spec/support/shared_examples/features/work_items_shared_examples.rb
index 934b496b822..b398d0b705b 100644
--- a/spec/support/shared_examples/features/work_items_shared_examples.rb
+++ b/spec/support/shared_examples/features/work_items_shared_examples.rb
@@ -861,3 +861,64 @@ RSpec.shared_examples 'work items iteration' do
end
end
end
+
+RSpec.shared_context 'with work_items_rolledup_dates' do |flag|
+ before do
+ stub_feature_flags(work_items_rolledup_dates: flag)
+
+ page.refresh
+ wait_for_all_requests
+ end
+end
+
+RSpec.shared_examples 'work items rolled up dates' do
+ let(:work_item_rolledup_dates_selector) { '[data-testid="work-item-rolledup-dates"]' }
+
+ include_context 'with work_items_rolledup_dates', true
+
+ context 'for accessibility' do
+ it 'passes axe automated accessibility testing in closed state' do
+ expect(page).to have_selector(work_item_rolledup_dates_selector)
+ expect(page).to be_axe_clean.within(work_item_rolledup_dates_selector)
+ end
+
+ it 'passes axe automated accessibility testing in open state' do
+ within(work_item_rolledup_dates_selector) do
+ click_button _('Edit')
+ wait_for_requests
+
+ expect(page).to be_axe_clean.within(work_item_rolledup_dates_selector)
+ end
+ end
+ end
+
+ context 'when edit is clicked' do
+ it 'selects and updates the dates to fixed once selected', :aggregate_failures do
+ expect(find_field('Inherited')).to be_checked
+
+ find_and_click_edit(work_item_rolledup_dates_selector)
+
+ within work_item_rolledup_dates_selector do
+ fill_in 'Start', with: '2021-01-01'
+ fill_in 'Due', with: '2021-01-02'
+ end
+
+ # Click outside to save
+ find("body").click
+
+ within work_item_rolledup_dates_selector do
+ expect(find_field('Fixed')).to be_checked
+ expect(page).to have_text('Start: Jan 1, 2021')
+ expect(page).to have_text('Due: Jan 2, 2021')
+ end
+ end
+ end
+
+ context 'when feature flag is disabled' do
+ include_context 'with work_items_rolledup_dates', false
+
+ it 'does not show rolled up dates' do
+ expect(page).not_to have_selector(work_item_rolledup_dates_selector)
+ end
+ end
+end
diff --git a/vite.config.js b/vite.config.js
index 41bc1d19914..f1d3342c719 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -1,4 +1,5 @@
import { readFileSync } from 'node:fs';
+import { stat, mkdir, copyFile } from 'node:fs/promises';
import path from 'node:path';
import { defineConfig } from 'vite';
@@ -6,6 +7,7 @@ import vue from '@vitejs/plugin-vue2';
import graphql from '@rollup/plugin-graphql';
import RubyPlugin from 'vite-plugin-ruby';
import chokidar from 'chokidar';
+import globby from 'globby';
import { viteCommonjs } from '@originjs/vite-plugin-commonjs';
import webpackConfig from './config/webpack.config';
import {
@@ -13,6 +15,7 @@ import {
IS_JH,
SOURCEGRAPH_PUBLIC_PATH,
GITLAB_WEB_IDE_PUBLIC_PATH,
+ copyFilesPatterns,
} from './config/webpack.constants';
/* eslint-disable import/extensions */
import { viteCSSCompilerPlugin } from './scripts/frontend/lib/compile_css.mjs';
@@ -90,6 +93,76 @@ const autoRestartPlugin = {
},
};
+/**
+ * This is a simple-reimplementation of the copy-webpack-plugin
+ *
+ * it also uses the `globby` package under the hood, and _only_ allows for copying
+ * 1. absolute paths
+ * 2. files and directories.
+ */
+function viteCopyPlugin({ patterns }) {
+ return {
+ name: 'viteCopyPlugin',
+ async configureServer() {
+ console.warn('Start copying files...');
+ let count = 0;
+
+ const allTheFiles = patterns.map(async (patternEntry) => {
+ const { from, to, globOptions = {} } = patternEntry;
+
+ // By only supporting absolute paths we simplify
+ // the implementation a lot
+ if (!path.isAbsolute(from)) {
+ throw new Error(`'from' path is not absolute: ${path}`);
+ }
+ if (!path.isAbsolute(to)) {
+ throw new Error(`'to' path is not absolute: ${path}`);
+ }
+
+ let pattern = '';
+ let sourceRoot = '';
+ const fromStat = await stat(from);
+ if (fromStat.isDirectory()) {
+ sourceRoot = from;
+ pattern = path.join(from, '**/*');
+ } else if (fromStat.isFile()) {
+ sourceRoot = path.dirname(from);
+ pattern = from;
+ } else {
+ // No need to support globs, because we do not
+ // use them yet...
+ throw new Error('Our implementation does not support globs.');
+ }
+
+ globOptions.dot = globOptions.dot ?? true;
+
+ const paths = await globby(pattern, globOptions);
+
+ return paths.map((srcPath) => {
+ const targetPath = path.join(to, path.relative(sourceRoot, srcPath));
+ return { srcPath, targetPath };
+ });
+ });
+
+ const srcTargetMap = (await Promise.all(allTheFiles)).flat();
+
+ await Promise.all(
+ srcTargetMap.map(async ({ srcPath, targetPath }) => {
+ try {
+ await mkdir(path.dirname(targetPath), { recursive: true });
+ await copyFile(srcPath, targetPath);
+ count += 1;
+ } catch (e) {
+ console.warn(`Could not copy ${srcPath} => ${targetPath}`);
+ }
+ }),
+ );
+
+ console.warn(`Done copying ${count} files...`);
+ },
+ };
+}
+
export default defineConfig({
cacheDir: path.resolve(__dirname, 'tmp/cache/vite'),
resolve: {
@@ -110,6 +183,9 @@ export default defineConfig({
plugins: [
viteCSSCompilerPlugin({ shouldWatch: viteGDKConfig.hmr !== null }),
viteTailwindCompilerPlugin({ shouldWatch: viteGDKConfig.hmr !== null }),
+ viteCopyPlugin({
+ patterns: copyFilesPatterns,
+ }),
viteGDKConfig.enabled ? autoRestartPlugin : null,
fixedRubyPlugin,
vue({