remove sprint.rb and move agile/sprint.rb

This commit is contained in:
ulferts
2026-04-20 17:47:11 +02:00
parent e634ba696c
commit 82768cc752
115 changed files with 463 additions and 639 deletions
@@ -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.
-110
View File
@@ -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
+74 -1
View File
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 %>
+12 -16
View File
@@ -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)
@@ -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
@@ -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:,
@@ -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
+2 -2
View File
@@ -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,
+1 -1
View File
@@ -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)
@@ -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)
@@ -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
@@ -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
@@ -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
@@ -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