mirror of
https://github.com/opf/openproject.git
synced 2026-06-13 19:20:00 +00:00
remove sprint.rb and move agile/sprint.rb
This commit is contained in:
@@ -41,7 +41,7 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
render(
|
||||
Primer::Alpha::Select.new(
|
||||
name: "target_id",
|
||||
label: Agile::Sprint.human_model_name,
|
||||
label: Sprint.human_model_name,
|
||||
visually_hide_label: true
|
||||
)
|
||||
) do |select|
|
||||
|
||||
@@ -44,7 +44,7 @@ module Backlogs
|
||||
@work_package = work_package
|
||||
@project = project
|
||||
@move_action = move_action
|
||||
@sprints = Agile::Sprint.for_project(@project).not_completed.order_by_date
|
||||
@sprints = Sprint.for_project(@project).not_completed.order_by_date
|
||||
@sprints = @sprints.where.not(id: work_package.sprint_id) if work_package.sprint_id
|
||||
end
|
||||
end
|
||||
|
||||
@@ -122,7 +122,7 @@ module Backlogs
|
||||
end
|
||||
|
||||
def resolved_active_sprint_ids
|
||||
active_sprint_ids || Agile::Sprint.for_project(sprint.project).active.pluck(:id)
|
||||
active_sprint_ids || Sprint.for_project(sprint.project).active.pluck(:id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -33,7 +33,7 @@ module Sprints
|
||||
validate :user_authorized
|
||||
|
||||
def self.model
|
||||
Agile::Sprint
|
||||
Sprint
|
||||
end
|
||||
|
||||
attribute :name
|
||||
|
||||
@@ -35,7 +35,7 @@ module Sprints
|
||||
validate :no_unfinished_work_packages
|
||||
|
||||
def self.model
|
||||
Agile::Sprint
|
||||
Sprint
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -67,7 +67,7 @@ module Sprints
|
||||
|
||||
def validate_no_other_active_sprint
|
||||
return unless model.in_planning?
|
||||
return unless Agile::Sprint.where(project: model.project).active.where.not(id: model.id).exists?
|
||||
return unless Sprint.where(project: model.project).active.where.not(id: model.id).exists?
|
||||
|
||||
errors.add :status, :only_one_active_sprint_allowed
|
||||
end
|
||||
|
||||
@@ -41,8 +41,8 @@ module WorkPackages
|
||||
private
|
||||
|
||||
def active_sprint_in_sharer_project
|
||||
unless Agile::Sprint
|
||||
.native_to_sprint_source(Agile::Sprint.find_by(id: model.sprint_id_was).project)
|
||||
unless Sprint
|
||||
.native_to_sprint_source(Sprint.find_by(id: model.sprint_id_was).project)
|
||||
.in_planning
|
||||
.exists?(id: model.sprint_id)
|
||||
errors.add(:sprint, :not_eligible_for_moving)
|
||||
|
||||
@@ -68,10 +68,10 @@ module Backlogs
|
||||
@backlog_buckets = Agile::BacklogBucket.for_project(@project)
|
||||
end
|
||||
|
||||
@sprints = Agile::Sprint.for_project(@project)
|
||||
.not_completed
|
||||
.order_by_date
|
||||
.includes(:project, :task_boards)
|
||||
@sprints = Sprint.for_project(@project)
|
||||
.not_completed
|
||||
.order_by_date
|
||||
.includes(:project, :task_boards)
|
||||
|
||||
@stories_by_sprint_id = WorkPackage
|
||||
.where(sprint: @sprints, project: @project)
|
||||
|
||||
@@ -54,7 +54,7 @@ module Backlogs
|
||||
@sprint_id = params.delete(:sprint_id)
|
||||
return unless @sprint_id
|
||||
|
||||
@sprint = Agile::Sprint.for_project(@project).visible.find(@sprint_id)
|
||||
@sprint = Sprint.for_project(@project).visible.find(@sprint_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -44,7 +44,7 @@ module Backlogs
|
||||
end
|
||||
|
||||
max_position = backlog_items_scope.maximum(:position) || 0
|
||||
open_sprints_exist = Agile::Sprint.for_project(@project).visible.not_completed.exists?
|
||||
open_sprints_exist = Sprint.for_project(@project).visible.not_completed.exists?
|
||||
|
||||
render(Backlogs::InboxMenuComponent.new(
|
||||
work_package: @work_package,
|
||||
@@ -115,7 +115,7 @@ module Backlogs
|
||||
end
|
||||
|
||||
def replace_sprint_component_via_turbo_stream(sprint_id)
|
||||
sprint = Agile::Sprint.for_project(@project).visible.find(sprint_id)
|
||||
sprint = Sprint.for_project(@project).visible.find(sprint_id)
|
||||
replace_via_turbo_stream(
|
||||
component: Backlogs::SprintComponent.new(sprint:, project: @project),
|
||||
method: :morph
|
||||
|
||||
@@ -48,7 +48,7 @@ module Backlogs
|
||||
def new_dialog
|
||||
call = ::Sprints::SetAttributesService.new(
|
||||
user: current_user,
|
||||
model: Agile::Sprint.new,
|
||||
model: Sprint.new,
|
||||
contract_class: ::EmptyContract
|
||||
).call(attributes: converted_sprint_params)
|
||||
|
||||
@@ -56,14 +56,14 @@ module Backlogs
|
||||
end
|
||||
|
||||
def edit_dialog
|
||||
@sprint = Agile::Sprint.for_project(@project).visible.find(params[:sprint_id])
|
||||
@sprint = Sprint.for_project(@project).visible.find(params[:sprint_id])
|
||||
|
||||
respond_with_dialog Backlogs::NewSprintDialogComponent.new(sprint: @sprint, state: :edit)
|
||||
end
|
||||
|
||||
def refresh_form
|
||||
id = edit_sprint_params.dig(:sprint, :id)
|
||||
sprint = id.present? ? Agile::Sprint.for_project(@project).visible.find(id) : Agile::Sprint.new
|
||||
sprint = id.present? ? Sprint.for_project(@project).visible.find(id) : Sprint.new
|
||||
|
||||
call = ::Sprints::SetAttributesService.new(
|
||||
user: current_user,
|
||||
@@ -156,7 +156,7 @@ module Backlogs
|
||||
Backlogs::FinishSprintDialogComponent.new(
|
||||
sprint: @sprint,
|
||||
project: @project,
|
||||
available_sprints: Agile::Sprint.native_to_sprint_source(@project).in_planning.where.not(id: @sprint.id).order_by_date
|
||||
available_sprints: Sprint.native_to_sprint_source(@project).in_planning.where.not(id: @sprint.id).order_by_date
|
||||
)
|
||||
)
|
||||
end
|
||||
@@ -165,7 +165,7 @@ module Backlogs
|
||||
load_project
|
||||
|
||||
sprint_id = params[:sprint_id]
|
||||
@sprint = Agile::Sprint.for_project(@project).visible.find(sprint_id) if sprint_id
|
||||
@sprint = Sprint.for_project(@project).visible.find(sprint_id) if sprint_id
|
||||
end
|
||||
|
||||
def sprint_params
|
||||
|
||||
@@ -38,7 +38,7 @@ module Backlogs
|
||||
# Deferred ActionMenu items (Primer include-fragment).
|
||||
def menu
|
||||
max_position = @allowed_stories.maximum(:position) || 0
|
||||
open_sprints_exist = Agile::Sprint.for_project(@project).visible.not_completed.where.not(id: @sprint.id).exists?
|
||||
open_sprints_exist = Sprint.for_project(@project).visible.not_completed.where.not(id: @sprint.id).exists?
|
||||
|
||||
render(Backlogs::StoryMenuListComponent.new(
|
||||
story: @story,
|
||||
@@ -51,7 +51,7 @@ module Backlogs
|
||||
layout: false)
|
||||
end
|
||||
|
||||
# Move a story from an Agile::Sprint to another Agile::Sprint, or the Inbox.
|
||||
# Move a story from an Sprint to another Sprint, or the Inbox.
|
||||
def move
|
||||
# The update service reloads the story internally (via #move_after),
|
||||
# so we memoize the previous sprint_id before the call.
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#-- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
# Intended to eventually replace the `Sprint` model from models/sprint.rb
|
||||
# Namespaced for now so that the rest of the application can keep using the old model.
|
||||
# Remove this namespace and the old class once all usages have been replaced.
|
||||
module Agile
|
||||
class Sprint < ApplicationRecord
|
||||
self.table_name = "sprints"
|
||||
|
||||
include ::Scopes::Scoped
|
||||
|
||||
belongs_to :project
|
||||
has_many :work_packages, inverse_of: :sprint, dependent: :nullify
|
||||
has_many :task_boards,
|
||||
as: :linked,
|
||||
class_name: "Boards::Grid",
|
||||
inverse_of: :linked,
|
||||
dependent: :nullify
|
||||
|
||||
scopes :for_project,
|
||||
:not_completed,
|
||||
:order_by_date,
|
||||
:receiving_projects,
|
||||
:visible,
|
||||
:native_to_sprint_source
|
||||
|
||||
enum :status,
|
||||
{
|
||||
in_planning: "in_planning",
|
||||
active: "active",
|
||||
completed: "completed"
|
||||
},
|
||||
default: "in_planning",
|
||||
validate: true
|
||||
|
||||
validates :name, :project, presence: true
|
||||
validates :start_date, :finish_date, presence: true, if: :active?
|
||||
validates :finish_date,
|
||||
comparison: { greater_than_or_equal_to: :start_date },
|
||||
if: :date_range_set?
|
||||
|
||||
validates :status,
|
||||
uniqueness: {
|
||||
scope: :project_id,
|
||||
conditions: -> { active },
|
||||
message: :only_one_active_sprint_allowed
|
||||
},
|
||||
if: :active?
|
||||
|
||||
def date_range_set?
|
||||
start_date? && finish_date?
|
||||
end
|
||||
|
||||
def duration
|
||||
return nil unless date_range_set?
|
||||
|
||||
Day.working.from_range(from: start_date, to: finish_date).count
|
||||
end
|
||||
|
||||
def task_board_for(project)
|
||||
task_boards.find { it.project_id == project.id }
|
||||
end
|
||||
|
||||
def work_packages_for(project)
|
||||
work_packages.where(project:).order_by_position
|
||||
end
|
||||
|
||||
def owned_by?(project)
|
||||
project_id == project.id
|
||||
end
|
||||
|
||||
def shared_with?(project)
|
||||
self.class.for_project(project).exists?(id:) && !owned_by?(project)
|
||||
end
|
||||
|
||||
def visible_to?(project)
|
||||
self.class.for_project(project).exists?(id:)
|
||||
end
|
||||
|
||||
def to_s = name
|
||||
end
|
||||
end
|
||||
@@ -1,38 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# -- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
# ++
|
||||
|
||||
module Queries
|
||||
module Agile
|
||||
module Sprints
|
||||
# Alias to allow auto-discovery by ParamsToQueryService for the Agile::Sprint model.
|
||||
SprintQuery = ::Queries::Sprints::SprintQuery
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -29,9 +29,9 @@
|
||||
# ++
|
||||
|
||||
class Queries::Sprints::Filters::SprintFilter < Queries::Filters::Base
|
||||
self.model = ::Agile::Sprint
|
||||
self.model = ::Sprint
|
||||
|
||||
def human_name
|
||||
::Agile::Sprint.human_attribute_name(name)
|
||||
::Sprint.human_attribute_name(name)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -35,11 +35,11 @@ module Queries
|
||||
include ::Queries::UnpersistedQuery
|
||||
|
||||
def self.model
|
||||
::Agile::Sprint
|
||||
::Sprint
|
||||
end
|
||||
|
||||
def default_scope
|
||||
::Agile::Sprint.visible(User.current)
|
||||
::Sprint.visible(User.current)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -73,7 +73,7 @@ module Queries::WorkPackages::Filter
|
||||
|
||||
def sprints
|
||||
@sprints ||= begin
|
||||
scope = Agile::Sprint.visible
|
||||
scope = Sprint.visible
|
||||
project ? scope.for_project(project) : scope
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#-- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) the OpenProject GmbH
|
||||
@@ -26,5 +28,76 @@
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
class Sprint < Version
|
||||
class Sprint < ApplicationRecord
|
||||
include ::Scopes::Scoped
|
||||
|
||||
belongs_to :project
|
||||
has_many :work_packages, inverse_of: :sprint, dependent: :nullify
|
||||
has_many :task_boards,
|
||||
as: :linked,
|
||||
class_name: "Boards::Grid",
|
||||
inverse_of: :linked,
|
||||
dependent: :nullify
|
||||
|
||||
scopes :for_project,
|
||||
:not_completed,
|
||||
:order_by_date,
|
||||
:receiving_projects,
|
||||
:visible,
|
||||
:native_to_sprint_source
|
||||
|
||||
enum :status,
|
||||
{
|
||||
in_planning: "in_planning",
|
||||
active: "active",
|
||||
completed: "completed"
|
||||
},
|
||||
default: "in_planning",
|
||||
validate: true
|
||||
|
||||
validates :name, :project, presence: true
|
||||
validates :start_date, :finish_date, presence: true, if: :active?
|
||||
validates :finish_date,
|
||||
comparison: { greater_than_or_equal_to: :start_date },
|
||||
if: :date_range_set?
|
||||
|
||||
validates :status,
|
||||
uniqueness: {
|
||||
scope: :project_id,
|
||||
conditions: -> { active },
|
||||
message: :only_one_active_sprint_allowed
|
||||
},
|
||||
if: :active?
|
||||
|
||||
def date_range_set?
|
||||
start_date? && finish_date?
|
||||
end
|
||||
|
||||
def duration
|
||||
return nil unless date_range_set?
|
||||
|
||||
Day.working.from_range(from: start_date, to: finish_date).count
|
||||
end
|
||||
|
||||
def task_board_for(project)
|
||||
task_boards.find { it.project_id == project.id }
|
||||
end
|
||||
|
||||
def work_packages_for(project)
|
||||
work_packages.where(project:).order_by_position
|
||||
end
|
||||
|
||||
def owned_by?(project)
|
||||
project_id == project.id
|
||||
end
|
||||
|
||||
def shared_with?(project)
|
||||
self.class.for_project(project).exists?(id:) && !owned_by?(project)
|
||||
end
|
||||
|
||||
def visible_to?(project)
|
||||
self.class.for_project(project).exists?(id:)
|
||||
end
|
||||
|
||||
def to_s = name
|
||||
end
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
module Agile::Sprints::Scopes::ForProject
|
||||
module Sprints::Scopes::ForProject
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
class_methods do
|
||||
+1
-1
@@ -28,7 +28,7 @@
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
# ++
|
||||
|
||||
module Agile::Sprints::Scopes::NativeToSprintSource
|
||||
module Sprints::Scopes::NativeToSprintSource
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
class_methods do
|
||||
+1
-1
@@ -28,7 +28,7 @@
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
module Agile::Sprints::Scopes::NotCompleted
|
||||
module Sprints::Scopes::NotCompleted
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def not_completed # rubocop:disable Naming/PredicateMethod
|
||||
+1
-1
@@ -28,7 +28,7 @@
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
module Agile::Sprints::Scopes::OrderByDate
|
||||
module Sprints::Scopes::OrderByDate
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
class_methods do
|
||||
+1
-1
@@ -28,7 +28,7 @@
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
module Agile::Sprints::Scopes::ReceivingProjects
|
||||
module Sprints::Scopes::ReceivingProjects
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
class_methods do
|
||||
+1
-1
@@ -28,7 +28,7 @@
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
module Agile::Sprints::Scopes
|
||||
module Sprints::Scopes
|
||||
module Visible
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
@@ -30,6 +30,6 @@
|
||||
|
||||
class Sprints::CreateService < BaseServices::Create
|
||||
def instance_class
|
||||
Agile::Sprint
|
||||
Sprint
|
||||
end
|
||||
end
|
||||
|
||||
@@ -39,7 +39,7 @@ class Sprints::FinishService < BaseServices::BaseContracted
|
||||
def before_perform(service_call)
|
||||
case params[:unfinished_action]
|
||||
when "move_to_sprint"
|
||||
@target_sprint = Agile::Sprint.find_by(id: params[:move_to_sprint_id])
|
||||
@target_sprint = Sprint.find_by(id: params[:move_to_sprint_id])
|
||||
move_to_sprint(@target_sprint).each { |result| service_call.add_dependent!(result) }
|
||||
when "move_to_top_of_backlog"
|
||||
move_to_backlog(position: 1).each { |result| service_call.add_dependent!(result) }
|
||||
|
||||
@@ -52,7 +52,7 @@ class Sprints::StartService < BaseServices::BaseContracted
|
||||
end
|
||||
|
||||
def ensure_task_boards(service_call)
|
||||
projects = Agile::Sprint.receiving_projects(model)
|
||||
projects = Sprint.receiving_projects(model)
|
||||
|
||||
projects.each do |project|
|
||||
next if model.task_board_for(project).present?
|
||||
|
||||
@@ -30,6 +30,6 @@
|
||||
|
||||
class Sprints::UpdateService < BaseServices::Update
|
||||
def instance_class
|
||||
Agile::Sprint
|
||||
Sprint
|
||||
end
|
||||
end
|
||||
|
||||
@@ -45,13 +45,13 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
data-generic-drag-and-drop-target="scrollContainer">
|
||||
<%=
|
||||
render(Primer::Beta::Subhead.new(hide_border: true, pb: 0)) do |head|
|
||||
head.with_heading(tag: :h3, size: :medium, font_weight: :bold) { Agile::Sprint.human_model_name.pluralize }
|
||||
head.with_heading(tag: :h3, size: :medium, font_weight: :bold) { Sprint.human_model_name.pluralize }
|
||||
|
||||
if allow_sprint_creation?(@project)
|
||||
head.with_actions do
|
||||
render Primer::Beta::Button.new(
|
||||
tag: :a,
|
||||
label: Agile::Sprint.human_model_name,
|
||||
label: Sprint.human_model_name,
|
||||
href: new_dialog_project_backlogs_sprints_path(@project, all_backlogs_params),
|
||||
data: {
|
||||
controller: "async-dialog",
|
||||
@@ -59,7 +59,7 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
}
|
||||
) do |button|
|
||||
button.with_leading_visual_icon(icon: :plus)
|
||||
Agile::Sprint.human_model_name
|
||||
Sprint.human_model_name
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -70,7 +70,7 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
if allow_sprint_creation?(@project)
|
||||
subheader.with_action_button(
|
||||
leading_icon: :plus,
|
||||
label: Agile::Sprint.human_model_name,
|
||||
label: Sprint.human_model_name,
|
||||
tag: :a,
|
||||
href: new_dialog_project_backlogs_sprints_path(@project),
|
||||
data: {
|
||||
@@ -78,7 +78,7 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
test_selector: "op-sprints--new-sprint-button"
|
||||
}
|
||||
) do
|
||||
Agile::Sprint.human_model_name
|
||||
Sprint.human_model_name
|
||||
end
|
||||
end
|
||||
end %>
|
||||
|
||||
@@ -34,7 +34,9 @@ en:
|
||||
|
||||
activerecord:
|
||||
attributes:
|
||||
agile/sprint:
|
||||
project:
|
||||
sprint_sharing: "Sprint sharing"
|
||||
sprint:
|
||||
duration: "Duration"
|
||||
finish_date: "Finish date"
|
||||
goal: "Sprint goal"
|
||||
@@ -44,10 +46,6 @@ en:
|
||||
in_planning: "In planning"
|
||||
active: "Active"
|
||||
completed: "Completed"
|
||||
project:
|
||||
sprint_sharing: "Sprint sharing"
|
||||
sprint:
|
||||
duration: "Sprint duration"
|
||||
user_preference:
|
||||
backlogs_versions_default_fold_state: "Show sprints folded"
|
||||
work_package:
|
||||
@@ -69,6 +67,15 @@ en:
|
||||
sprint_sharing:
|
||||
share_all_projects_already_taken: "cannot be set because project \"%{name}\" is already sharing with all projects."
|
||||
share_all_projects_already_taken_anonymous: "cannot be set because another project is already sharing with all projects."
|
||||
sprint:
|
||||
attributes:
|
||||
base:
|
||||
unfinished_work_packages:
|
||||
one: "There is %{count} work package that was not completed in this sprint."
|
||||
other: "There are %{count} work packages that were not completed in this sprint."
|
||||
format: "%{message}"
|
||||
status:
|
||||
not_active: "is not active so it cannot be closed."
|
||||
work_package:
|
||||
backlog_bucket_xor_sprint: "cannot be assigned to both a sprint and a backlog bucket."
|
||||
attributes:
|
||||
@@ -82,17 +89,6 @@ en:
|
||||
sprint:
|
||||
not_shared_with_project: "is not shared with the project the work package is in."
|
||||
not_eligible_for_moving: "is not an active sprint in the project which holds the sprint the work package is moved out of."
|
||||
agile/sprint:
|
||||
attributes:
|
||||
base:
|
||||
unfinished_work_packages:
|
||||
one: "There is %{count} work package that was not completed in this sprint."
|
||||
other: "There are %{count} work packages that were not completed in this sprint."
|
||||
format: "%{message}"
|
||||
status:
|
||||
not_active: "is not active so it cannot be closed."
|
||||
sprint:
|
||||
cannot_end_before_it_starts: "Sprint cannot end before it starts."
|
||||
|
||||
models:
|
||||
sprint: "Sprint"
|
||||
|
||||
@@ -59,7 +59,7 @@ class MigrateVersionsToSprints < ActiveRecord::Migration[8.0]
|
||||
end
|
||||
|
||||
def create_sprint(version)
|
||||
Agile::Sprint.create!(
|
||||
Sprint.create!(
|
||||
name: version.name,
|
||||
project_id: version.project_id,
|
||||
status: version.status == "open" ? "in_planning" : "completed",
|
||||
|
||||
@@ -44,7 +44,7 @@ module API
|
||||
link :status do
|
||||
{
|
||||
href: "#{::API::V3::URN_PREFIX}sprints:status:#{represented.status}",
|
||||
title: I18n.t("activerecord.attributes.agile/sprint.statuses.#{represented.status}")
|
||||
title: I18n.t("activerecord.attributes.sprint.statuses.#{represented.status}")
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
@@ -34,15 +34,15 @@ module API
|
||||
class SprintsAPI < ::API::OpenProjectAPI
|
||||
resources :sprints do
|
||||
get &::API::V3::Utilities::Endpoints::Index
|
||||
.new(model: Agile::Sprint)
|
||||
.new(model: Sprint)
|
||||
.mount
|
||||
|
||||
route_param :id, type: Integer, desc: "Sprint ID" do
|
||||
after_validation do
|
||||
@sprint = Agile::Sprint.visible(current_user).find(params[:id])
|
||||
@sprint = Sprint.visible(current_user).find(params[:id])
|
||||
end
|
||||
|
||||
get &::API::V3::Utilities::Endpoints::Show.new(model: Agile::Sprint).mount
|
||||
get &::API::V3::Utilities::Endpoints::Show.new(model: Sprint).mount
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -39,7 +39,7 @@ module API
|
||||
|
||||
get &::API::V3::Utilities::Endpoints::Index
|
||||
.new(
|
||||
model: Agile::Sprint,
|
||||
model: Sprint,
|
||||
scope: -> { @project.assignable_sprints }
|
||||
)
|
||||
.mount
|
||||
|
||||
@@ -140,7 +140,6 @@ module OpenProject::Backlogs
|
||||
patch_with_namespace :WorkPackages, :UpdateContract
|
||||
patch_with_namespace :API, :V3, :WorkPackages, :EagerLoading, :Checksum
|
||||
patch_with_namespace :API, :V3, :WorkPackages, :Schema, :SpecificWorkPackageSchema
|
||||
patch_with_namespace :API, :V3, :Utilities, :ResourceLinkGenerator
|
||||
|
||||
config.to_prepare do
|
||||
next if Versions::BaseContract.include?(OpenProject::Backlogs::Patches::Versions::BaseContractPatch)
|
||||
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#-- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
module OpenProject::Backlogs::Patches::API::V3::Utilities::ResourceLinkGeneratorPatch
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
singleton_class.prepend(ClassMethods)
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
private
|
||||
|
||||
def determine_path_method(record)
|
||||
return :sprint if record.is_a?(Agile::Sprint)
|
||||
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -72,7 +72,7 @@ module OpenProject::Backlogs::Patches::BaseContractPatch
|
||||
|
||||
def sprint_shared_with_project
|
||||
return if model.sprint.nil? ||
|
||||
Agile::Sprint.for_project(model.project).exists?(id: model.sprint_id)
|
||||
Sprint.for_project(model.project).exists?(id: model.sprint_id)
|
||||
|
||||
errors.add :sprint, :not_shared_with_project
|
||||
end
|
||||
|
||||
@@ -35,7 +35,7 @@ module OpenProject::Backlogs::Patches::ProjectPatch
|
||||
included do
|
||||
has_and_belongs_to_many :done_statuses, join_table: :done_statuses_for_project, class_name: "::Status"
|
||||
has_many :backlog_buckets, class_name: "Agile::BacklogBucket", dependent: :destroy
|
||||
has_many :sprints, class_name: "Agile::Sprint", dependent: :destroy
|
||||
has_many :sprints, class_name: "Sprint", dependent: :destroy
|
||||
end
|
||||
|
||||
def backlogs_enabled?
|
||||
@@ -43,7 +43,7 @@ module OpenProject::Backlogs::Patches::ProjectPatch
|
||||
end
|
||||
|
||||
def assignable_sprints
|
||||
@assignable_sprints ||= Agile::Sprint.for_project(self).visible.not_completed
|
||||
@assignable_sprints ||= Sprint.for_project(self).visible.not_completed
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ module OpenProject::Backlogs::Patches::WorkPackagePatch
|
||||
if: -> { backlogs_enabled? }
|
||||
|
||||
belongs_to :backlog_bucket, class_name: "Agile::BacklogBucket", optional: true
|
||||
belongs_to :sprint, class_name: "Agile::Sprint", optional: true
|
||||
belongs_to :sprint, optional: true
|
||||
|
||||
include OpenProject::Backlogs::List
|
||||
end
|
||||
|
||||
@@ -98,9 +98,9 @@ module OpenProject::Backlogs
|
||||
|
||||
def visible_sprints
|
||||
if @project
|
||||
Agile::Sprint.for_project(@project)
|
||||
Sprint.for_project(@project)
|
||||
else
|
||||
Agile::Sprint
|
||||
Sprint
|
||||
end
|
||||
.visible
|
||||
end
|
||||
|
||||
@@ -87,8 +87,8 @@ RSpec.describe Backlogs::MoveToSprintDialogComponent, type: :component do
|
||||
end
|
||||
|
||||
context "when in_planning and active sprints exist" do
|
||||
let!(:planning_sprint) { create(:agile_sprint, project:, name: "Planning Sprint", status: "in_planning") }
|
||||
let!(:active_sprint) { create(:agile_sprint, project:, name: "Active Sprint", status: "active") }
|
||||
let!(:planning_sprint) { create(:sprint, project:, name: "Planning Sprint", status: "in_planning") }
|
||||
let!(:active_sprint) { create(:sprint, project:, name: "Active Sprint", status: "active") }
|
||||
|
||||
it "lists them as select options with sprint: prefix values" do
|
||||
render_component
|
||||
@@ -99,7 +99,7 @@ RSpec.describe Backlogs::MoveToSprintDialogComponent, type: :component do
|
||||
end
|
||||
|
||||
context "when a completed sprint exists" do
|
||||
let!(:completed_sprint) { create(:agile_sprint, project:, name: "Old Sprint", status: "completed") }
|
||||
let!(:completed_sprint) { create(:sprint, project:, name: "Old Sprint", status: "completed") }
|
||||
|
||||
it "does not list the completed sprint" do
|
||||
render_component
|
||||
@@ -109,7 +109,7 @@ RSpec.describe Backlogs::MoveToSprintDialogComponent, type: :component do
|
||||
end
|
||||
|
||||
context "when a sprint belongs to a different project" do
|
||||
let!(:other_sprint) { create(:agile_sprint, project: create(:project), name: "Other Sprint") }
|
||||
let!(:other_sprint) { create(:sprint, project: create(:project), name: "Other Sprint") }
|
||||
|
||||
it "does not list sprints from other projects" do
|
||||
render_component
|
||||
@@ -119,8 +119,8 @@ RSpec.describe Backlogs::MoveToSprintDialogComponent, type: :component do
|
||||
end
|
||||
|
||||
context "when the work package is already in a sprint" do
|
||||
let!(:current_sprint) { create(:agile_sprint, project:, name: "Current Sprint") }
|
||||
let!(:target_sprint) { create(:agile_sprint, project:, name: "Target Sprint") }
|
||||
let!(:current_sprint) { create(:sprint, project:, name: "Current Sprint") }
|
||||
let!(:target_sprint) { create(:sprint, project:, name: "Target Sprint") }
|
||||
let(:work_package) { create(:work_package, project:, sprint: current_sprint) }
|
||||
|
||||
it "excludes that sprint from the options" do
|
||||
|
||||
@@ -41,7 +41,7 @@ RSpec.describe Backlogs::SprintComponent, type: :component do
|
||||
current_user { user }
|
||||
|
||||
let(:project) { create(:project, types: [type_feature, type_task]) }
|
||||
let(:sprint) { create(:agile_sprint, project:, name: "Sprint 1", start_date: Date.yesterday, finish_date: Date.tomorrow) }
|
||||
let(:sprint) { create(:sprint, project:, name: "Sprint 1", start_date: Date.yesterday, finish_date: Date.tomorrow) }
|
||||
|
||||
def render_component
|
||||
render_inline(described_class.new(sprint:, project:, current_user: user))
|
||||
@@ -57,7 +57,7 @@ RSpec.describe Backlogs::SprintComponent, type: :component do
|
||||
priority: default_priority,
|
||||
story_points: 5,
|
||||
position: 1,
|
||||
sprint: sprint)
|
||||
sprint:)
|
||||
end
|
||||
let!(:story2) do
|
||||
create(:work_package,
|
||||
@@ -67,7 +67,7 @@ RSpec.describe Backlogs::SprintComponent, type: :component do
|
||||
priority: default_priority,
|
||||
story_points: 3,
|
||||
position: 2,
|
||||
sprint: sprint)
|
||||
sprint:)
|
||||
end
|
||||
|
||||
it "renders a Primer::Beta::BorderBox" do
|
||||
@@ -79,7 +79,7 @@ RSpec.describe Backlogs::SprintComponent, type: :component do
|
||||
it "has the sprint ID in the DOM id" do
|
||||
render_component
|
||||
|
||||
expect(page).to have_css(".Box#agile_sprint_#{sprint.id}")
|
||||
expect(page).to have_css(".Box#sprint_#{sprint.id}")
|
||||
end
|
||||
|
||||
it "renders SprintHeaderComponent in header" do
|
||||
@@ -91,7 +91,7 @@ RSpec.describe Backlogs::SprintComponent, type: :component do
|
||||
it "renders a stable id on the sprint header" do
|
||||
render_component
|
||||
|
||||
expect(page).to have_element(:div, class: "Box-header", id: /\Aagile_sprint_#{sprint.id}_header\z/)
|
||||
expect(page).to have_element(:div, class: "Box-header", id: /\Asprint_#{sprint.id}_header\z/)
|
||||
end
|
||||
|
||||
it "renders StoryComponent for each story" do
|
||||
|
||||
@@ -41,7 +41,7 @@ RSpec.describe Backlogs::SprintHeaderComponent, type: :component do
|
||||
let(:project) { create(:project, types: [type_feature, type_task]) }
|
||||
let(:start_date) { Date.new(2024, 1, 15) }
|
||||
let(:finish_date) { Date.new(2024, 1, 29) }
|
||||
let(:sprint) { create(:agile_sprint, project:, name: "Sprint 1", start_date:, finish_date:) }
|
||||
let(:sprint) { create(:sprint, project:, name: "Sprint 1", start_date:, finish_date:) }
|
||||
let(:state) { :show }
|
||||
let(:folded) { false }
|
||||
|
||||
@@ -121,7 +121,7 @@ RSpec.describe Backlogs::SprintHeaderComponent, type: :component do
|
||||
it "renders a stable id on the sprint menu trigger" do
|
||||
render_component
|
||||
|
||||
expect(page).to have_element(:button, id: /\Aagile_sprint_#{sprint.id}_menu-button\z/)
|
||||
expect(page).to have_element(:button, id: /\Asprint_#{sprint.id}_menu-button\z/)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -142,7 +142,7 @@ RSpec.describe Backlogs::SprintHeaderComponent, type: :component do
|
||||
end
|
||||
|
||||
context "when sprint has no dates" do
|
||||
let(:sprint) { build_stubbed(:agile_sprint, project:, name: "Sprint 1", start_date: nil, finish_date: nil) }
|
||||
let(:sprint) { build_stubbed(:sprint, project:, name: "Sprint 1", start_date: nil, finish_date: nil) }
|
||||
|
||||
it "renders without date range or calendar icon" do
|
||||
render_component
|
||||
@@ -170,7 +170,7 @@ RSpec.describe Backlogs::SprintHeaderComponent, type: :component do
|
||||
|
||||
context "when another sprint is already active" do
|
||||
let!(:active_sprint) do
|
||||
create(:agile_sprint, project:, name: "Active Sprint", status: "active",
|
||||
create(:sprint, project:, name: "Active Sprint", status: "active",
|
||||
start_date: Date.yesterday, finish_date: Date.tomorrow)
|
||||
end
|
||||
|
||||
@@ -207,7 +207,7 @@ RSpec.describe Backlogs::SprintHeaderComponent, type: :component do
|
||||
|
||||
context "when the sprint is active and the user can finish it" do
|
||||
let(:sprint) do
|
||||
create(:agile_sprint, project:, name: "Sprint 1", status: "active",
|
||||
create(:sprint, project:, name: "Sprint 1", status: "active",
|
||||
start_date:, finish_date:)
|
||||
end
|
||||
|
||||
@@ -227,7 +227,7 @@ RSpec.describe Backlogs::SprintHeaderComponent, type: :component do
|
||||
|
||||
context "when the sprint is completed" do
|
||||
let(:sprint) do
|
||||
create(:agile_sprint, project:, name: "Sprint 1", status: "completed",
|
||||
create(:sprint, project:, name: "Sprint 1", status: "completed",
|
||||
start_date:, finish_date:)
|
||||
end
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ RSpec.describe Backlogs::SprintMenuComponent, type: :component do
|
||||
shared_let(:type_task) { create(:type_task) }
|
||||
|
||||
let(:project) { create(:project, types: [type_feature, type_task]) }
|
||||
let(:sprint) { create(:agile_sprint, project:, name: "Sprint 1", start_date: Date.yesterday, finish_date: Date.tomorrow) }
|
||||
let(:sprint) { create(:sprint, project:, name: "Sprint 1", start_date: Date.yesterday, finish_date: Date.tomorrow) }
|
||||
let(:user) { create(:user) }
|
||||
let(:permissions) { [] }
|
||||
|
||||
@@ -106,7 +106,7 @@ RSpec.describe Backlogs::SprintMenuComponent, type: :component do
|
||||
|
||||
context "when the sprint is active and has a task board" do
|
||||
let(:sprint) do
|
||||
create(:agile_sprint,
|
||||
create(:sprint,
|
||||
project:,
|
||||
name: "Sprint 1",
|
||||
start_date: Date.yesterday,
|
||||
@@ -133,7 +133,7 @@ RSpec.describe Backlogs::SprintMenuComponent, type: :component do
|
||||
|
||||
context "when the sprint is completed and has a task board" do
|
||||
let(:sprint) do
|
||||
create(:agile_sprint,
|
||||
create(:sprint,
|
||||
project:,
|
||||
name: "Sprint 1",
|
||||
start_date: Date.yesterday,
|
||||
@@ -153,7 +153,7 @@ RSpec.describe Backlogs::SprintMenuComponent, type: :component do
|
||||
let(:source_project) { create(:project, sprint_sharing: "share_all_projects", types: [type_feature, type_task]) }
|
||||
let(:project) { create(:project, sprint_sharing: "receive_shared", types: [type_feature, type_task]) }
|
||||
let(:sprint) do
|
||||
create(:agile_sprint,
|
||||
create(:sprint,
|
||||
project: source_project,
|
||||
name: "Shared Sprint",
|
||||
start_date: Date.yesterday,
|
||||
|
||||
@@ -34,7 +34,7 @@ RSpec.describe Backlogs::SprintPageHeaderComponent, type: :component do
|
||||
let(:project) { create(:project, name: "Test Project") }
|
||||
let(:start_date) { Date.new(2024, 1, 15) }
|
||||
let(:finish_date) { Date.new(2024, 1, 29) }
|
||||
let(:sprint) { create(:agile_sprint, project:, name: "Sprint 1", start_date:, finish_date:) }
|
||||
let(:sprint) { create(:sprint, project:, name: "Sprint 1", start_date:, finish_date:) }
|
||||
|
||||
def render_component
|
||||
render_inline(described_class.new(sprint:, project:))
|
||||
@@ -89,7 +89,7 @@ RSpec.describe Backlogs::SprintPageHeaderComponent, type: :component do
|
||||
|
||||
describe "date handling" do
|
||||
context "when sprint has only start_date" do
|
||||
let(:sprint) { create(:agile_sprint, project:, name: "Sprint 1", start_date:, finish_date: nil) }
|
||||
let(:sprint) { create(:sprint, project:, name: "Sprint 1", start_date:, finish_date: nil) }
|
||||
|
||||
it "renders only start date" do
|
||||
render_component
|
||||
@@ -100,7 +100,7 @@ RSpec.describe Backlogs::SprintPageHeaderComponent, type: :component do
|
||||
end
|
||||
|
||||
context "when sprint has only finish_date" do
|
||||
let(:sprint) { create(:agile_sprint, project:, name: "Sprint 1", start_date: nil, finish_date:) }
|
||||
let(:sprint) { create(:sprint, project:, name: "Sprint 1", start_date: nil, finish_date:) }
|
||||
|
||||
it "renders only finish date" do
|
||||
render_component
|
||||
@@ -111,7 +111,7 @@ RSpec.describe Backlogs::SprintPageHeaderComponent, type: :component do
|
||||
end
|
||||
|
||||
context "when sprint has no dates" do
|
||||
let(:sprint) { create(:agile_sprint, project:, name: "Sprint 1", start_date: nil, finish_date: nil) }
|
||||
let(:sprint) { create(:sprint, project:, name: "Sprint 1", start_date: nil, finish_date: nil) }
|
||||
|
||||
it "renders no time elements" do
|
||||
render_component
|
||||
|
||||
@@ -39,7 +39,7 @@ RSpec.describe Backlogs::StoryComponent, type: :component do
|
||||
current_user { user }
|
||||
|
||||
let(:project) { create(:project, types: [type_feature, type_task]) }
|
||||
let(:sprint) { create(:agile_sprint, project:, name: "Sprint 1", start_date: Date.yesterday, finish_date: Date.tomorrow) }
|
||||
let(:sprint) { create(:sprint, project:, name: "Sprint 1", start_date: Date.yesterday, finish_date: Date.tomorrow) }
|
||||
let(:story_points) { 5 }
|
||||
let(:story) do
|
||||
create(:work_package,
|
||||
@@ -50,7 +50,7 @@ RSpec.describe Backlogs::StoryComponent, type: :component do
|
||||
priority: default_priority,
|
||||
story_points:,
|
||||
position: 1,
|
||||
sprint: sprint)
|
||||
sprint:)
|
||||
end
|
||||
let(:permissions) { %i[manage_sprint_items] }
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ RSpec.describe Backlogs::StoryMenuListComponent, type: :component do
|
||||
current_user { user }
|
||||
|
||||
let(:project) { create(:project, types: [type_feature, type_task]) }
|
||||
let(:sprint) { create(:agile_sprint, project:, name: "Sprint 1", start_date: Date.yesterday, finish_date: Date.tomorrow) }
|
||||
let(:sprint) { create(:sprint, project:, name: "Sprint 1", start_date: Date.yesterday, finish_date: Date.tomorrow) }
|
||||
let(:position) { 2 }
|
||||
let(:max_position) { 3 }
|
||||
let(:story) do
|
||||
@@ -51,7 +51,7 @@ RSpec.describe Backlogs::StoryMenuListComponent, type: :component do
|
||||
priority: default_priority,
|
||||
story_points: 5,
|
||||
position:,
|
||||
sprint: sprint)
|
||||
sprint:)
|
||||
end
|
||||
|
||||
def render_component(position: 2, max_position: 3, open_sprints_exist: true)
|
||||
|
||||
@@ -35,7 +35,7 @@ RSpec.describe Sprints::CreateContract do
|
||||
include_context "as sprint contract"
|
||||
|
||||
let(:sprint) do
|
||||
Agile::Sprint.new(name: sprint_name,
|
||||
Sprint.new(name: sprint_name,
|
||||
project: sprint_project,
|
||||
start_date: sprint_start_date,
|
||||
finish_date: sprint_finish_date,
|
||||
|
||||
@@ -36,7 +36,7 @@ RSpec.describe Sprints::FinishContract do
|
||||
|
||||
let(:project) { build_stubbed(:project) }
|
||||
let(:user) { build_stubbed(:user) }
|
||||
let(:sprint) { build_stubbed(:agile_sprint, project:, status: sprint_status) }
|
||||
let(:sprint) { build_stubbed(:sprint, project:, status: sprint_status) }
|
||||
let(:sprint_status) { "active" }
|
||||
let(:unfinished_count) { 0 }
|
||||
let(:permissions) { [:start_complete_sprint] }
|
||||
|
||||
@@ -34,7 +34,7 @@ RSpec.describe Sprints::StartContract do
|
||||
let(:project) { create(:project) }
|
||||
let(:user) { create(:user) }
|
||||
let(:sprint) do
|
||||
create(:agile_sprint,
|
||||
create(:sprint,
|
||||
project:,
|
||||
status: sprint_status)
|
||||
end
|
||||
@@ -84,7 +84,7 @@ RSpec.describe Sprints::StartContract do
|
||||
end
|
||||
|
||||
context "when the sprint has no start date" do
|
||||
let(:sprint) { create(:agile_sprint, project:, status: sprint_status, start_date: nil) }
|
||||
let(:sprint) { create(:sprint, project:, status: sprint_status, start_date: nil) }
|
||||
|
||||
it "is invalid" do
|
||||
expect(contract.validate).to be(false)
|
||||
@@ -93,7 +93,7 @@ RSpec.describe Sprints::StartContract do
|
||||
end
|
||||
|
||||
context "when the sprint has no finish date" do
|
||||
let(:sprint) { create(:agile_sprint, project:, status: sprint_status, finish_date: nil) }
|
||||
let(:sprint) { create(:sprint, project:, status: sprint_status, finish_date: nil) }
|
||||
|
||||
it "is invalid" do
|
||||
expect(contract.validate).to be(false)
|
||||
@@ -103,7 +103,7 @@ RSpec.describe Sprints::StartContract do
|
||||
|
||||
context "when another active sprint exists in the project" do
|
||||
before do
|
||||
create(:agile_sprint,
|
||||
create(:sprint,
|
||||
project:,
|
||||
status: "active")
|
||||
end
|
||||
@@ -116,7 +116,7 @@ RSpec.describe Sprints::StartContract do
|
||||
|
||||
context "when an active sprint exists in a different project" do
|
||||
before do
|
||||
create(:agile_sprint,
|
||||
create(:sprint,
|
||||
project: create(:project),
|
||||
status: "active")
|
||||
end
|
||||
|
||||
@@ -35,7 +35,7 @@ RSpec.describe Sprints::UpdateContract do
|
||||
include_context "as sprint contract"
|
||||
|
||||
let(:sprint) do
|
||||
build_stubbed(:agile_sprint,
|
||||
build_stubbed(:sprint,
|
||||
name: sprint_name,
|
||||
project: sprint_project,
|
||||
start_date: sprint_start_date,
|
||||
|
||||
@@ -37,7 +37,7 @@ RSpec.shared_examples "work package contract with backlogs extensions" do
|
||||
let(:work_package_priority) { build_stubbed(:priority) }
|
||||
let(:work_package_author) { build_stubbed(:user) }
|
||||
let(:work_package_story_points) { 5 }
|
||||
let(:work_package_sprint) { build_stubbed(:agile_sprint) }
|
||||
let(:work_package_sprint) { build_stubbed(:sprint) }
|
||||
let(:work_package_position) { 5 }
|
||||
let(:shared_sprints) { [work_package_sprint] }
|
||||
let(:backlogs_enabled) { true }
|
||||
@@ -61,7 +61,7 @@ RSpec.shared_examples "work package contract with backlogs extensions" do
|
||||
before do
|
||||
shared_sprints_scope = instance_double(ActiveRecord::Relation)
|
||||
|
||||
allow(Agile::Sprint)
|
||||
allow(Sprint)
|
||||
.to receive(:for_project)
|
||||
.with(work_package.project)
|
||||
.and_return(shared_sprints_scope)
|
||||
@@ -126,12 +126,12 @@ RSpec.shared_examples "work package contract with backlogs extensions" do
|
||||
end
|
||||
|
||||
context "when sprint is completed (shared with project but not assignable)" do
|
||||
let(:completed_sprint) { build_stubbed(:agile_sprint, status: :completed) }
|
||||
let(:completed_sprint) { build_stubbed(:sprint, status: :completed) }
|
||||
let(:work_package_sprint) { completed_sprint }
|
||||
|
||||
before do
|
||||
# The sprint is still shared with the project (the outer before mock makes
|
||||
# `Agile::Sprint.for_project.exists?` return true), so `sprint_shared_with_project`
|
||||
# `Sprint.for_project.exists?` return true), so `sprint_shared_with_project`
|
||||
# passes. We stub assignable_sprints to exclude it, simulating the `.not_completed`
|
||||
# scope, so only `validate_sprint_is_assignable` fires.
|
||||
allow(work_package_project).to receive(:assignable_sprints).and_return([])
|
||||
|
||||
@@ -36,7 +36,7 @@ RSpec.describe Backlogs::BacklogController do
|
||||
shared_let(:user) { create(:admin) }
|
||||
shared_let(:project) { create(:project) }
|
||||
shared_let(:status) { create(:status, name: "status 1", is_default: true) }
|
||||
shared_let(:sprint) { create(:agile_sprint, project:) }
|
||||
shared_let(:sprint) { create(:sprint, project:) }
|
||||
shared_let(:backlog_bucket) { create(:backlog_bucket, project:) }
|
||||
shared_let(:work_package) { create(:work_package, project:, status:) }
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ RSpec.describe Backlogs::BurndownChartController do
|
||||
shared_let(:user) { create(:admin) }
|
||||
shared_let(:project) { create(:project) }
|
||||
shared_let(:status) { create(:status, name: "status 1", is_default: true) }
|
||||
shared_let(:sprint) { create(:agile_sprint, project:) }
|
||||
shared_let(:sprint) { create(:sprint, project:) }
|
||||
|
||||
current_user { user }
|
||||
|
||||
|
||||
@@ -140,8 +140,8 @@ RSpec.describe Backlogs::InboxController do
|
||||
end
|
||||
|
||||
describe "PUT #move" do
|
||||
let(:agile_sprint) { create(:agile_sprint, name: "Sprint 1", project:) }
|
||||
let(:target_id) { "sprint:#{agile_sprint.id}" }
|
||||
let(:sprint) { create(:sprint, name: "Sprint 1", project:) }
|
||||
let(:target_id) { "sprint:#{sprint.id}" }
|
||||
let(:prev_id) { 1 }
|
||||
|
||||
subject do
|
||||
@@ -155,13 +155,13 @@ RSpec.describe Backlogs::InboxController do
|
||||
format: :turbo_stream
|
||||
end
|
||||
|
||||
context "when moving to an Agile::Sprint" do
|
||||
context "when moving to an Sprint" do
|
||||
it "replaces both the inbox and target sprint components", :aggregate_failures do
|
||||
expect(response).to be_successful
|
||||
expect(response).to have_turbo_stream action: "replace",
|
||||
target: "backlogs-backlogs-component-#{project.id}"
|
||||
expect(response).to have_turbo_stream action: "replace",
|
||||
target: "backlogs-sprint-component-#{agile_sprint.id}"
|
||||
target: "backlogs-sprint-component-#{sprint.id}"
|
||||
|
||||
# Flash message is omitted here on purpose (#73600)
|
||||
expect(response).not_to have_turbo_stream action: "flash", target: "op-primer-flash-component"
|
||||
@@ -190,7 +190,7 @@ RSpec.describe Backlogs::InboxController do
|
||||
end
|
||||
|
||||
context "when no prev_id is provided" do
|
||||
let!(:work_packages) { create_list(:work_package, 5, project:, sprint: agile_sprint) }
|
||||
let!(:work_packages) { create_list(:work_package, 5, project:, sprint:) }
|
||||
let(:prev_id) { nil }
|
||||
|
||||
it "places the work package at the top of the sprint" do
|
||||
@@ -410,7 +410,7 @@ RSpec.describe Backlogs::InboxController do
|
||||
end
|
||||
|
||||
describe "GET #move_to_sprint_dialog" do
|
||||
let!(:sprint) { create(:agile_sprint, name: "Sprint 1", project:) }
|
||||
let!(:sprint) { create(:sprint, name: "Sprint 1", project:) }
|
||||
|
||||
subject do
|
||||
get :move_to_sprint_dialog,
|
||||
|
||||
@@ -67,7 +67,7 @@ RSpec.describe Backlogs::SprintsController do
|
||||
end
|
||||
|
||||
describe "GET #edit_dialog" do
|
||||
let!(:sprint) { create(:agile_sprint, project:) }
|
||||
let!(:sprint) { create(:sprint, project:) }
|
||||
|
||||
it "responds with success", :aggregate_failures do
|
||||
get :edit_dialog, params: { project_id: project.id, sprint_id: sprint.id }, format: :turbo_stream
|
||||
@@ -134,7 +134,7 @@ RSpec.describe Backlogs::SprintsController do
|
||||
end
|
||||
|
||||
describe "PUT #update" do
|
||||
let!(:sprint) { create(:agile_sprint, name: "Original sprint name", project:) }
|
||||
let!(:sprint) { create(:sprint, name: "Original sprint name", project:) }
|
||||
|
||||
let(:params) do
|
||||
{
|
||||
@@ -171,7 +171,7 @@ RSpec.describe Backlogs::SprintsController do
|
||||
end
|
||||
|
||||
describe "POST #start" do
|
||||
let!(:sprint) { create(:agile_sprint, project:) }
|
||||
let!(:sprint) { create(:sprint, project:) }
|
||||
let(:service_result) { ServiceResult.success(result: sprint.tap { it.status = "active" }) }
|
||||
let(:service) { instance_double(Sprints::StartService, call: service_result) }
|
||||
let(:request_params) { { project_id: project.id, sprint_id: sprint.id } }
|
||||
@@ -186,7 +186,7 @@ RSpec.describe Backlogs::SprintsController do
|
||||
context "when the sprint is rendered in a receiving project" do
|
||||
let(:source_project) { create(:project, sprint_sharing: "share_all_projects") }
|
||||
let(:project) { create(:project, sprint_sharing: "receive_shared") }
|
||||
let!(:sprint) { create(:agile_sprint, project: source_project) }
|
||||
let!(:sprint) { create(:sprint, project: source_project) }
|
||||
let(:source_permissions) { %i[view_sprints start_complete_sprint] }
|
||||
let!(:board) { create(:board_grid_with_query, project:, linked: sprint) }
|
||||
|
||||
@@ -294,7 +294,7 @@ RSpec.describe Backlogs::SprintsController do
|
||||
end
|
||||
|
||||
context "when another sprint is already active" do
|
||||
let!(:active_sprint) { create(:agile_sprint, project:, status: "active") }
|
||||
let!(:active_sprint) { create(:sprint, project:, status: "active") }
|
||||
let(:service_result) do
|
||||
ServiceResult.failure(
|
||||
result: sprint,
|
||||
@@ -323,7 +323,7 @@ RSpec.describe Backlogs::SprintsController do
|
||||
end
|
||||
|
||||
context "when the sprint is already active" do
|
||||
let!(:sprint) { create(:agile_sprint, project:, status: "active") }
|
||||
let!(:sprint) { create(:sprint, project:, status: "active") }
|
||||
let(:service_result) { ServiceResult.failure }
|
||||
|
||||
it "redirects back with the default start failure message", :aggregate_failures do
|
||||
@@ -337,7 +337,7 @@ RSpec.describe Backlogs::SprintsController do
|
||||
end
|
||||
|
||||
describe "POST #finish" do
|
||||
let!(:sprint) { create(:agile_sprint, project:, status: "active") }
|
||||
let!(:sprint) { create(:sprint, project:, status: "active") }
|
||||
let(:request_params) { { project_id: project.id, sprint_id: sprint.id } }
|
||||
let(:service_result) do
|
||||
ServiceResult.success(
|
||||
@@ -356,7 +356,7 @@ RSpec.describe Backlogs::SprintsController do
|
||||
context "when the sprint is rendered in a receiving project" do
|
||||
let(:source_project) { create(:project, sprint_sharing: "share_all_projects") }
|
||||
let(:project) { create(:project, sprint_sharing: "receive_shared") }
|
||||
let!(:sprint) { create(:agile_sprint, project: source_project, status: "active") }
|
||||
let!(:sprint) { create(:sprint, project: source_project, status: "active") }
|
||||
let(:source_permissions) { %i[view_sprints start_complete_sprint] }
|
||||
|
||||
before do
|
||||
@@ -441,7 +441,7 @@ RSpec.describe Backlogs::SprintsController do
|
||||
end
|
||||
|
||||
context "when the sprint is already completed" do
|
||||
let!(:sprint) { create(:agile_sprint, project:, status: "completed") }
|
||||
let!(:sprint) { create(:sprint, project:, status: "completed") }
|
||||
let(:service_result) { ServiceResult.failure }
|
||||
|
||||
it "redirects back with the default finish failure message", :aggregate_failures do
|
||||
@@ -511,7 +511,7 @@ RSpec.describe Backlogs::SprintsController do
|
||||
end
|
||||
|
||||
context "when refreshing the form in edit mode by passing a sprint id" do
|
||||
let!(:sprint) { create(:agile_sprint, project:) }
|
||||
let!(:sprint) { create(:sprint, project:) }
|
||||
let(:params) do
|
||||
{
|
||||
project_id: project.id,
|
||||
|
||||
@@ -42,7 +42,7 @@ RSpec.describe Backlogs::TaskboardController do
|
||||
current_user { user }
|
||||
|
||||
describe "GET show" do
|
||||
let(:sprint) { create(:agile_sprint, project:) }
|
||||
let(:sprint) { create(:sprint, project:) }
|
||||
|
||||
context "when the board exists" do
|
||||
let!(:other_project) { create(:project) }
|
||||
@@ -91,7 +91,7 @@ RSpec.describe Backlogs::TaskboardController do
|
||||
member_with_permissions: { user => permissions })
|
||||
end
|
||||
let(:permissions) { %i[view_sprints view_work_packages] }
|
||||
let(:sprint) { create(:agile_sprint, project: source_project) }
|
||||
let(:sprint) { create(:sprint, project: source_project) }
|
||||
|
||||
before do
|
||||
create(:board_grid_with_query, project: source_project, linked: sprint)
|
||||
|
||||
@@ -39,8 +39,8 @@ RSpec.describe Backlogs::WorkPackagesController do
|
||||
let(:user) { create(:admin) }
|
||||
let(:project) { create(:project) }
|
||||
let(:status) { create(:status, name: "status 1", is_default: true) }
|
||||
let(:agile_sprint) { create(:agile_sprint, name: "Agile Sprint 1", project:) }
|
||||
let(:story) { create(:work_package, status:, sprint: agile_sprint, project:) }
|
||||
let(:sprint) { create(:sprint, name: "Agile Sprint 1", project:) }
|
||||
let(:story) { create(:work_package, status:, sprint:, project:) }
|
||||
|
||||
describe "load_story" do
|
||||
subject do
|
||||
@@ -52,7 +52,7 @@ RSpec.describe Backlogs::WorkPackagesController do
|
||||
let(:load_story_id) { story.id }
|
||||
|
||||
context "when the work package is in the requested sprint" do
|
||||
let(:requested_sprint) { agile_sprint }
|
||||
let(:requested_sprint) { sprint }
|
||||
|
||||
it "assigns the visible work package", :aggregate_failures do
|
||||
subject
|
||||
@@ -63,7 +63,7 @@ RSpec.describe Backlogs::WorkPackagesController do
|
||||
end
|
||||
|
||||
context "when the work package is not in the requested sprint" do
|
||||
let(:requested_sprint) { create(:agile_sprint, name: "Other Sprint load_story", project:) }
|
||||
let(:requested_sprint) { create(:sprint, name: "Other Sprint load_story", project:) }
|
||||
|
||||
it { is_expected.to have_http_status :not_found }
|
||||
end
|
||||
@@ -71,15 +71,15 @@ RSpec.describe Backlogs::WorkPackagesController do
|
||||
|
||||
describe "POST #reorder" do
|
||||
it "responds with success", :aggregate_failures do
|
||||
post :reorder, params: { project_id: project.id, sprint_id: agile_sprint.id, id: story.id, direction: "highest" },
|
||||
post :reorder, params: { project_id: project.id, sprint_id: sprint.id, id: story.id, direction: "highest" },
|
||||
format: :turbo_stream
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response).to have_http_status :ok
|
||||
expect(response).to have_turbo_stream action: "replace", target: "backlogs-sprint-component-#{agile_sprint.id}"
|
||||
assert_select %(turbo-stream[action="replace"][target="backlogs-sprint-component-#{agile_sprint.id}"][method="morph"])
|
||||
expect(response).to have_turbo_stream action: "replace", target: "backlogs-sprint-component-#{sprint.id}"
|
||||
assert_select %(turbo-stream[action="replace"][target="backlogs-sprint-component-#{sprint.id}"][method="morph"])
|
||||
expect(assigns(:project)).to eq(project)
|
||||
expect(assigns(:sprint)).to eq(agile_sprint)
|
||||
expect(assigns(:sprint)).to eq(sprint)
|
||||
expect(assigns(:story)).to eq(story)
|
||||
end
|
||||
|
||||
@@ -95,42 +95,42 @@ RSpec.describe Backlogs::WorkPackagesController do
|
||||
end
|
||||
|
||||
it "renders an error flash with 422", :aggregate_failures do
|
||||
post :reorder, params: { project_id: project.id, sprint_id: agile_sprint.id, id: story.id, direction: "highest" },
|
||||
post :reorder, params: { project_id: project.id, sprint_id: sprint.id, id: story.id, direction: "highest" },
|
||||
format: :turbo_stream
|
||||
|
||||
expect(response).to have_http_status :unprocessable_entity
|
||||
expect(response).to have_turbo_stream action: "flash", target: "op-primer-flash-component"
|
||||
expect(response).not_to have_turbo_stream action: "replace", target: "backlogs-sprint-component-#{agile_sprint.id}"
|
||||
expect(response).not_to have_turbo_stream action: "replace", target: "backlogs-sprint-component-#{sprint.id}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "PUT #move" do
|
||||
let(:story_in_agile_sprint) { create(:work_package, status:, sprint: agile_sprint, project:) }
|
||||
let(:story_in_sprint) { create(:work_package, status:, sprint:, project:) }
|
||||
|
||||
context "with another Agile::Sprint as target" do
|
||||
let(:other_agile_sprint) { create(:agile_sprint, name: "Agile Sprint 2", project:) }
|
||||
context "with another Sprint as target" do
|
||||
let(:other_sprint) { create(:sprint, name: "Agile Sprint 2", project:) }
|
||||
|
||||
it "responds with success and moves story to another Agile::Sprint", :aggregate_failures do
|
||||
it "responds with success and moves story to another Sprint", :aggregate_failures do
|
||||
put :move, params: {
|
||||
project_id: project.id,
|
||||
sprint_id: agile_sprint.id,
|
||||
id: story_in_agile_sprint.id,
|
||||
target_id: "sprint:#{other_agile_sprint.id}",
|
||||
sprint_id: sprint.id,
|
||||
id: story_in_sprint.id,
|
||||
target_id: "sprint:#{other_sprint.id}",
|
||||
prev_id: nil
|
||||
},
|
||||
format: :turbo_stream
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response).to have_http_status :ok
|
||||
expect(response).to have_turbo_stream action: "replace", target: "backlogs-sprint-component-#{agile_sprint.id}"
|
||||
expect(response).to have_turbo_stream action: "replace", target: "backlogs-sprint-component-#{other_agile_sprint.id}"
|
||||
assert_select %(turbo-stream[action="replace"][target="backlogs-sprint-component-#{agile_sprint.id}"])
|
||||
assert_select %(turbo-stream[action="replace"][target="backlogs-sprint-component-#{other_agile_sprint.id}"])
|
||||
expect(response).to have_turbo_stream action: "replace", target: "backlogs-sprint-component-#{sprint.id}"
|
||||
expect(response).to have_turbo_stream action: "replace", target: "backlogs-sprint-component-#{other_sprint.id}"
|
||||
assert_select %(turbo-stream[action="replace"][target="backlogs-sprint-component-#{sprint.id}"])
|
||||
assert_select %(turbo-stream[action="replace"][target="backlogs-sprint-component-#{other_sprint.id}"])
|
||||
expect(response).to have_turbo_stream action: "flash", target: "op-primer-flash-component"
|
||||
expect(assigns(:project)).to eq(project)
|
||||
expect(assigns(:sprint)).to eq(agile_sprint)
|
||||
expect(assigns(:story)).to eq(story_in_agile_sprint)
|
||||
expect(assigns(:sprint)).to eq(sprint)
|
||||
expect(assigns(:story)).to eq(story_in_sprint)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -140,8 +140,8 @@ RSpec.describe Backlogs::WorkPackagesController do
|
||||
it "responds with success and moves story to Inbox at the given position", :aggregate_failures do
|
||||
put :move, params: {
|
||||
project_id: project.id,
|
||||
sprint_id: agile_sprint.id,
|
||||
id: story_in_agile_sprint.id,
|
||||
sprint_id: sprint.id,
|
||||
id: story_in_sprint.id,
|
||||
target_id: "inbox",
|
||||
prev_id: existing_inbox_item.id
|
||||
},
|
||||
@@ -149,16 +149,16 @@ RSpec.describe Backlogs::WorkPackagesController do
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response).to have_http_status :ok
|
||||
expect(response).to have_turbo_stream action: "replace", target: "backlogs-sprint-component-#{agile_sprint.id}"
|
||||
expect(response).to have_turbo_stream action: "replace", target: "backlogs-sprint-component-#{sprint.id}"
|
||||
expect(response).to have_turbo_stream action: "replace", target: "backlogs-backlogs-component-#{project.id}"
|
||||
assert_select %(turbo-stream[action="replace"][target="backlogs-sprint-component-#{agile_sprint.id}"])
|
||||
assert_select %(turbo-stream[action="replace"][target="backlogs-sprint-component-#{sprint.id}"])
|
||||
assert_select %(turbo-stream[action="replace"][target="backlogs-backlogs-component-#{project.id}"][method="morph"])
|
||||
expect(response).to have_turbo_stream action: "flash", target: "op-primer-flash-component"
|
||||
expect(assigns(:project)).to eq(project)
|
||||
expect(assigns(:sprint)).to eq(agile_sprint)
|
||||
expect(assigns(:story)).to eq(story_in_agile_sprint)
|
||||
expect(story_in_agile_sprint.reload.sprint).to be_nil
|
||||
expect(story_in_agile_sprint.reload.position).to eq(2)
|
||||
expect(assigns(:sprint)).to eq(sprint)
|
||||
expect(assigns(:story)).to eq(story_in_sprint)
|
||||
expect(story_in_sprint.reload.sprint).to be_nil
|
||||
expect(story_in_sprint.reload.position).to eq(2)
|
||||
end
|
||||
|
||||
context "when all=1 with an inbox over the pagination threshold" do
|
||||
@@ -170,8 +170,8 @@ RSpec.describe Backlogs::WorkPackagesController do
|
||||
it "replaces the inbox without a show-more row in the stream" do
|
||||
put :move, params: {
|
||||
project_id: project.id,
|
||||
sprint_id: agile_sprint.id,
|
||||
id: story_in_agile_sprint.id,
|
||||
sprint_id: sprint.id,
|
||||
id: story_in_sprint.id,
|
||||
target_id: "inbox",
|
||||
prev_id: existing_inbox_item.id,
|
||||
all: "1"
|
||||
@@ -185,7 +185,7 @@ RSpec.describe Backlogs::WorkPackagesController do
|
||||
end
|
||||
|
||||
context "when service call fails" do
|
||||
let(:other_agile_sprint) { create(:agile_sprint, name: "Agile Sprint 2", project:) }
|
||||
let(:other_sprint) { create(:sprint, name: "Agile Sprint 2", project:) }
|
||||
let(:service_result) { ServiceResult.failure(message: "Something went wrong") }
|
||||
|
||||
before do
|
||||
@@ -199,23 +199,23 @@ RSpec.describe Backlogs::WorkPackagesController do
|
||||
it "renders an error flash with 422", :aggregate_failures do
|
||||
put :move, params: {
|
||||
project_id: project.id,
|
||||
sprint_id: agile_sprint.id,
|
||||
id: story_in_agile_sprint.id,
|
||||
target_id: "sprint:#{other_agile_sprint.id}",
|
||||
sprint_id: sprint.id,
|
||||
id: story_in_sprint.id,
|
||||
target_id: "sprint:#{other_sprint.id}",
|
||||
position: 1
|
||||
},
|
||||
format: :turbo_stream
|
||||
|
||||
expect(response).to have_http_status :unprocessable_entity
|
||||
expect(response).to have_turbo_stream action: "flash", target: "op-primer-flash-component"
|
||||
expect(response).not_to have_turbo_stream action: "replace", target: "backlogs-sprint-component-#{agile_sprint.id}"
|
||||
expect(response).not_to have_turbo_stream action: "replace", target: "backlogs-sprint-component-#{sprint.id}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET #menu" do
|
||||
subject do
|
||||
get :menu, params: { project_id: project.id, sprint_id: agile_sprint.id, id: story.id }, format: :html
|
||||
get :menu, params: { project_id: project.id, sprint_id: sprint.id, id: story.id }, format: :html
|
||||
end
|
||||
|
||||
it "returns deferred action menu list HTML", :aggregate_failures do
|
||||
@@ -227,7 +227,7 @@ RSpec.describe Backlogs::WorkPackagesController do
|
||||
context "when all=1 is in params" do
|
||||
subject do
|
||||
get :menu,
|
||||
params: { project_id: project.id, sprint_id: agile_sprint.id, id: story.id, all: "1" },
|
||||
params: { project_id: project.id, sprint_id: sprint.id, id: story.id, all: "1" },
|
||||
format: :html
|
||||
end
|
||||
|
||||
@@ -238,7 +238,7 @@ RSpec.describe Backlogs::WorkPackagesController do
|
||||
end
|
||||
|
||||
context "when another open sprint exists" do
|
||||
let!(:other_open_sprint) { create(:agile_sprint, name: "Sprint 2", project:) }
|
||||
let!(:other_open_sprint) { create(:sprint, name: "Sprint 2", project:) }
|
||||
|
||||
before { allow(Backlogs::StoryMenuListComponent).to receive(:new).and_call_original }
|
||||
|
||||
@@ -276,7 +276,7 @@ RSpec.describe Backlogs::WorkPackagesController do
|
||||
describe "GET #move_to_sprint_dialog" do
|
||||
subject do
|
||||
get :move_to_sprint_dialog,
|
||||
params: { project_id: project.id, sprint_id: agile_sprint.id, id: story.id },
|
||||
params: { project_id: project.id, sprint_id: sprint.id, id: story.id },
|
||||
format: :turbo_stream
|
||||
end
|
||||
|
||||
@@ -291,7 +291,7 @@ RSpec.describe Backlogs::WorkPackagesController do
|
||||
context "when all=1 is in params" do
|
||||
subject do
|
||||
get :move_to_sprint_dialog,
|
||||
params: { project_id: project.id, sprint_id: agile_sprint.id, id: story.id, all: "1" },
|
||||
params: { project_id: project.id, sprint_id: sprint.id, id: story.id, all: "1" },
|
||||
format: :turbo_stream
|
||||
end
|
||||
|
||||
|
||||
@@ -30,13 +30,6 @@
|
||||
|
||||
FactoryBot.define do
|
||||
factory :sprint do
|
||||
name { "version" }
|
||||
effective_date { Date.today + 14.days }
|
||||
sharing { "none" }
|
||||
status { "open" }
|
||||
end
|
||||
|
||||
factory :agile_sprint, class: "Agile::Sprint" do
|
||||
sequence(:name) { |n| "Sprint #{n}" }
|
||||
project
|
||||
status { "in_planning" }
|
||||
|
||||
@@ -34,7 +34,7 @@ require_relative "../../support/pages/backlog"
|
||||
RSpec.describe "Create", :js do
|
||||
shared_let(:project) { create(:project) }
|
||||
shared_let(:initial_sprint) do
|
||||
create(:agile_sprint,
|
||||
create(:sprint,
|
||||
project:,
|
||||
name: "Initial sprint",
|
||||
start_date: Date.new(2025, 9, 5),
|
||||
@@ -152,7 +152,7 @@ RSpec.describe "Create", :js do
|
||||
|
||||
describe "proposed sprint names" do
|
||||
before do
|
||||
Agile::Sprint.delete_all
|
||||
Sprint.delete_all
|
||||
end
|
||||
|
||||
it "prefilled with 'Sprint 1' if there are no previous sprints" do
|
||||
@@ -167,7 +167,7 @@ RSpec.describe "Create", :js do
|
||||
|
||||
context "with a previous sprint" do
|
||||
before do
|
||||
create(:agile_sprint, name: "Be ambitious 42", project:)
|
||||
create(:sprint, name: "Be ambitious 42", project:)
|
||||
|
||||
planning_page.visit!
|
||||
planning_page.open_create_sprint_dialog
|
||||
|
||||
@@ -45,7 +45,7 @@ RSpec.describe "Edit", :js do
|
||||
let(:planning_page) { Pages::Backlog.new(project) }
|
||||
|
||||
let!(:closed_sprint) do
|
||||
create(:agile_sprint,
|
||||
create(:sprint,
|
||||
project:,
|
||||
status: "completed",
|
||||
start_date: Date.new(2025, 8, 25),
|
||||
@@ -53,14 +53,14 @@ RSpec.describe "Edit", :js do
|
||||
end
|
||||
|
||||
let!(:first_sprint) do
|
||||
create(:agile_sprint,
|
||||
create(:sprint,
|
||||
project:,
|
||||
start_date: Date.new(2025, 9, 5),
|
||||
finish_date: Date.new(2025, 9, 15))
|
||||
end
|
||||
|
||||
let!(:second_sprint) do
|
||||
create(:agile_sprint,
|
||||
create(:sprint,
|
||||
project:,
|
||||
start_date: Date.new(2025, 9, 16),
|
||||
finish_date: Date.new(2025, 9, 26))
|
||||
|
||||
@@ -36,7 +36,7 @@ RSpec.describe "Sprint list", :js do
|
||||
shared_let(:other_project) { create(:project) }
|
||||
shared_let(:user) { create(:user, member_with_permissions: { project => %i[view_sprints view_work_packages] }) }
|
||||
shared_let(:sprint) do
|
||||
create(:agile_sprint, project:,
|
||||
create(:sprint, project:,
|
||||
start_date: Date.new(2025, 9, 1),
|
||||
finish_date: Date.new(2025, 9, 14))
|
||||
end
|
||||
|
||||
@@ -56,19 +56,19 @@ RSpec.describe "Start and finish sprints", :js do
|
||||
end
|
||||
let(:task_statuses) { task_type.statuses }
|
||||
let!(:first_sprint) do
|
||||
create(:agile_sprint,
|
||||
create(:sprint,
|
||||
project:,
|
||||
start_date: Date.new(2025, 9, 5),
|
||||
finish_date: Date.new(2025, 9, 15))
|
||||
end
|
||||
let!(:second_sprint) do
|
||||
create(:agile_sprint,
|
||||
create(:sprint,
|
||||
project:,
|
||||
start_date: Date.new(2025, 9, 16),
|
||||
finish_date: Date.new(2025, 9, 26))
|
||||
end
|
||||
let!(:closed_sprint) do
|
||||
create(:agile_sprint,
|
||||
create(:sprint,
|
||||
project:,
|
||||
status: "completed",
|
||||
start_date: Date.new(2025, 8, 25),
|
||||
@@ -126,7 +126,7 @@ RSpec.describe "Start and finish sprints", :js do
|
||||
|
||||
context "when the sprint is active" do
|
||||
let!(:first_sprint) do
|
||||
create(:agile_sprint,
|
||||
create(:sprint,
|
||||
project:,
|
||||
status: "active",
|
||||
start_date: Date.new(2025, 9, 5),
|
||||
@@ -181,7 +181,7 @@ RSpec.describe "Start and finish sprints", :js do
|
||||
# because of work packages but not because they are genuinely shared, are not options to move
|
||||
# work packages to.
|
||||
let!(:sprint_from_other_project) do
|
||||
create(:agile_sprint,
|
||||
create(:sprint,
|
||||
project: create(:project),
|
||||
start_date: Date.new(2025, 9, 5),
|
||||
finish_date: Date.new(2025, 9, 15)) do |sprint|
|
||||
|
||||
@@ -35,7 +35,7 @@ RSpec.describe "Show burndown chart", :js do
|
||||
include Redmine::I18n
|
||||
|
||||
shared_let(:project) { create(:project, enabled_module_names: %w(backlogs)) }
|
||||
shared_let(:sprint) { create(:agile_sprint, status: "active", project:, start_date: 1.week.ago, finish_date: 1.week.from_now) }
|
||||
shared_let(:sprint) { create(:sprint, status: "active", project:, start_date: 1.week.ago, finish_date: 1.week.from_now) }
|
||||
|
||||
let(:planning_page) { Pages::Backlog.new(project) }
|
||||
let(:role) do
|
||||
|
||||
@@ -70,7 +70,7 @@ RSpec.describe "Inbox column in sprint planning view", :js do
|
||||
end
|
||||
|
||||
context "when the inbox has no work packages" do
|
||||
let!(:sprint) { create(:agile_sprint, name: "Sprint 1", project:) }
|
||||
let!(:sprint) { create(:sprint, name: "Sprint 1", project:) }
|
||||
|
||||
before { planning_page.visit! }
|
||||
|
||||
@@ -183,7 +183,7 @@ RSpec.describe "Inbox column in sprint planning view", :js do
|
||||
types: [type],
|
||||
enabled_module_names: %w[work_package_tracking backlogs])
|
||||
end
|
||||
let!(:shared_sprint) { create(:agile_sprint, name: "Shared Sprint", project: source_project) }
|
||||
let!(:shared_sprint) { create(:sprint, name: "Shared Sprint", project: source_project) }
|
||||
|
||||
before { planning_page.visit! }
|
||||
|
||||
@@ -195,7 +195,7 @@ RSpec.describe "Inbox column in sprint planning view", :js do
|
||||
end
|
||||
|
||||
context "when a sprint is present" do
|
||||
let!(:sprint) { create(:agile_sprint, name: "Sprint 1", project:) }
|
||||
let!(:sprint) { create(:sprint, name: "Sprint 1", project:) }
|
||||
|
||||
before { planning_page.visit! }
|
||||
|
||||
@@ -206,7 +206,7 @@ RSpec.describe "Inbox column in sprint planning view", :js do
|
||||
end
|
||||
|
||||
context "with work packages in the inbox" do
|
||||
let!(:sprint) { create(:agile_sprint, name: "Sprint 1", project:) }
|
||||
let!(:sprint) { create(:sprint, name: "Sprint 1", project:) }
|
||||
let!(:inbox_wp1) { create(:work_package, project:) }
|
||||
let!(:inbox_wp2) { create(:work_package, project:) }
|
||||
let!(:inbox_wp3) { create(:work_package, project:) }
|
||||
@@ -264,7 +264,7 @@ RSpec.describe "Inbox column in sprint planning view", :js do
|
||||
end
|
||||
|
||||
describe "moving backlog items to a sprint via the 'Move to sprint' menu item" do
|
||||
let!(:sprint2) { create(:agile_sprint, name: "Sprint 2", project:) }
|
||||
let!(:sprint2) { create(:sprint, name: "Sprint 2", project:) }
|
||||
let!(:sprint_wp) { create(:work_package, project:, sprint:) }
|
||||
|
||||
before { planning_page.visit! }
|
||||
@@ -418,7 +418,7 @@ RSpec.describe "Inbox column in sprint planning view", :js do
|
||||
end
|
||||
|
||||
describe "retaining the 'show all' state" do
|
||||
let!(:sprint) { create(:agile_sprint, name: "Sprint 1", project:) }
|
||||
let!(:sprint) { create(:sprint, name: "Sprint 1", project:) }
|
||||
let!(:inbox_items) { create_list(:work_package, 5, project:, type:) }
|
||||
let!(:sprint_wp1) { create(:work_package, project:, sprint:, type:) }
|
||||
let!(:sprint_wp2) { create(:work_package, project:, sprint:, type:) }
|
||||
|
||||
@@ -57,8 +57,8 @@ RSpec.describe "Create work package in sprint", :js do
|
||||
let!(:priority) { create(:default_priority) }
|
||||
let!(:status) { create(:default_status) }
|
||||
|
||||
let!(:sprint1) { create(:agile_sprint, project:) }
|
||||
let!(:sprint2) { create(:agile_sprint, project:) }
|
||||
let!(:sprint1) { create(:sprint, project:) }
|
||||
let!(:sprint2) { create(:sprint, project:) }
|
||||
|
||||
let!(:sprint1_wp1) { create(:work_package, sprint: sprint1, type:, project:) }
|
||||
let!(:sprint1_wp2) { create(:work_package, sprint: sprint1, type:, project:) }
|
||||
|
||||
@@ -55,8 +55,8 @@ RSpec.describe "Dragging work packages in and between sprints",
|
||||
|
||||
let(:type) { create(:type) }
|
||||
|
||||
let!(:sprint1) { create(:agile_sprint, project:) }
|
||||
let!(:sprint2) { create(:agile_sprint, project:) }
|
||||
let!(:sprint1) { create(:sprint, project:) }
|
||||
let!(:sprint2) { create(:sprint, project:) }
|
||||
|
||||
let!(:sprint1_wp1) { create(:work_package, sprint: sprint1, type:, project:) }
|
||||
let!(:sprint1_wp2) { create(:work_package, sprint: sprint1, type:, project:) }
|
||||
|
||||
@@ -45,8 +45,8 @@ RSpec.describe "Filter work packages by backlog filters", :js do
|
||||
parent: work_package_with_story_type,
|
||||
project:)
|
||||
end
|
||||
shared_let(:own_sprint) { create(:agile_sprint, project:) }
|
||||
shared_let(:shared_sprint) { create(:agile_sprint, project: create(:project)) }
|
||||
shared_let(:own_sprint) { create(:sprint, project:) }
|
||||
shared_let(:shared_sprint) { create(:sprint, project: create(:project)) }
|
||||
shared_let(:work_package_in_own_sprint) { create(:work_package, type: task_type, project:, sprint: own_sprint) }
|
||||
shared_let(:work_package_in_shared_sprint) { create(:work_package, type: task_type, project:, sprint: shared_sprint) }
|
||||
|
||||
|
||||
@@ -36,16 +36,16 @@ RSpec.describe "Sprint displayed and selectable on work package table", :js do
|
||||
let(:finish_date) { Date.new(2025, 10, 25) }
|
||||
let(:other_start_date) { start_date + 20.days }
|
||||
let(:other_finish_date) { finish_date + 20.days }
|
||||
let(:sprint) { create(:agile_sprint, project:, name: "Sprint", start_date:, finish_date:) }
|
||||
let(:sprint) { create(:sprint, project:, name: "Sprint", start_date:, finish_date:) }
|
||||
let(:other_sprint_name) { "Other sprint" }
|
||||
let(:other_sprint) do
|
||||
create(:agile_sprint,
|
||||
create(:sprint,
|
||||
project:,
|
||||
name: other_sprint_name,
|
||||
start_date: other_start_date,
|
||||
finish_date: other_finish_date)
|
||||
end
|
||||
let(:sprint_from_other_project) { create(:agile_sprint, project: another_project, name: "Sprint from other project") }
|
||||
let(:sprint_from_other_project) { create(:sprint, project: another_project, name: "Sprint from other project") }
|
||||
let(:project) { create(:project, name: "Project", enabled_module_names:) }
|
||||
let(:project_sharing) do
|
||||
create(:project,
|
||||
@@ -294,7 +294,7 @@ RSpec.describe "Sprint displayed and selectable on work package table", :js do
|
||||
context "without being a member in a project at all" do
|
||||
let!(:query) { build(:global_query, user: current_user) }
|
||||
let!(:project_where_user_is_no_member) { create(:project) }
|
||||
let!(:sprint_that_user_cannot_see) { create(:agile_sprint, project: project_where_user_is_no_member) }
|
||||
let!(:sprint_that_user_cannot_see) { create(:sprint, project: project_where_user_is_no_member) }
|
||||
let!(:work_package_that_user_cannot_see) do
|
||||
create(:work_package, project: project_where_user_is_no_member, sprint: sprint_that_user_cannot_see)
|
||||
end
|
||||
@@ -315,7 +315,7 @@ RSpec.describe "Sprint displayed and selectable on work package table", :js do
|
||||
end
|
||||
|
||||
context "when a sprint is shared" do
|
||||
let(:shared_sprint) { create(:agile_sprint, project: project_sharing, name: "Shared sprint") }
|
||||
let(:shared_sprint) { create(:sprint, project: project_sharing, name: "Shared sprint") }
|
||||
let!(:query) { build(:global_query, user: current_user) }
|
||||
let!(:wp_with_shared_sprint) do
|
||||
create(:work_package,
|
||||
|
||||
@@ -32,8 +32,8 @@ require "spec_helper"
|
||||
|
||||
RSpec.describe "Sprint displayed and selectable on work package view", :js do
|
||||
shared_let(:project) { create(:project) }
|
||||
shared_let(:sprint) { create(:agile_sprint, project:) }
|
||||
shared_let(:other_sprint) { create(:agile_sprint, project:) }
|
||||
shared_let(:sprint) { create(:sprint, project:) }
|
||||
shared_let(:other_sprint) { create(:sprint, project:) }
|
||||
shared_let(:work_package) { create(:work_package, project:, sprint:) }
|
||||
|
||||
let(:permissions) { %i(view_work_packages view_sprints manage_sprint_items) }
|
||||
|
||||
@@ -38,7 +38,7 @@ RSpec.describe API::V3::Sprints::SprintRepresenter, "rendering" do
|
||||
let(:finish_date) { Date.new(2024, 1, 10) }
|
||||
let(:status) { "in_planning" }
|
||||
let(:sprint) do
|
||||
build_stubbed(:agile_sprint,
|
||||
build_stubbed(:sprint,
|
||||
project: workspace,
|
||||
status:,
|
||||
name: "Sprint 1",
|
||||
@@ -80,7 +80,7 @@ RSpec.describe API::V3::Sprints::SprintRepresenter, "rendering" do
|
||||
context "with in_planning value" do
|
||||
it_behaves_like "has a titled link" do
|
||||
let(:href) { "urn:openproject-org:api:v3:sprints:status:in_planning" }
|
||||
let(:title) { I18n.t("activerecord.attributes.agile/sprint.statuses.in_planning") }
|
||||
let(:title) { I18n.t("activerecord.attributes.sprint.statuses.in_planning") }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -89,7 +89,7 @@ RSpec.describe API::V3::Sprints::SprintRepresenter, "rendering" do
|
||||
|
||||
it_behaves_like "has a titled link" do
|
||||
let(:href) { "urn:openproject-org:api:v3:sprints:status:active" }
|
||||
let(:title) { I18n.t("activerecord.attributes.agile/sprint.statuses.active") }
|
||||
let(:title) { I18n.t("activerecord.attributes.sprint.statuses.active") }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -98,7 +98,7 @@ RSpec.describe API::V3::Sprints::SprintRepresenter, "rendering" do
|
||||
|
||||
it_behaves_like "has a titled link" do
|
||||
let(:href) { "urn:openproject-org:api:v3:sprints:status:completed" }
|
||||
let(:title) { I18n.t("activerecord.attributes.agile/sprint.statuses.completed") }
|
||||
let(:title) { I18n.t("activerecord.attributes.sprint.statuses.completed") }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#-- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
require "spec_helper"
|
||||
|
||||
RSpec.describe API::V3::Utilities::ResourceLinkGenerator do
|
||||
include API::V3::Utilities::PathHelper
|
||||
|
||||
describe ".make_link" do
|
||||
it "resolves an Agile::Sprint to the sprint API path" do
|
||||
sprint = build_stubbed(:agile_sprint)
|
||||
expect(described_class.make_link(sprint)).to eql api_v3_paths.sprint(sprint.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
+2
-2
@@ -33,8 +33,8 @@ require_relative Rails.root.join("spec/lib/api/v3/work_packages/eager_loading/ea
|
||||
|
||||
RSpec.describe API::V3::WorkPackages::EagerLoading::Checksum, "integration" do
|
||||
shared_let(:project) { create(:project) }
|
||||
shared_let(:sprint) { create(:agile_sprint, project:) }
|
||||
shared_let(:other_sprint) { create(:agile_sprint, project:) }
|
||||
shared_let(:sprint) { create(:sprint, project:) }
|
||||
shared_let(:other_sprint) { create(:sprint, project:) }
|
||||
shared_let(:work_package) do
|
||||
create(:work_package,
|
||||
project:,
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ RSpec.describe API::V3::WorkPackages::WorkPackageRepresenter, "rendering" do
|
||||
|
||||
let(:story_points) { 23 }
|
||||
let(:position) { 123 }
|
||||
let(:sprint) { build_stubbed(:agile_sprint) }
|
||||
let(:sprint) { build_stubbed(:sprint) }
|
||||
let(:embed_links) { true }
|
||||
let(:representer) do
|
||||
described_class.create(work_package, current_user:, embed_links:)
|
||||
|
||||
@@ -62,12 +62,12 @@ RSpec.describe MigrateVersionsToSprints, type: :model do
|
||||
context "when all criteria are met (used in the backlog and work package present)" do
|
||||
context "when version is used as a sprint (DISPLAY_LEFT)" do
|
||||
it "creates one sprint" do
|
||||
expect { migrate }.to change(Agile::Sprint, :count).by(1)
|
||||
expect { migrate }.to change(Sprint, :count).by(1)
|
||||
end
|
||||
|
||||
it "copies name, start_date and finish_date" do
|
||||
migrate
|
||||
sprint = Agile::Sprint.last
|
||||
sprint = Sprint.last
|
||||
expect(sprint.name).to eq("Test Sprint")
|
||||
expect(sprint.start_date).to eq(Date.new(2026, 1, 1))
|
||||
expect(sprint.finish_date).to eq(Date.new(2026, 1, 14))
|
||||
@@ -78,12 +78,12 @@ RSpec.describe MigrateVersionsToSprints, type: :model do
|
||||
let(:version_type) { :backlog }
|
||||
|
||||
it "creates one sprint" do
|
||||
expect { migrate }.to change(Agile::Sprint, :count).by(1)
|
||||
expect { migrate }.to change(Sprint, :count).by(1)
|
||||
end
|
||||
|
||||
it "copies name, start_date and finish_date" do
|
||||
migrate
|
||||
sprint = Agile::Sprint.last
|
||||
sprint = Sprint.last
|
||||
expect(sprint.name).to eq("Test Sprint")
|
||||
expect(sprint.start_date).to eq(Date.new(2026, 1, 1))
|
||||
expect(sprint.finish_date).to eq(Date.new(2026, 1, 14))
|
||||
@@ -95,7 +95,7 @@ RSpec.describe MigrateVersionsToSprints, type: :model do
|
||||
let(:version_type) { :display_none }
|
||||
|
||||
it "does not create a sprint" do
|
||||
expect { migrate }.not_to change(Agile::Sprint, :count)
|
||||
expect { migrate }.not_to change(Sprint, :count)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -103,7 +103,7 @@ RSpec.describe MigrateVersionsToSprints, type: :model do
|
||||
let!(:wp1) { nil }
|
||||
|
||||
it "does not create a sprint" do
|
||||
expect { migrate }.not_to change(Agile::Sprint, :count)
|
||||
expect { migrate }.not_to change(Sprint, :count)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -111,8 +111,8 @@ RSpec.describe MigrateVersionsToSprints, type: :model do
|
||||
describe "date handling" do
|
||||
context "when both start_date and effective_date are null" do
|
||||
it "creates a sprint with nil dates" do
|
||||
expect { migrate }.to change(Agile::Sprint, :count).by(1)
|
||||
sprint = Agile::Sprint.last
|
||||
expect { migrate }.to change(Sprint, :count).by(1)
|
||||
sprint = Sprint.last
|
||||
expect(sprint.start_date).to be_nil
|
||||
expect(sprint.finish_date).to be_nil
|
||||
end
|
||||
@@ -123,7 +123,7 @@ RSpec.describe MigrateVersionsToSprints, type: :model do
|
||||
|
||||
it "sets effective_date for finish_date" do
|
||||
migrate
|
||||
sprint = Agile::Sprint.last
|
||||
sprint = Sprint.last
|
||||
expect(sprint.start_date).to be_nil
|
||||
expect(sprint.finish_date).to eq(Date.new(2026, 2, 28))
|
||||
end
|
||||
@@ -134,7 +134,7 @@ RSpec.describe MigrateVersionsToSprints, type: :model do
|
||||
|
||||
it "sets start_date for start_date" do
|
||||
migrate
|
||||
sprint = Agile::Sprint.last
|
||||
sprint = Sprint.last
|
||||
expect(sprint.start_date).to eq(Date.new(2026, 2, 1))
|
||||
expect(sprint.finish_date).to be_nil
|
||||
end
|
||||
@@ -147,7 +147,7 @@ RSpec.describe MigrateVersionsToSprints, type: :model do
|
||||
|
||||
it "creates sprint with in_planning status" do
|
||||
migrate
|
||||
expect(Agile::Sprint.last.status).to eq("in_planning")
|
||||
expect(Sprint.last.status).to eq("in_planning")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -156,7 +156,7 @@ RSpec.describe MigrateVersionsToSprints, type: :model do
|
||||
|
||||
it "creates sprint with completed status" do
|
||||
migrate
|
||||
expect(Agile::Sprint.last.status).to eq("completed")
|
||||
expect(Sprint.last.status).to eq("completed")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -165,7 +165,7 @@ RSpec.describe MigrateVersionsToSprints, type: :model do
|
||||
|
||||
it "creates sprint with completed status" do
|
||||
migrate
|
||||
expect(Agile::Sprint.last.status).to eq("completed")
|
||||
expect(Sprint.last.status).to eq("completed")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -175,7 +175,7 @@ RSpec.describe MigrateVersionsToSprints, type: :model do
|
||||
|
||||
it "sets sprint_id on all associated work packages" do
|
||||
migrate
|
||||
sprint = Agile::Sprint.last
|
||||
sprint = Sprint.last
|
||||
expect(wp1.reload.sprint_id).to eq(sprint.id)
|
||||
expect(wp2.reload.sprint_id).to eq(sprint.id)
|
||||
end
|
||||
@@ -194,7 +194,7 @@ RSpec.describe MigrateVersionsToSprints, type: :model do
|
||||
|
||||
it "assigns work packages to their respective sprints" do
|
||||
migrate
|
||||
sprints = Agile::Sprint.all.index_by(&:name)
|
||||
sprints = Sprint.all.index_by(&:name)
|
||||
expect(wp1.reload.sprint_id).to eq(sprints[version.name].id)
|
||||
expect(wp2.reload.sprint_id).to eq(sprints[version.name].id)
|
||||
expect(wp3.reload.sprint_id).to eq(sprints[version2.name].id)
|
||||
@@ -209,7 +209,7 @@ RSpec.describe MigrateVersionsToSprints, type: :model do
|
||||
|
||||
it "assigns work packages from both projects" do
|
||||
migrate
|
||||
sprint = Agile::Sprint.last
|
||||
sprint = Sprint.last
|
||||
expect(wp1.reload.sprint_id).to eq(sprint.id)
|
||||
expect(wp2.reload.sprint_id).to eq(sprint.id)
|
||||
expect(wp_in_other_project.reload.sprint_id).to eq(sprint.id)
|
||||
@@ -224,7 +224,7 @@ RSpec.describe MigrateVersionsToSprints, type: :model do
|
||||
|
||||
it "only assigns work packages from the sprint project" do
|
||||
migrate
|
||||
sprint = Agile::Sprint.last
|
||||
sprint = Sprint.last
|
||||
expect(wp1.reload.sprint_id).to eq(sprint.id)
|
||||
expect(wp2.reload.sprint_id).to eq(sprint.id)
|
||||
expect(wp_in_other_project.reload.sprint_id).to be_nil
|
||||
|
||||
@@ -40,7 +40,7 @@ RSpec.describe Backlog do
|
||||
let(:project) { create(:project) }
|
||||
let(:open_status) { create(:status, is_closed: false) }
|
||||
let(:closed_status) { create(:status, is_closed: true) }
|
||||
let(:agile_sprint) { create(:agile_sprint, project:) }
|
||||
let(:sprint) { create(:sprint, project:) }
|
||||
|
||||
before { login_as create(:admin) }
|
||||
|
||||
@@ -49,7 +49,7 @@ RSpec.describe Backlog do
|
||||
it "returns work packages with no sprint assigned and open status" do
|
||||
inbox_wp = create(:work_package, project:, status: open_status)
|
||||
create(:work_package, project:, status: closed_status)
|
||||
create(:work_package, project:, status: open_status, sprint: agile_sprint)
|
||||
create(:work_package, project:, status: open_status, sprint:)
|
||||
|
||||
expect(inbox).to contain_exactly(inbox_wp)
|
||||
end
|
||||
|
||||
@@ -61,7 +61,7 @@ RSpec.describe Burndown do
|
||||
subject(:burndown) { described_class.new(sprint, project) }
|
||||
|
||||
describe "for an agile sprint" do
|
||||
let(:sprint) { create(:agile_sprint, project:) }
|
||||
let(:sprint) { create(:sprint, project:) }
|
||||
|
||||
describe "WITH the today date fixed to April 4th, 2011 and having a 10 (working days) sprint" do
|
||||
around do |example|
|
||||
@@ -191,7 +191,7 @@ RSpec.describe Burndown do
|
||||
end
|
||||
|
||||
context "without dates on the sprint" do
|
||||
let(:sprint) { create(:agile_sprint, project:, start_date: nil, finish_date: nil) }
|
||||
let(:sprint) { create(:sprint, project:, start_date: nil, finish_date: nil) }
|
||||
let(:story) do
|
||||
build(:story,
|
||||
:created_in_past,
|
||||
|
||||
@@ -33,6 +33,6 @@ require "spec_helper"
|
||||
RSpec.describe Project do
|
||||
describe "associations" do
|
||||
it { is_expected.to have_many(:backlog_buckets).class_name("Agile::BacklogBucket").dependent(:destroy) }
|
||||
it { is_expected.to have_many(:sprints).class_name("Agile::Sprint").dependent(:destroy) }
|
||||
it { is_expected.to have_many(:sprints).class_name("Sprint").dependent(:destroy) }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -35,7 +35,7 @@ RSpec.describe Queries::Sprints::Filters::NameFilter do
|
||||
let(:class_key) { :name }
|
||||
let(:human_name) { I18n.t(:label_name) }
|
||||
let(:type) { :string }
|
||||
let(:model) { Agile::Sprint }
|
||||
let(:model) { Sprint }
|
||||
|
||||
describe "#allowed_values" do
|
||||
it "is nil" do
|
||||
|
||||
@@ -35,6 +35,6 @@ RSpec.describe Queries::Sprints::Filters::TypeaheadFilter do
|
||||
let(:class_key) { :typeahead }
|
||||
let(:human_name) { I18n.t(:label_search) }
|
||||
let(:type) { :search }
|
||||
let(:model) { Agile::Sprint }
|
||||
let(:model) { Sprint }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -34,9 +34,9 @@ RSpec.describe Queries::Sprints::SprintQuery, "integration" do
|
||||
shared_let(:project) { create(:project, public: false) }
|
||||
shared_let(:other_project) { create(:project, public: false) }
|
||||
shared_let(:project_without_permission) { create(:project, public: false) }
|
||||
shared_let(:sprint) { create(:agile_sprint, project:, name: "Alpha Sprint") }
|
||||
shared_let(:other_sprint) { create(:agile_sprint, project: other_project, name: "Beta Sprint") }
|
||||
shared_let(:sprint_without_permission) { create(:agile_sprint, project: project_without_permission) }
|
||||
shared_let(:sprint) { create(:sprint, project:, name: "Alpha Sprint") }
|
||||
shared_let(:other_sprint) { create(:sprint, project: other_project, name: "Beta Sprint") }
|
||||
shared_let(:sprint_without_permission) { create(:sprint, project: project_without_permission) }
|
||||
|
||||
let(:instance) { described_class.new }
|
||||
let(:permissions) { %i[view_sprints] }
|
||||
|
||||
@@ -38,7 +38,7 @@ RSpec.describe Queries::WorkPackages::Filter::SprintFilter do
|
||||
def pluck(*_args); end
|
||||
end
|
||||
end
|
||||
let(:sprint) { build_stubbed(:agile_sprint) }
|
||||
let(:sprint) { build_stubbed(:sprint) }
|
||||
|
||||
it_behaves_like "basic query filter" do
|
||||
let(:type) { :list_optional }
|
||||
@@ -53,7 +53,7 @@ RSpec.describe Queries::WorkPackages::Filter::SprintFilter do
|
||||
current_user { build_stubbed(:user) }
|
||||
|
||||
before do
|
||||
allow(Agile::Sprint)
|
||||
allow(Sprint)
|
||||
.to receive(:visible)
|
||||
.and_return(visible_scope)
|
||||
|
||||
@@ -126,8 +126,8 @@ RSpec.describe Queries::WorkPackages::Filter::SprintFilter do
|
||||
end
|
||||
|
||||
describe "#value_objects" do
|
||||
let(:sprint1) { build_stubbed(:agile_sprint) }
|
||||
let(:sprint2) { build_stubbed(:agile_sprint) }
|
||||
let(:sprint1) { build_stubbed(:sprint) }
|
||||
let(:sprint2) { build_stubbed(:sprint) }
|
||||
|
||||
before do
|
||||
allow(visible_scope)
|
||||
|
||||
+16
-16
@@ -30,7 +30,7 @@
|
||||
|
||||
require "spec_helper"
|
||||
|
||||
RSpec.describe Agile::Sprint do
|
||||
RSpec.describe Sprint do
|
||||
let(:project) { create(:project) }
|
||||
let(:sprint_status) { "in_planning" }
|
||||
|
||||
@@ -91,14 +91,14 @@ RSpec.describe Agile::Sprint do
|
||||
end
|
||||
|
||||
it "prevents multiple active sprints in the same project" do
|
||||
create(:agile_sprint, project:, status: "active")
|
||||
create(:sprint, project:, status: "active")
|
||||
expect(sprint).not_to be_valid
|
||||
expect(sprint.errors[:status]).to include("only one active sprint is allowed per project.")
|
||||
end
|
||||
|
||||
it "allows multiple active sprints in different projects" do
|
||||
other_project = create(:project)
|
||||
create(:agile_sprint, project: other_project, status: "active")
|
||||
create(:sprint, project: other_project, status: "active")
|
||||
expect(sprint).to be_valid
|
||||
end
|
||||
|
||||
@@ -109,8 +109,8 @@ RSpec.describe Agile::Sprint do
|
||||
end
|
||||
|
||||
it "allows multiple non-active sprints in the same project" do
|
||||
create(:agile_sprint, project:, status: "completed")
|
||||
create(:agile_sprint, project:, status: "in_planning")
|
||||
create(:sprint, project:, status: "completed")
|
||||
create(:sprint, project:, status: "in_planning")
|
||||
sprint.status = "in_planning"
|
||||
expect(sprint).to be_valid
|
||||
end
|
||||
@@ -134,7 +134,7 @@ RSpec.describe Agile::Sprint do
|
||||
end
|
||||
|
||||
describe "#task_board_for" do
|
||||
let(:sprint) { create(:agile_sprint, project:) }
|
||||
let(:sprint) { create(:sprint, project:) }
|
||||
let(:other_project) { create(:project) }
|
||||
|
||||
context "when a sprint task board exists" do
|
||||
@@ -182,7 +182,7 @@ RSpec.describe Agile::Sprint do
|
||||
end
|
||||
|
||||
describe "work_package association" do
|
||||
let(:sprint) { create(:agile_sprint, project:) }
|
||||
let(:sprint) { create(:sprint, project:) }
|
||||
let(:work_package) { create(:work_package, project:, sprint:) }
|
||||
|
||||
it "can have work packages associated" do
|
||||
@@ -197,7 +197,7 @@ RSpec.describe Agile::Sprint do
|
||||
end
|
||||
|
||||
describe "#work_packages_for" do
|
||||
let(:sprint) { create(:agile_sprint, project:) }
|
||||
let(:sprint) { create(:sprint, project:) }
|
||||
let(:other_project) { create(:project) }
|
||||
let!(:wp1) { create(:work_package, project:, sprint:) }
|
||||
let!(:wp2) { create(:work_package, project:, sprint:) }
|
||||
@@ -240,7 +240,7 @@ RSpec.describe Agile::Sprint do
|
||||
end
|
||||
|
||||
describe "#owned_by?" do
|
||||
let(:sprint) { create(:agile_sprint, project:) }
|
||||
let(:sprint) { create(:sprint, project:) }
|
||||
let(:other_project) { create(:project) }
|
||||
|
||||
it "returns true when the sprint belongs to the given project" do
|
||||
@@ -253,7 +253,7 @@ RSpec.describe Agile::Sprint do
|
||||
end
|
||||
|
||||
describe "#shared_with?" do
|
||||
let(:sprint) { create(:agile_sprint, project:) }
|
||||
let(:sprint) { create(:sprint, project:) }
|
||||
let(:receiver_project) { create(:project, sprint_sharing: "receive_shared") }
|
||||
let(:other_project) { create(:project, sprint_sharing: "no_sharing") }
|
||||
|
||||
@@ -282,7 +282,7 @@ RSpec.describe Agile::Sprint do
|
||||
context "with subproject sharing" do
|
||||
let(:parent_project) { create(:project, sprint_sharing: "share_subprojects") }
|
||||
let(:child_project) { create(:project, parent: parent_project, sprint_sharing: "receive_shared") }
|
||||
let(:parent_sprint) { create(:agile_sprint, project: parent_project) }
|
||||
let(:parent_sprint) { create(:sprint, project: parent_project) }
|
||||
|
||||
it "returns true when sprint is shared from parent to child" do
|
||||
expect(parent_sprint.shared_with?(child_project)).to be true
|
||||
@@ -294,7 +294,7 @@ RSpec.describe Agile::Sprint do
|
||||
end
|
||||
|
||||
context "with work package assignment to unrelated project" do
|
||||
let(:unrelated_sprint) { create(:agile_sprint, project: other_project) }
|
||||
let(:unrelated_sprint) { create(:sprint, project: other_project) }
|
||||
|
||||
before do
|
||||
create(:work_package, project:, sprint: unrelated_sprint)
|
||||
@@ -307,7 +307,7 @@ RSpec.describe Agile::Sprint do
|
||||
end
|
||||
|
||||
describe "#visible_to?" do
|
||||
let(:sprint) { create(:agile_sprint, project:) }
|
||||
let(:sprint) { create(:sprint, project:) }
|
||||
let(:receiver_project) { create(:project, sprint_sharing: "receive_shared") }
|
||||
let(:other_project) { create(:project, sprint_sharing: "no_sharing") }
|
||||
|
||||
@@ -335,7 +335,7 @@ RSpec.describe Agile::Sprint do
|
||||
|
||||
context "with global sharing" do
|
||||
let(:global_sharer) { create(:project, sprint_sharing: "share_all_projects") }
|
||||
let(:global_sprint) { create(:agile_sprint, project: global_sharer) }
|
||||
let(:global_sprint) { create(:sprint, project: global_sharer) }
|
||||
|
||||
it "returns true for projects that receive shared sprints" do
|
||||
expect(global_sprint.visible_to?(receiver_project)).to be true
|
||||
@@ -354,7 +354,7 @@ RSpec.describe Agile::Sprint do
|
||||
let(:parent_project) { create(:project, sprint_sharing: "share_subprojects") }
|
||||
let(:child_project) { create(:project, parent: parent_project, sprint_sharing: "receive_shared") }
|
||||
let(:grandchild_project) { create(:project, parent: child_project, sprint_sharing: "receive_shared") }
|
||||
let(:parent_sprint) { create(:agile_sprint, project: parent_project) }
|
||||
let(:parent_sprint) { create(:sprint, project: parent_project) }
|
||||
|
||||
it "returns true for direct child receiving shared sprints" do
|
||||
expect(parent_sprint.visible_to?(child_project)).to be true
|
||||
@@ -371,7 +371,7 @@ RSpec.describe Agile::Sprint do
|
||||
|
||||
context "with work package assignment" do
|
||||
let(:unrelated_project) { create(:project, sprint_sharing: "no_sharing") }
|
||||
let(:unrelated_sprint) { create(:agile_sprint, project: unrelated_project) }
|
||||
let(:unrelated_sprint) { create(:sprint, project: unrelated_project) }
|
||||
|
||||
before do
|
||||
create(:work_package, project:, sprint: unrelated_sprint)
|
||||
+25
-25
@@ -30,18 +30,18 @@
|
||||
|
||||
require "spec_helper"
|
||||
|
||||
RSpec.describe Agile::Sprints::Scopes::ForProject do
|
||||
RSpec.describe Sprints::Scopes::ForProject do
|
||||
let(:sprint_sharing) { "no_sharing" }
|
||||
let(:project) { create(:project, sprint_sharing:) }
|
||||
let(:global_sharer) { create(:project, sprint_sharing: "share_all_projects") }
|
||||
let(:other_project) { create(:project) }
|
||||
let!(:sprint_in_project) { create(:agile_sprint, project:) }
|
||||
let!(:global_sprint) { create(:agile_sprint, project: global_sharer) }
|
||||
let!(:sprint_in_other_project) { create(:agile_sprint, project: other_project) }
|
||||
let!(:sprint_in_project) { create(:sprint, project:) }
|
||||
let!(:global_sprint) { create(:sprint, project: global_sharer) }
|
||||
let!(:sprint_in_other_project) { create(:sprint, project: other_project) }
|
||||
|
||||
shared_examples "executes a single SQL query" do
|
||||
it "resolves for_project in a single query" do
|
||||
expect { Agile::Sprint.for_project(project).load }.to have_a_query_limit(1)
|
||||
expect { Sprint.for_project(project).load }.to have_a_query_limit(1)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -53,24 +53,24 @@ RSpec.describe Agile::Sprints::Scopes::ForProject do
|
||||
|
||||
context "and there are no work package assignments" do
|
||||
it "returns only the project's own sprint" do
|
||||
expect(Agile::Sprint.for_project(project)).to contain_exactly(sprint_in_project)
|
||||
expect(Sprint.for_project(project)).to contain_exactly(sprint_in_project)
|
||||
end
|
||||
end
|
||||
|
||||
context "and the project has a work package assigned to a sprint from another project" do
|
||||
let!(:cross_project_sprint) { create(:agile_sprint, project: other_project) }
|
||||
let!(:cross_project_sprint) { create(:sprint, project: other_project) }
|
||||
let!(:work_package) { create(:work_package, project:, sprint: cross_project_sprint) }
|
||||
|
||||
it "returns both the own sprint and the sprint assigned via work package" do
|
||||
expect(Agile::Sprint.for_project(project)).to contain_exactly(sprint_in_project, cross_project_sprint)
|
||||
expect(Sprint.for_project(project)).to contain_exactly(sprint_in_project, cross_project_sprint)
|
||||
end
|
||||
|
||||
context "when the cross-project sprint is completed" do
|
||||
let!(:completed_sprint) { create(:agile_sprint, project: other_project, status: "completed") }
|
||||
let!(:completed_sprint) { create(:sprint, project: other_project, status: "completed") }
|
||||
let!(:work_package) { create(:work_package, project:, sprint: completed_sprint) }
|
||||
|
||||
it "returns the completed sprint among the sprints" do
|
||||
expect(Agile::Sprint.for_project(project)).to include(completed_sprint)
|
||||
expect(Sprint.for_project(project)).to include(completed_sprint)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -83,16 +83,16 @@ RSpec.describe Agile::Sprints::Scopes::ForProject do
|
||||
|
||||
context "and there are no work package assignments" do
|
||||
it "returns only the project's own sprint" do
|
||||
expect(Agile::Sprint.for_project(project)).to contain_exactly(sprint_in_project)
|
||||
expect(Sprint.for_project(project)).to contain_exactly(sprint_in_project)
|
||||
end
|
||||
end
|
||||
|
||||
context "and a work package in the project is assigned to a sprint from another project" do
|
||||
let!(:cross_project_sprint) { create(:agile_sprint, project: other_project) }
|
||||
let!(:cross_project_sprint) { create(:sprint, project: other_project) }
|
||||
let!(:work_package) { create(:work_package, project:, sprint: cross_project_sprint) }
|
||||
|
||||
it "returns both the own sprint and the cross-project sprint" do
|
||||
expect(Agile::Sprint.for_project(project)).to contain_exactly(sprint_in_project, cross_project_sprint)
|
||||
expect(Sprint.for_project(project)).to contain_exactly(sprint_in_project, cross_project_sprint)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -104,16 +104,16 @@ RSpec.describe Agile::Sprints::Scopes::ForProject do
|
||||
|
||||
context "and there are no work package assignments" do
|
||||
it "returns only the project's own sprint" do
|
||||
expect(Agile::Sprint.for_project(project)).to contain_exactly(sprint_in_project)
|
||||
expect(Sprint.for_project(project)).to contain_exactly(sprint_in_project)
|
||||
end
|
||||
end
|
||||
|
||||
context "and a work package in the project is assigned to a sprint from another project" do
|
||||
let!(:cross_project_sprint) { create(:agile_sprint, project: other_project) }
|
||||
let!(:cross_project_sprint) { create(:sprint, project: other_project) }
|
||||
let!(:work_package) { create(:work_package, project:, sprint: cross_project_sprint) }
|
||||
|
||||
it "returns both the own sprint and the cross-project sprint" do
|
||||
expect(Agile::Sprint.for_project(project)).to contain_exactly(sprint_in_project, cross_project_sprint)
|
||||
expect(Sprint.for_project(project)).to contain_exactly(sprint_in_project, cross_project_sprint)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -125,14 +125,14 @@ RSpec.describe Agile::Sprints::Scopes::ForProject do
|
||||
|
||||
context "and there is only a global sharer" do
|
||||
it "returns only the sprints shared from the global sharer project" do
|
||||
expect(Agile::Sprint.for_project(project)).to contain_exactly(global_sprint)
|
||||
expect(Sprint.for_project(project)).to contain_exactly(global_sprint)
|
||||
end
|
||||
|
||||
context "and a work package is assigned to the project's own sprint" do
|
||||
let!(:work_package) { create(:work_package, project:, sprint: sprint_in_project) }
|
||||
|
||||
it "returns both the global shared sprint and the project's own sprint" do
|
||||
expect(Agile::Sprint.for_project(project)).to contain_exactly(global_sprint, sprint_in_project)
|
||||
expect(Sprint.for_project(project)).to contain_exactly(global_sprint, sprint_in_project)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -140,7 +140,7 @@ RSpec.describe Agile::Sprints::Scopes::ForProject do
|
||||
let!(:work_package) { create(:work_package, project:, sprint: global_sprint) }
|
||||
|
||||
it "returns the shared sprint only once" do
|
||||
expect(Agile::Sprint.for_project(project)).to contain_exactly(global_sprint)
|
||||
expect(Sprint.for_project(project)).to contain_exactly(global_sprint)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -148,7 +148,7 @@ RSpec.describe Agile::Sprints::Scopes::ForProject do
|
||||
let!(:work_package) { create(:work_package, project:, sprint: sprint_in_other_project) }
|
||||
|
||||
it "returns the global shared sprint and the unrelated project's sprint" do
|
||||
expect(Agile::Sprint.for_project(project)).to contain_exactly(global_sprint, sprint_in_other_project)
|
||||
expect(Sprint.for_project(project)).to contain_exactly(global_sprint, sprint_in_other_project)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -156,17 +156,17 @@ RSpec.describe Agile::Sprints::Scopes::ForProject do
|
||||
context "and there is a subproject-sharing ancestor" do
|
||||
let(:subproject_sharer) { create(:project, sprint_sharing: "share_subprojects") }
|
||||
let(:project) { create(:project, parent: subproject_sharer, sprint_sharing:) }
|
||||
let!(:subproject_sprint) { create(:agile_sprint, project: subproject_sharer) }
|
||||
let!(:subproject_sprint) { create(:sprint, project: subproject_sharer) }
|
||||
|
||||
it "returns only the sprints shared from the closest subproject-sharing ancestor" do
|
||||
expect(Agile::Sprint.for_project(project)).to contain_exactly(subproject_sprint)
|
||||
expect(Sprint.for_project(project)).to contain_exactly(subproject_sprint)
|
||||
end
|
||||
|
||||
context "and a work package is assigned to the project's own sprint" do
|
||||
let!(:work_package) { create(:work_package, project:, sprint: sprint_in_project) }
|
||||
|
||||
it "returns both the ancestor's shared sprint and the project's own sprint" do
|
||||
expect(Agile::Sprint.for_project(project)).to contain_exactly(subproject_sprint, sprint_in_project)
|
||||
expect(Sprint.for_project(project)).to contain_exactly(subproject_sprint, sprint_in_project)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -174,7 +174,7 @@ RSpec.describe Agile::Sprints::Scopes::ForProject do
|
||||
let!(:work_package) { create(:work_package, project:, sprint: subproject_sprint) }
|
||||
|
||||
it "returns the ancestor's shared sprint only once" do
|
||||
expect(Agile::Sprint.for_project(project)).to contain_exactly(subproject_sprint)
|
||||
expect(Sprint.for_project(project)).to contain_exactly(subproject_sprint)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -182,7 +182,7 @@ RSpec.describe Agile::Sprints::Scopes::ForProject do
|
||||
let!(:work_package) { create(:work_package, project:, sprint: global_sprint) }
|
||||
|
||||
it "returns both the ancestor's shared sprint and the global sharer's sprint" do
|
||||
expect(Agile::Sprint.for_project(project)).to contain_exactly(subproject_sprint, global_sprint)
|
||||
expect(Sprint.for_project(project)).to contain_exactly(subproject_sprint, global_sprint)
|
||||
end
|
||||
end
|
||||
end
|
||||
+25
-25
@@ -30,18 +30,18 @@
|
||||
|
||||
require "spec_helper"
|
||||
|
||||
RSpec.describe Agile::Sprints::Scopes::NativeToSprintSource do
|
||||
RSpec.describe Sprints::Scopes::NativeToSprintSource do
|
||||
let(:sprint_sharing) { "no_sharing" }
|
||||
let(:project) { create(:project, sprint_sharing:) }
|
||||
let(:global_sharer) { create(:project, sprint_sharing: "share_all_projects") }
|
||||
let(:other_project) { create(:project) }
|
||||
let!(:sprint_in_project) { create(:agile_sprint, project:) }
|
||||
let!(:global_sprint) { create(:agile_sprint, project: global_sharer) }
|
||||
let!(:sprint_in_other_project) { create(:agile_sprint, project: other_project) }
|
||||
let!(:sprint_in_project) { create(:sprint, project:) }
|
||||
let!(:global_sprint) { create(:sprint, project: global_sharer) }
|
||||
let!(:sprint_in_other_project) { create(:sprint, project: other_project) }
|
||||
|
||||
shared_examples "executes a single SQL query" do
|
||||
it "resolves native_to_sprint_source in a single query" do
|
||||
expect { Agile::Sprint.native_to_sprint_source(project).load }.to have_a_query_limit(1)
|
||||
expect { Sprint.native_to_sprint_source(project).load }.to have_a_query_limit(1)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -53,24 +53,24 @@ RSpec.describe Agile::Sprints::Scopes::NativeToSprintSource do
|
||||
|
||||
context "and there are no work package assignments" do
|
||||
it "returns only the project's own sprint" do
|
||||
expect(Agile::Sprint.native_to_sprint_source(project)).to contain_exactly(sprint_in_project)
|
||||
expect(Sprint.native_to_sprint_source(project)).to contain_exactly(sprint_in_project)
|
||||
end
|
||||
end
|
||||
|
||||
context "and the project has a work package assigned to a sprint from another project" do
|
||||
let!(:cross_project_sprint) { create(:agile_sprint, project: other_project) }
|
||||
let!(:cross_project_sprint) { create(:sprint, project: other_project) }
|
||||
let!(:work_package) { create(:work_package, project:, sprint: cross_project_sprint) }
|
||||
|
||||
it "returns only the project's own sprint" do
|
||||
expect(Agile::Sprint.native_to_sprint_source(project)).to contain_exactly(sprint_in_project)
|
||||
expect(Sprint.native_to_sprint_source(project)).to contain_exactly(sprint_in_project)
|
||||
end
|
||||
|
||||
context "when the cross-project sprint is completed" do
|
||||
let!(:completed_sprint) { create(:agile_sprint, project: other_project, status: "completed") }
|
||||
let!(:completed_sprint) { create(:sprint, project: other_project, status: "completed") }
|
||||
let!(:work_package) { create(:work_package, project:, sprint: completed_sprint) }
|
||||
|
||||
it "returns only the project's own sprint" do
|
||||
expect(Agile::Sprint.native_to_sprint_source(project)).to contain_exactly(sprint_in_project)
|
||||
expect(Sprint.native_to_sprint_source(project)).to contain_exactly(sprint_in_project)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -83,16 +83,16 @@ RSpec.describe Agile::Sprints::Scopes::NativeToSprintSource do
|
||||
|
||||
context "and there are no work package assignments" do
|
||||
it "returns only the project's own sprint" do
|
||||
expect(Agile::Sprint.native_to_sprint_source(project)).to contain_exactly(sprint_in_project)
|
||||
expect(Sprint.native_to_sprint_source(project)).to contain_exactly(sprint_in_project)
|
||||
end
|
||||
end
|
||||
|
||||
context "and a work package in the project is assigned to a sprint from another project" do
|
||||
let!(:cross_project_sprint) { create(:agile_sprint, project: other_project) }
|
||||
let!(:cross_project_sprint) { create(:sprint, project: other_project) }
|
||||
let!(:work_package) { create(:work_package, project:, sprint: cross_project_sprint) }
|
||||
|
||||
it "returns only the project's own sprint" do
|
||||
expect(Agile::Sprint.native_to_sprint_source(project)).to contain_exactly(sprint_in_project)
|
||||
expect(Sprint.native_to_sprint_source(project)).to contain_exactly(sprint_in_project)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -104,16 +104,16 @@ RSpec.describe Agile::Sprints::Scopes::NativeToSprintSource do
|
||||
|
||||
context "and there are no work package assignments" do
|
||||
it "returns only the project's own sprint" do
|
||||
expect(Agile::Sprint.native_to_sprint_source(project)).to contain_exactly(sprint_in_project)
|
||||
expect(Sprint.native_to_sprint_source(project)).to contain_exactly(sprint_in_project)
|
||||
end
|
||||
end
|
||||
|
||||
context "and a work package in the project is assigned to a sprint from another project" do
|
||||
let!(:cross_project_sprint) { create(:agile_sprint, project: other_project) }
|
||||
let!(:cross_project_sprint) { create(:sprint, project: other_project) }
|
||||
let!(:work_package) { create(:work_package, project:, sprint: cross_project_sprint) }
|
||||
|
||||
it "returns only the project's own sprint" do
|
||||
expect(Agile::Sprint.native_to_sprint_source(project)).to contain_exactly(sprint_in_project)
|
||||
expect(Sprint.native_to_sprint_source(project)).to contain_exactly(sprint_in_project)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -125,14 +125,14 @@ RSpec.describe Agile::Sprints::Scopes::NativeToSprintSource do
|
||||
|
||||
context "and there is only a global sharer" do
|
||||
it "returns only the sprints shared from the global sharer project" do
|
||||
expect(Agile::Sprint.native_to_sprint_source(project)).to contain_exactly(global_sprint)
|
||||
expect(Sprint.native_to_sprint_source(project)).to contain_exactly(global_sprint)
|
||||
end
|
||||
|
||||
context "and a work package is assigned to the project's own sprint" do
|
||||
let!(:work_package) { create(:work_package, project:, sprint: sprint_in_project) }
|
||||
|
||||
it "returns only the sprints shared from the global sharer project" do
|
||||
expect(Agile::Sprint.native_to_sprint_source(project)).to contain_exactly(global_sprint)
|
||||
expect(Sprint.native_to_sprint_source(project)).to contain_exactly(global_sprint)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -140,7 +140,7 @@ RSpec.describe Agile::Sprints::Scopes::NativeToSprintSource do
|
||||
let!(:work_package) { create(:work_package, project:, sprint: global_sprint) }
|
||||
|
||||
it "returns the shared sprint only once" do
|
||||
expect(Agile::Sprint.native_to_sprint_source(project)).to contain_exactly(global_sprint)
|
||||
expect(Sprint.native_to_sprint_source(project)).to contain_exactly(global_sprint)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -148,7 +148,7 @@ RSpec.describe Agile::Sprints::Scopes::NativeToSprintSource do
|
||||
let!(:work_package) { create(:work_package, project:, sprint: sprint_in_other_project) }
|
||||
|
||||
it "returns only the sprints shared from the global sharer project" do
|
||||
expect(Agile::Sprint.native_to_sprint_source(project)).to contain_exactly(global_sprint)
|
||||
expect(Sprint.native_to_sprint_source(project)).to contain_exactly(global_sprint)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -156,17 +156,17 @@ RSpec.describe Agile::Sprints::Scopes::NativeToSprintSource do
|
||||
context "and there is a subproject-sharing ancestor" do
|
||||
let(:subproject_sharer) { create(:project, sprint_sharing: "share_subprojects") }
|
||||
let(:project) { create(:project, parent: subproject_sharer, sprint_sharing:) }
|
||||
let!(:subproject_sprint) { create(:agile_sprint, project: subproject_sharer) }
|
||||
let!(:subproject_sprint) { create(:sprint, project: subproject_sharer) }
|
||||
|
||||
it "returns only the sprints shared from the closest subproject-sharing ancestor" do
|
||||
expect(Agile::Sprint.native_to_sprint_source(project)).to contain_exactly(subproject_sprint)
|
||||
expect(Sprint.native_to_sprint_source(project)).to contain_exactly(subproject_sprint)
|
||||
end
|
||||
|
||||
context "and a work package is assigned to the project's own sprint" do
|
||||
let!(:work_package) { create(:work_package, project:, sprint: sprint_in_project) }
|
||||
|
||||
it "returns only the sprints shared from the closest subproject-sharing ancestor" do
|
||||
expect(Agile::Sprint.native_to_sprint_source(project)).to contain_exactly(subproject_sprint)
|
||||
expect(Sprint.native_to_sprint_source(project)).to contain_exactly(subproject_sprint)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -174,7 +174,7 @@ RSpec.describe Agile::Sprints::Scopes::NativeToSprintSource do
|
||||
let!(:work_package) { create(:work_package, project:, sprint: subproject_sprint) }
|
||||
|
||||
it "returns the ancestor's shared sprint only once" do
|
||||
expect(Agile::Sprint.native_to_sprint_source(project)).to contain_exactly(subproject_sprint)
|
||||
expect(Sprint.native_to_sprint_source(project)).to contain_exactly(subproject_sprint)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -182,7 +182,7 @@ RSpec.describe Agile::Sprints::Scopes::NativeToSprintSource do
|
||||
let!(:work_package) { create(:work_package, project:, sprint: global_sprint) }
|
||||
|
||||
it "returns only the sprints shared from the closest subproject-sharing ancestor" do
|
||||
expect(Agile::Sprint.native_to_sprint_source(project)).to contain_exactly(subproject_sprint)
|
||||
expect(Sprint.native_to_sprint_source(project)).to contain_exactly(subproject_sprint)
|
||||
end
|
||||
end
|
||||
end
|
||||
+3
-3
@@ -30,13 +30,13 @@
|
||||
|
||||
require "spec_helper"
|
||||
|
||||
RSpec.describe Agile::Sprints::Scopes::ReceivingProjects do
|
||||
RSpec.describe Sprints::Scopes::ReceivingProjects do
|
||||
let(:source_project) { create(:project, sprint_sharing: source_sharing) }
|
||||
let(:source_sharing) { "no_sharing" }
|
||||
let(:sprint) { create(:agile_sprint, project: source_project) }
|
||||
let(:sprint) { create(:sprint, project: source_project) }
|
||||
|
||||
describe ".receiving_projects" do
|
||||
subject(:scope) { Agile::Sprint.receiving_projects(sprint) }
|
||||
subject(:scope) { Sprint.receiving_projects(sprint) }
|
||||
|
||||
it "resolves in a single query" do
|
||||
sprint
|
||||
+5
-5
@@ -30,17 +30,17 @@
|
||||
|
||||
require "spec_helper"
|
||||
|
||||
RSpec.describe Agile::Sprints::Scopes::Visible do
|
||||
RSpec.describe Sprints::Scopes::Visible do
|
||||
shared_let(:project_globally_sharing) { create(:project, sprint_sharing: "share_all_projects") }
|
||||
shared_let(:project_receiving) { create(:project, sprint_sharing: "receive_shared") }
|
||||
shared_let(:sprint_in_global_sharer) { create(:agile_sprint, project: project_globally_sharing) }
|
||||
shared_let(:sprint_in_global_sharer) { create(:sprint, project: project_globally_sharing) }
|
||||
|
||||
shared_let(:project_with_own_sprint) { create(:project) }
|
||||
shared_let(:sprint_own) { create(:agile_sprint, project: project_with_own_sprint) }
|
||||
shared_let(:sprint_own) { create(:sprint, project: project_with_own_sprint) }
|
||||
|
||||
shared_let(:project_with_referenced_by_wp_sprint) { create(:project) }
|
||||
shared_let(:sprint_referenced_by_wp) do
|
||||
create(:agile_sprint, project: create(:project)) do |sprint|
|
||||
create(:sprint, project: create(:project)) do |sprint|
|
||||
create(:work_package, sprint:, project: project_with_referenced_by_wp_sprint)
|
||||
end
|
||||
end
|
||||
@@ -85,7 +85,7 @@ RSpec.describe Agile::Sprints::Scopes::Visible do
|
||||
end
|
||||
shared_let(:user_without_membership) { create(:user) }
|
||||
|
||||
subject { Agile::Sprint.visible(current_user) }
|
||||
subject { Sprint.visible(current_user) }
|
||||
|
||||
context "for a user with view_sprints in project with own sprint" do
|
||||
current_user { user_with_permission_in_project_with_own_sprint }
|
||||
@@ -33,7 +33,7 @@ require "spec_helper"
|
||||
RSpec.describe WorkPackage do
|
||||
describe "associations" do
|
||||
it { is_expected.to belong_to(:backlog_bucket).class_name("Agile::BacklogBucket").optional(true) }
|
||||
it { is_expected.to belong_to(:sprint).class_name("Agile::Sprint").optional(true) }
|
||||
it { is_expected.to belong_to(:sprint).class_name("Sprint").optional(true) }
|
||||
end
|
||||
|
||||
describe ".order_by_position" do
|
||||
|
||||
@@ -37,8 +37,8 @@ RSpec.describe WorkPackage, "positions" do # rubocop:disable RSpec/SpecFilePathF
|
||||
|
||||
shared_let(:project) { create(:project) }
|
||||
shared_let(:type) { create(:type) }
|
||||
shared_let(:sprint1) { create(:agile_sprint, project:, name: "Sprint 1") }
|
||||
shared_let(:sprint2) { create(:agile_sprint, project:, name: "Sprint 2") }
|
||||
shared_let(:sprint1) { create(:sprint, project:, name: "Sprint 1") }
|
||||
shared_let(:sprint2) { create(:sprint, project:, name: "Sprint 2") }
|
||||
|
||||
let!(:sprint1_wp1) { create_work_package(subject: "Sprint 1 WorkPackage 1", sprint: sprint1) }
|
||||
let!(:sprint1_wp2) { create_work_package(subject: "Sprint 1 WorkPackage 2", sprint: sprint1) }
|
||||
|
||||
@@ -33,8 +33,8 @@ require "spec_helper"
|
||||
RSpec.describe "WorkPackage sprint association journaling", # rubocop:disable RSpec/DescribeClass
|
||||
with_settings: { journal_aggregation_time_minutes: 0 } do
|
||||
shared_let(:project) { create(:project) }
|
||||
shared_let(:sprint1) { create(:agile_sprint, name: "Sprint 1", project:) }
|
||||
shared_let(:sprint2) { create(:agile_sprint, name: "Sprint 2", project:) }
|
||||
shared_let(:sprint1) { create(:sprint, name: "Sprint 1", project:) }
|
||||
shared_let(:sprint2) { create(:sprint, name: "Sprint 2", project:) }
|
||||
shared_let(:work_package_with_sprint) do
|
||||
create(:work_package, :created_in_past, created_at: 1.day.ago, project:, sprint: sprint1)
|
||||
end
|
||||
|
||||
@@ -38,9 +38,9 @@ RSpec.describe "API v3 Sprint resource", content_type: :json do
|
||||
shared_let(:project) { create(:project, public: false) }
|
||||
shared_let(:other_project) { create(:project, public: false) }
|
||||
shared_let(:project_without_permission) { create(:project, public: false) }
|
||||
shared_let(:sprint) { create(:agile_sprint, project:) }
|
||||
shared_let(:other_sprint) { create(:agile_sprint, project: other_project) }
|
||||
shared_let(:sprint_without_permission) { create(:agile_sprint, project: project_without_permission) }
|
||||
shared_let(:sprint) { create(:sprint, project:) }
|
||||
shared_let(:other_sprint) { create(:sprint, project: other_project) }
|
||||
shared_let(:sprint_without_permission) { create(:sprint, project: project_without_permission) }
|
||||
|
||||
let(:permissions) { %i[view_sprints] }
|
||||
|
||||
|
||||
@@ -38,9 +38,9 @@ RSpec.describe "API v3 Sprint resource on project", content_type: :json do
|
||||
shared_let(:project) { create(:project, public: false) }
|
||||
shared_let(:other_project) { create(:project, public: false) }
|
||||
shared_let(:project_without_permission) { create(:project, public: false) }
|
||||
shared_let(:sprint) { create(:agile_sprint, project:) }
|
||||
shared_let(:other_sprint) { create(:agile_sprint, project: other_project) }
|
||||
shared_let(:sprint_without_permission) { create(:agile_sprint, project: project_without_permission) }
|
||||
shared_let(:sprint) { create(:sprint, project:) }
|
||||
shared_let(:other_sprint) { create(:sprint, project: other_project) }
|
||||
shared_let(:sprint_without_permission) { create(:sprint, project: project_without_permission) }
|
||||
|
||||
let(:permissions) { %i[view_sprints] }
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ RSpec.describe "API v3 Sprint resource", content_type: :json do
|
||||
include API::V3::Utilities::PathHelper
|
||||
|
||||
shared_let(:project) { create(:project, public: false) }
|
||||
shared_let(:sprint) { create(:agile_sprint, project:) }
|
||||
shared_let(:sprint) { create(:sprint, project:) }
|
||||
|
||||
let(:permissions) { %i[view_sprints] }
|
||||
|
||||
|
||||
@@ -39,9 +39,9 @@ RSpec.describe "API v3 Work package resource",
|
||||
shared_let(:type) { project.types.first }
|
||||
shared_let(:status) { create(:status, is_default: true) }
|
||||
shared_let(:priority) { create(:priority, is_default: true) }
|
||||
shared_let(:sprint) { create(:agile_sprint, project:) }
|
||||
shared_let(:completed_sprint) { create(:agile_sprint, project:, status: :completed) }
|
||||
shared_let(:outside_sprint) { create(:agile_sprint, project: create(:project)) }
|
||||
shared_let(:sprint) { create(:sprint, project:) }
|
||||
shared_let(:completed_sprint) { create(:sprint, project:, status: :completed) }
|
||||
shared_let(:outside_sprint) { create(:sprint, project: create(:project)) }
|
||||
|
||||
let(:role) { create(:project_role, permissions:) }
|
||||
let(:permissions) { %i[add_work_packages view_work_packages manage_sprint_items view_sprints] }
|
||||
|
||||
@@ -40,9 +40,9 @@ RSpec.describe "API v3 Work package resource",
|
||||
shared_let(:type) { project.types.first }
|
||||
shared_let(:status) { create(:status, is_default: true) }
|
||||
shared_let(:priority) { create(:priority, is_default: true) }
|
||||
shared_let(:sprint) { create(:agile_sprint, project:) }
|
||||
shared_let(:completed_sprint) { create(:agile_sprint, project:, status: :completed) }
|
||||
shared_let(:outside_sprint) { create(:agile_sprint, project: other_project) }
|
||||
shared_let(:sprint) { create(:sprint, project:) }
|
||||
shared_let(:completed_sprint) { create(:sprint, project:, status: :completed) }
|
||||
shared_let(:outside_sprint) { create(:sprint, project: other_project) }
|
||||
shared_let(:work_package) { create(:work_package, project:, type:, status:, priority:) }
|
||||
|
||||
let(:role) { create(:project_role, permissions:) }
|
||||
|
||||
@@ -38,7 +38,7 @@ RSpec.describe "Backlogs::Backlog", :skip_csrf, type: :rails_request do
|
||||
shared_let(:user) { create(:admin) }
|
||||
shared_let(:project) { create(:project) }
|
||||
shared_let(:status) { create(:status, name: "status 1", is_default: true) }
|
||||
shared_let(:sprint) { create(:agile_sprint, project:) }
|
||||
shared_let(:sprint) { create(:sprint, project:) }
|
||||
shared_let(:story) { create(:work_package, status:, sprint:, project:) }
|
||||
|
||||
current_user { user }
|
||||
@@ -91,10 +91,10 @@ RSpec.describe "Backlogs::Backlog", :skip_csrf, type: :rails_request do
|
||||
|
||||
context "with no sprints available" do
|
||||
before do
|
||||
allow(Agile::Sprint)
|
||||
allow(Sprint)
|
||||
.to receive(:for_project)
|
||||
.with(project)
|
||||
.and_return(Agile::Sprint.none)
|
||||
.and_return(Sprint.none)
|
||||
end
|
||||
|
||||
it "still renders the sprint planning container for turbo-frame requests" do
|
||||
|
||||
@@ -36,7 +36,7 @@ RSpec.describe "Backlogs::BurndownChart", :skip_csrf, type: :rails_request do
|
||||
shared_let(:user) { create(:admin) }
|
||||
shared_let(:project) { create(:project) }
|
||||
shared_let(:status) { create(:status, name: "status 1", is_default: true) }
|
||||
shared_let(:sprint) { create(:agile_sprint, project:) }
|
||||
shared_let(:sprint) { create(:sprint, project:) }
|
||||
|
||||
current_user { user }
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ RSpec.describe "Backlogs::Sprints", :skip_csrf, type: :rails_request do
|
||||
shared_let(:user) { create(:admin) }
|
||||
shared_let(:project) { create(:project) }
|
||||
shared_let(:status) { create(:status, name: "status 1", is_default: true) }
|
||||
shared_let(:sprint) { create(:agile_sprint, name: "Original sprint name", project:) }
|
||||
shared_let(:sprint) { create(:sprint, name: "Original sprint name", project:) }
|
||||
|
||||
current_user { user }
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user