Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
da576e4a0b
commit
9f9d994f13
|
@ -156,7 +156,7 @@ Dangerfile @gl-quality/eng-prod
|
||||||
/app/assets/javascripts/ci/pipeline_schedules/ @gitlab-org/ci-cd/verify/frontend
|
/app/assets/javascripts/ci/pipeline_schedules/ @gitlab-org/ci-cd/verify/frontend
|
||||||
/app/assets/javascripts/pipeline_editor/ @gitlab-org/ci-cd/verify/frontend
|
/app/assets/javascripts/pipeline_editor/ @gitlab-org/ci-cd/verify/frontend
|
||||||
/ee/app/assets/javascripts/ci/ci_minutes_usage/ @gitlab-org/ci-cd/verify/frontend
|
/ee/app/assets/javascripts/ci/ci_minutes_usage/ @gitlab-org/ci-cd/verify/frontend
|
||||||
/ee/app/assets/javascripts/usage_quotas/ci_minutes_usage/ @gitlab-org/ci-cd/verify/frontend
|
/ee/app/assets/javascripts/ci/usage_quotas/ci_minutes_usage/ @gitlab-org/ci-cd/verify/frontend
|
||||||
/ee/app/assets/javascripts/usage_quotas/pipelines/ @gitlab-org/ci-cd/verify/frontend
|
/ee/app/assets/javascripts/usage_quotas/pipelines/ @gitlab-org/ci-cd/verify/frontend
|
||||||
/ee/app/assets/javascripts/reports/ @gitlab-org/ci-cd/verify/frontend
|
/ee/app/assets/javascripts/reports/ @gitlab-org/ci-cd/verify/frontend
|
||||||
|
|
||||||
|
|
|
@ -431,7 +431,7 @@ module SearchHelper
|
||||||
def search_navigation
|
def search_navigation
|
||||||
{
|
{
|
||||||
projects: { sort: 1, label: _("Projects"), data: { qa_selector: 'projects_tab' }, condition: @project.nil? },
|
projects: { sort: 1, label: _("Projects"), data: { qa_selector: 'projects_tab' }, condition: @project.nil? },
|
||||||
blobs: { sort: 2, label: _("Code"), data: { qa_selector: 'code_tab' }, condition: project_search_tabs?(:blobs) || search_service.show_elasticsearch_tabs? || feature_flag_tab_enabled?(:global_search_code_tab) },
|
blobs: { sort: 2, label: _("Code"), data: { qa_selector: 'code_tab' }, condition: project_search_tabs?(:blobs) || (search_service.show_elasticsearch_tabs? && feature_flag_tab_enabled?(:global_search_code_tab)) },
|
||||||
# sort: 3 is reserved for EE items
|
# sort: 3 is reserved for EE items
|
||||||
issues: { sort: 4, label: _("Issues"), condition: project_search_tabs?(:issues) || feature_flag_tab_enabled?(:global_search_issues_tab) },
|
issues: { sort: 4, label: _("Issues"), condition: project_search_tabs?(:issues) || feature_flag_tab_enabled?(:global_search_issues_tab) },
|
||||||
merge_requests: { sort: 5, label: _("Merge requests"), condition: project_search_tabs?(:merge_requests) || feature_flag_tab_enabled?(:global_search_merge_requests_tab) },
|
merge_requests: { sort: 5, label: _("Merge requests"), condition: project_search_tabs?(:merge_requests) || feature_flag_tab_enabled?(:global_search_merge_requests_tab) },
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
%div
|
%div
|
||||||
= _('No authentication methods configured.')
|
= _('No authentication methods configured.')
|
||||||
|
|
||||||
- if Feature.enabled?(:restyle_login_page, @project)
|
- if Feature.enabled?(:restyle_login_page, @project) && Gitlab::CurrentSettings.current_application_settings.terms
|
||||||
%p.gl-px-5
|
%p.gl-px-5
|
||||||
= html_escape(s_("SignUp|By signing in you accept the %{link_start}Terms of Use and acknowledge the Privacy Policy and Cookie Policy%{link_end}.")) % { link_start: "<a href='#{terms_path}' target='_blank' rel='noreferrer noopener'>".html_safe,
|
= html_escape(s_("SignUp|By signing in you accept the %{link_start}Terms of Use and acknowledge the Privacy Policy and Cookie Policy%{link_end}.")) % { link_start: "<a href='#{terms_path}' target='_blank' rel='noreferrer noopener'>".html_safe,
|
||||||
link_end: '</a>'.html_safe }
|
link_end: '</a>'.html_safe }
|
||||||
|
|
|
@ -2703,6 +2703,15 @@
|
||||||
:weight: 1
|
:weight: 1
|
||||||
:idempotent: true
|
:idempotent: true
|
||||||
:tags: []
|
:tags: []
|
||||||
|
- :name: merge_requests_delete_branch
|
||||||
|
:worker_name: MergeRequests::DeleteBranchWorker
|
||||||
|
:feature_category: :source_code_management
|
||||||
|
:has_external_dependencies: false
|
||||||
|
:urgency: :high
|
||||||
|
:resource_boundary: :unknown
|
||||||
|
:weight: 1
|
||||||
|
:idempotent: true
|
||||||
|
:tags: []
|
||||||
- :name: merge_requests_delete_source_branch
|
- :name: merge_requests_delete_source_branch
|
||||||
:worker_name: MergeRequests::DeleteSourceBranchWorker
|
:worker_name: MergeRequests::DeleteSourceBranchWorker
|
||||||
:feature_category: :source_code_management
|
:feature_category: :source_code_management
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module MergeRequests
|
||||||
|
class DeleteBranchWorker
|
||||||
|
include ApplicationWorker
|
||||||
|
|
||||||
|
data_consistency :always
|
||||||
|
|
||||||
|
feature_category :source_code_management
|
||||||
|
urgency :high
|
||||||
|
idempotent!
|
||||||
|
|
||||||
|
def perform(merge_request_id, user_id, branch_name, retarget_branch)
|
||||||
|
merge_request = MergeRequest.find_by_id(merge_request_id)
|
||||||
|
user = User.find_by_id(user_id)
|
||||||
|
|
||||||
|
return unless merge_request.present? && user.present?
|
||||||
|
|
||||||
|
delete_service_result = ::Branches::DeleteService.new(merge_request.source_project, user)
|
||||||
|
.execute(branch_name)
|
||||||
|
|
||||||
|
if Feature.enabled?(:track_delete_source_errors, merge_request.source_project) && delete_service_result&.error?
|
||||||
|
delete_service_result.track_exception
|
||||||
|
end
|
||||||
|
|
||||||
|
return unless retarget_branch
|
||||||
|
|
||||||
|
::MergeRequests::RetargetChainService.new(project: merge_request.source_project, current_user: user)
|
||||||
|
.execute(merge_request)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -18,6 +18,9 @@ class MergeRequests::DeleteSourceBranchWorker
|
||||||
# Source branch changed while it's being removed
|
# Source branch changed while it's being removed
|
||||||
return if merge_request.source_branch_sha != source_branch_sha
|
return if merge_request.source_branch_sha != source_branch_sha
|
||||||
|
|
||||||
|
if Feature.enabled?(:add_delete_branch_worker, merge_request.source_project)
|
||||||
|
::MergeRequests::DeleteBranchWorker.perform_async(merge_request_id, user_id, merge_request.source_branch, true)
|
||||||
|
else
|
||||||
delete_service_result = ::Branches::DeleteService.new(merge_request.source_project, user)
|
delete_service_result = ::Branches::DeleteService.new(merge_request.source_project, user)
|
||||||
.execute(merge_request.source_branch)
|
.execute(merge_request.source_branch)
|
||||||
|
|
||||||
|
@ -27,6 +30,7 @@ class MergeRequests::DeleteSourceBranchWorker
|
||||||
|
|
||||||
::MergeRequests::RetargetChainService.new(project: merge_request.source_project, current_user: user)
|
::MergeRequests::RetargetChainService.new(project: merge_request.source_project, current_user: user)
|
||||||
.execute(merge_request)
|
.execute(merge_request)
|
||||||
|
end
|
||||||
rescue ActiveRecord::RecordNotFound
|
rescue ActiveRecord::RecordNotFound
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
name: add_delete_branch_worker
|
||||||
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102208
|
||||||
|
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/381640
|
||||||
|
milestone: '15.6'
|
||||||
|
type: development
|
||||||
|
group: group::code review
|
||||||
|
default_enabled: false
|
|
@ -299,6 +299,8 @@
|
||||||
- 1
|
- 1
|
||||||
- - merge_requests_create_approval_note
|
- - merge_requests_create_approval_note
|
||||||
- 1
|
- 1
|
||||||
|
- - merge_requests_delete_branch
|
||||||
|
- 1
|
||||||
- - merge_requests_delete_source_branch
|
- - merge_requests_delete_source_branch
|
||||||
- 1
|
- 1
|
||||||
- - merge_requests_execute_approval_hooks
|
- - merge_requests_execute_approval_hooks
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
announcement_milestone: "15.4" # (required) The milestone when this feature was first announced as deprecated.
|
announcement_milestone: "15.4" # (required) The milestone when this feature was first announced as deprecated.
|
||||||
announcement_date: "2022-09-22" # (required) The date of the milestone release when this feature was first announced as deprecated. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
|
announcement_date: "2022-09-22" # (required) The date of the milestone release when this feature was first announced as deprecated. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
|
||||||
removal_milestone: "16.0" # (required) The milestone when this feature is planned to be removed
|
removal_milestone: "16.0" # (required) The milestone when this feature is planned to be removed
|
||||||
removal_date: "2022-05-22"# (required) The date of the milestone release when this feature is planned to be removed. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
|
removal_date: "2022-05-22" # (required) The date of the milestone release when this feature is planned to be removed. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
|
||||||
breaking_change: true # (required) If this deprecation is a breaking change, set this value to true
|
breaking_change: true # (required) If this deprecation is a breaking change, set this value to true
|
||||||
reporter: phikai # (required) GitLab username of the person reporting the deprecation
|
reporter: phikai # (required) GitLab username of the person reporting the deprecation
|
||||||
stage: create # (required) String value of the stage that the feature was created in. e.g., Growth
|
stage: create # (required) String value of the stage that the feature was created in. e.g., Growth
|
||||||
|
|
|
@ -41,9 +41,9 @@
|
||||||
#
|
#
|
||||||
end_of_support_milestone: # (optional) Use "XX.YY" format. The milestone when support for this feature will end.
|
end_of_support_milestone: # (optional) Use "XX.YY" format. The milestone when support for this feature will end.
|
||||||
end_of_support_date: # (optional) The date of the milestone release when support for this feature will end.
|
end_of_support_date: # (optional) The date of the milestone release when support for this feature will end.
|
||||||
#
|
#
|
||||||
# OTHER OPTIONAL FIELDS
|
# OTHER OPTIONAL FIELDS
|
||||||
#
|
#
|
||||||
tiers: # (optional - may be required in the future) An array of tiers that the feature is available in currently. e.g., [Free, Silver, Gold, Core, Premium, Ultimate]
|
tiers: # (optional - may be required in the future) An array of tiers that the feature is available in currently. e.g., [Free, Silver, Gold, Core, Premium, Ultimate]
|
||||||
documentation_url: # (optional) This is a link to the current documentation page
|
documentation_url: # (optional) This is a link to the current documentation page
|
||||||
image_url: # (optional) This is a link to a thumbnail image depicting the feature
|
image_url: # (optional) This is a link to a thumbnail image depicting the feature
|
||||||
|
|
|
@ -219,6 +219,8 @@ The availability objectives for Gitaly clusters assuming a single node failure a
|
||||||
second. Failover requires ten consecutive failed health checks on each
|
second. Failover requires ten consecutive failed health checks on each
|
||||||
Praefect node.
|
Praefect node.
|
||||||
|
|
||||||
|
Improvements to RPO and RTO are proposed in epic [8903](https://gitlab.com/groups/gitlab-org/-/epics/8903).
|
||||||
|
|
||||||
WARNING:
|
WARNING:
|
||||||
If complete cluster failure occurs, disaster recovery plans should be executed. These can affect the
|
If complete cluster failure occurs, disaster recovery plans should be executed. These can affect the
|
||||||
RPO and RTO discussed above.
|
RPO and RTO discussed above.
|
||||||
|
|
|
@ -1028,7 +1028,11 @@ Use **setup** as a noun, and **set up** as a verb. For example:
|
||||||
|
|
||||||
## sign in
|
## sign in
|
||||||
|
|
||||||
Use **sign in** instead of **sign on** or **log on** or **log in**. If the user interface has different words, use those.
|
Use **sign in** or **sign in to**.
|
||||||
|
|
||||||
|
Do not use **sign on** or **sign into**, or **log on**, **log in**, or **log into**.
|
||||||
|
|
||||||
|
If the user interface has different words, use those.
|
||||||
|
|
||||||
You can use **single sign-on**.
|
You can use **single sign-on**.
|
||||||
|
|
||||||
|
|
|
@ -76,6 +76,8 @@ Kubernetes version to a supported version at any time:
|
||||||
GitLab aims to support a new minor Kubernetes version three months after its initial release. GitLab supports at least three production-ready Kubernetes minor
|
GitLab aims to support a new minor Kubernetes version three months after its initial release. GitLab supports at least three production-ready Kubernetes minor
|
||||||
versions at any given time.
|
versions at any given time.
|
||||||
|
|
||||||
|
When installing the agent, use a Helm version compatible with your Kubernetes version. Other versions of Helm might not work. For a list of compatible versions, see the [Helm version support policy](https://helm.sh/docs/topics/version_skew/).
|
||||||
|
|
||||||
Support for deprecated APIs can be removed from the GitLab codebase when we drop support for the Kubernetes version that only supports the deprecated API.
|
Support for deprecated APIs can be removed from the GitLab codebase when we drop support for the Kubernetes version that only supports the deprecated API.
|
||||||
|
|
||||||
Some GitLab features might work on versions not listed here. [This epic](https://gitlab.com/groups/gitlab-org/-/epics/4827) tracks support for Kubernetes versions.
|
Some GitLab features might work on versions not listed here. [This epic](https://gitlab.com/groups/gitlab-org/-/epics/4827) tracks support for Kubernetes versions.
|
||||||
|
|
|
@ -60,7 +60,7 @@ function update_tests_metadata() {
|
||||||
scripts/flaky_examples/prune-old-flaky-examples "${FLAKY_RSPEC_SUITE_REPORT_PATH}"
|
scripts/flaky_examples/prune-old-flaky-examples "${FLAKY_RSPEC_SUITE_REPORT_PATH}"
|
||||||
|
|
||||||
if [[ "$CI_PIPELINE_SOURCE" == "schedule" ]]; then
|
if [[ "$CI_PIPELINE_SOURCE" == "schedule" ]]; then
|
||||||
scripts/insert-rspec-profiling-data
|
PGSSLMODE=$RSPEC_PROFILING_PGSSLMODE PGSSLROOTCERT=$RSPEC_PROFILING_PGSSLROOTCERT PGSSLCERT=$RSPEC_PROFILING_PGSSLCERT PGSSLKEY=$RSPEC_PROFILING_PGSSLKEY scripts/insert-rspec-profiling-data
|
||||||
else
|
else
|
||||||
echo "Not inserting profiling data as the pipeline is not a scheduled one."
|
echo "Not inserting profiling data as the pipeline is not a scheduled one."
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -861,8 +861,8 @@ RSpec.describe SearchHelper do
|
||||||
where(:feature_flag_tab_enabled, :show_elasticsearch_tabs, :project_search_tabs, :condition) do
|
where(:feature_flag_tab_enabled, :show_elasticsearch_tabs, :project_search_tabs, :condition) do
|
||||||
false | false | false | false
|
false | false | false | false
|
||||||
true | true | true | true
|
true | true | true | true
|
||||||
true | false | false | true
|
true | false | false | false
|
||||||
false | true | false | true
|
false | true | false | false
|
||||||
false | false | true | true
|
false | false | true | true
|
||||||
true | false | true | true
|
true | false | true | true
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
RSpec.describe MergeRequests::DeleteBranchWorker do
|
||||||
|
let_it_be(:merge_request) { create(:merge_request) }
|
||||||
|
let_it_be(:user) { create(:user) }
|
||||||
|
|
||||||
|
let(:branch) { merge_request.source_branch }
|
||||||
|
let(:sha) { merge_request.source_branch_sha }
|
||||||
|
let(:retarget_branch) { true }
|
||||||
|
let(:worker) { described_class.new }
|
||||||
|
|
||||||
|
describe '#perform' do
|
||||||
|
context 'with a non-existing merge request' do
|
||||||
|
it 'does nothing' do
|
||||||
|
expect(::Branches::DeleteService).not_to receive(:new)
|
||||||
|
worker.perform(non_existing_record_id, user.id, branch, retarget_branch)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a non-existing user' do
|
||||||
|
it 'does nothing' do
|
||||||
|
expect(::Branches::DeleteService).not_to receive(:new)
|
||||||
|
|
||||||
|
worker.perform(merge_request.id, non_existing_record_id, branch, retarget_branch)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with existing user and merge request' do
|
||||||
|
it 'calls service to delete source branch' do
|
||||||
|
expect_next_instance_of(::Branches::DeleteService) do |instance|
|
||||||
|
expect(instance).to receive(:execute).with(branch)
|
||||||
|
end
|
||||||
|
|
||||||
|
worker.perform(merge_request.id, user.id, branch, retarget_branch)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when retarget branch param is true' do
|
||||||
|
it 'calls the retarget chain service' do
|
||||||
|
expect_next_instance_of(::MergeRequests::RetargetChainService) do |instance|
|
||||||
|
expect(instance).to receive(:execute).with(merge_request)
|
||||||
|
end
|
||||||
|
|
||||||
|
worker.perform(merge_request.id, user.id, branch, retarget_branch)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when retarget branch param is false' do
|
||||||
|
let(:retarget_branch) { false }
|
||||||
|
|
||||||
|
it 'does not call the retarget chain service' do
|
||||||
|
expect(::MergeRequests::RetargetChainService).not_to receive(:new)
|
||||||
|
|
||||||
|
worker.perform(merge_request.id, user.id, branch, retarget_branch)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when delete service returns an error' do
|
||||||
|
let(:service_result) { ServiceResponse.error(message: 'placeholder') }
|
||||||
|
|
||||||
|
it 'tracks the exception' do
|
||||||
|
expect_next_instance_of(::Branches::DeleteService) do |instance|
|
||||||
|
expect(instance).to receive(:execute).with(merge_request.source_branch).and_return(service_result)
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(service_result).to receive(:track_exception).and_call_original
|
||||||
|
|
||||||
|
worker.perform(merge_request.id, user.id, branch, retarget_branch)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when track_delete_source_errors is disabled' do
|
||||||
|
before do
|
||||||
|
stub_feature_flags(track_delete_source_errors: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not track the exception' do
|
||||||
|
expect_next_instance_of(::Branches::DeleteService) do |instance|
|
||||||
|
expect(instance).to receive(:execute).with(merge_request.source_branch).and_return(service_result)
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(service_result).not_to receive(:track_exception)
|
||||||
|
|
||||||
|
worker.perform(merge_request.id, user.id, branch, retarget_branch)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'an idempotent worker' do
|
||||||
|
let(:merge_request) { create(:merge_request) }
|
||||||
|
let(:job_args) { [merge_request.id, sha, user.id, true] }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,6 +10,51 @@ RSpec.describe MergeRequests::DeleteSourceBranchWorker do
|
||||||
let(:worker) { described_class.new }
|
let(:worker) { described_class.new }
|
||||||
|
|
||||||
describe '#perform' do
|
describe '#perform' do
|
||||||
|
context 'when the add_delete_branch_worker feature flag is enabled' do
|
||||||
|
context 'with a non-existing merge request' do
|
||||||
|
it 'does nothing' do
|
||||||
|
expect(::MergeRequests::DeleteBranchWorker).not_to receive(:perform_async)
|
||||||
|
|
||||||
|
worker.perform(non_existing_record_id, sha, user.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a non-existing user' do
|
||||||
|
it 'does nothing' do
|
||||||
|
expect(::MergeRequests::DeleteBranchWorker).not_to receive(:perform_async)
|
||||||
|
|
||||||
|
worker.perform(merge_request.id, sha, non_existing_record_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with existing user and merge request' do
|
||||||
|
it 'creates a new delete branch worker async' do
|
||||||
|
expect(::MergeRequests::DeleteBranchWorker).to receive(:perform_async).with(merge_request.id, user.id,
|
||||||
|
merge_request.source_branch, true)
|
||||||
|
|
||||||
|
worker.perform(merge_request.id, sha, user.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'source branch sha does not match' do
|
||||||
|
it 'does nothing' do
|
||||||
|
expect(::MergeRequests::DeleteBranchWorker).not_to receive(:perform_async)
|
||||||
|
|
||||||
|
worker.perform(merge_request.id, 'new-source-branch-sha', user.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'an idempotent worker' do
|
||||||
|
let(:merge_request) { create(:merge_request) }
|
||||||
|
let(:job_args) { [merge_request.id, sha, user.id] }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the add_delete_branch_worker feature flag is disabled' do
|
||||||
|
before do
|
||||||
|
stub_feature_flags(add_delete_branch_worker: false)
|
||||||
|
end
|
||||||
|
|
||||||
context 'with a non-existing merge request' do
|
context 'with a non-existing merge request' do
|
||||||
it 'does nothing' do
|
it 'does nothing' do
|
||||||
expect(::Branches::DeleteService).not_to receive(:new)
|
expect(::Branches::DeleteService).not_to receive(:new)
|
||||||
|
@ -102,4 +147,5 @@ RSpec.describe MergeRequests::DeleteSourceBranchWorker do
|
||||||
let(:job_args) { [merge_request.id, sha, user.id] }
|
let(:job_args) { [merge_request.id, sha, user.id] }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue