[#74768] Remove calculated_value_project_attribute feature flag

https://community.openproject.org/wp/74768
This commit is contained in:
Ivan Kuchin
2026-05-12 19:16:07 +02:00
parent 51381443e5
commit b648341030
31 changed files with 58 additions and 173 deletions
@@ -102,9 +102,6 @@ OpenProject::CustomFieldFormat.map do |fields|
label: :label_calculated_value,
only: %w(Project),
order: 14,
enabled: lambda do
OpenProject::FeatureDecisions.calculated_value_project_attribute_active?
end,
enterprise_feature: :calculated_values,
formatter: "CustomValue::CalculatedValueStrategy")
end
-4
View File
@@ -45,10 +45,6 @@ OpenProject::FeatureDecisions.add :built_in_oauth_applications,
description: "Allows the display and use of built-in OAuth applications.",
force_active: true
OpenProject::FeatureDecisions.add :calculated_value_project_attribute,
description: "Allows the use of calculated values as a project attribute.",
force_active: true
OpenProject::FeatureDecisions.add :minutes_styling_meeting_pdf,
description: "Allow exporting a meeting with FITKO styling. " \
"See #65124 for details."
@@ -77,8 +77,7 @@ RSpec.shared_examples_for "custom_field contract" do
end
end
context "for a calculated field", with_ee: %i[calculated_values],
with_flag: { calculated_value_project_attribute: true } do
context "for a calculated field", with_ee: %i[calculated_values] do
let(:custom_field_field_format) { "calculated_value" }
let(:custom_field_is_required) { false }
let(:custom_field_formula) { "1 + 1" }
@@ -58,8 +58,7 @@ RSpec.describe CustomFields::UpdateContract do
subject(:contract) { described_class.new(custom_field, current_user) }
context "for a calculated field", with_ee: %i[calculated_values],
with_flag: { calculated_value_project_attribute: true } do
context "for a calculated field", with_ee: %i[calculated_values] do
let(:custom_field_field_format) { "calculated_value" }
let(:custom_field_formula) { "1 + 1" }
@@ -31,10 +31,7 @@
require "spec_helper"
require_relative "shared_context"
RSpec.describe "Edit project custom field calculated value",
:js,
with_ee: %i[calculated_values weighted_item_lists],
with_flag: { calculated_value_project_attribute: true } do
RSpec.describe "Edit project custom field calculated value", :js, with_ee: %i[calculated_values weighted_item_lists] do
include_context "with seeded project custom fields"
shared_let(:weighted_item_list_project_custom_field) do
@@ -128,40 +128,32 @@ RSpec.describe "Create project custom fields in sections", :js do
end
context "when trying to create calculated value field" do
context "without the feature flag", with_flag: { calculated_value_project_attribute: false } do
it "prevents creation" do
cf_index_page.expect_not_having_create_item "Calculated value"
before do
cf_index_page.click_to_create_new_custom_field "Calculated value"
end
context "without calculated_values enterprise feature" do
it do
expect(page)
.to have_enterprise_banner(:premium)
.and have_no_field("custom_field_name")
.and have_no_button("Save")
end
end
context "with the feature flag", with_flag: { calculated_value_project_attribute: true } do
before do
cf_index_page.click_to_create_new_custom_field "Calculated value"
end
context "with calculated_values enterprise feature", with_ee: %i[calculated_values] do
it "allows creation" do
fill_in("custom_field_name", with: "New calculated value custom field")
select(section_for_select_fields.name, from: "custom_field_custom_field_section_id")
find_field(id: "custom_field_formula", type: :hidden).set("1 + 1")
context "without calculated_values enterprise feature" do
it do
expect(page)
.to have_enterprise_banner(:premium)
.and have_no_field("custom_field_name")
.and have_no_button("Save")
end
end
click_on("Save")
context "with calculated_values enterprise feature", with_ee: %i[calculated_values] do
it "allows creation" do
fill_in("custom_field_name", with: "New calculated value custom field")
select(section_for_select_fields.name, from: "custom_field_custom_field_section_id")
find_field(id: "custom_field_formula", type: :hidden).set("1 + 1")
expect(page).to have_text("Successful creation")
click_on("Save")
expect(page).to have_text("Successful creation")
created = ProjectCustomField.find_by_name("New calculated value custom field")
expect(page).to have_current_path(admin_settings_project_custom_field_path(created))
expect(page).to have_text("New calculated value custom field")
end
created = ProjectCustomField.find_by_name("New calculated value custom field")
expect(page).to have_current_path(admin_settings_project_custom_field_path(created))
expect(page).to have_text("New calculated value custom field")
end
end
end
@@ -32,9 +32,7 @@ require "spec_helper"
require_relative "../format_field_expectations"
RSpec.describe "Project calculated value custom fields", :js do
context "with feature flag", with_flag: { calculated_value_project_attribute: true } do
context "with enterprise token", with_ee: %i[calculated_values] do
it_behaves_like "expected fields for the Project custom field's format", "Calculated value"
end
context "with enterprise token", with_ee: %i[calculated_values] do
it_behaves_like "expected fields for the Project custom field's format", "Calculated value"
end
end
@@ -157,7 +157,7 @@ RSpec.describe "List project custom fields", :js do
end
describe "managing project custom fields" do
context "with calculated value feature flag active", with_flag: { calculated_value_project_attribute: true } do
context "with calculated value type" do
it "offers the type for creation with enterprise icon" do
cf_index_page.expect_having_create_item(I18n.t("label_calculated_value"), enterprise_icon: true)
end
@@ -188,28 +188,6 @@ RSpec.describe "List project custom fields", :js do
expect(containers.last.text).to include(calculated_value_project_custom_field.name)
end
end
it "lists calculated values even if the feature flag is deactivated later" do
# This spec tests that calculated values are still shown after the feature flag is deactivated.
# First, a custom field of type calculated value is created. This must be done while the feature flag is active,
# or else the model validation will fail.
# Next, we simulate that the feature flag is off:
allow(OpenProject::FeatureDecisions).to receive(:calculated_value_project_attribute_active?).and_return(false)
# Revisit the page and check that the field is still listed:
cf_index_page.visit!
within_project_custom_field_section_container(section_for_input_fields) do
containers = page.all(".op-project-custom-field-container")
expect(containers.last.text).to include(calculated_value_project_custom_field.name)
end
end
end
end
context "without calculated value feature flag active" do
it "does not offer the type for creation" do
cf_index_page.expect_not_having_create_item("Calculated value")
end
end
@@ -31,10 +31,7 @@
require "spec_helper"
require_relative "shared_context"
RSpec.describe "Weighted item lists and calculated values",
:js,
with_ee: %i[calculated_values weighted_item_lists],
with_flag: { calculated_value_project_attribute: true } do
RSpec.describe "Weighted item lists and calculated values", :js, with_ee: %i[calculated_values weighted_item_lists] do
current_user { create(:admin) }
let!(:project) { create(:project) }
+1 -3
View File
@@ -397,9 +397,7 @@ RSpec.describe "Projects lists columns", :js, with_settings: { login_required?:
end
end
context "with calculated value columns",
with_ee: %i[calculated_values],
with_flag: { calculated_value_project_attribute: true } do
context "with calculated value columns", with_ee: %i[calculated_values] do
let!(:static_calculated_value) do
create(:calculated_value_project_custom_field,
name: "Calculated value field",
+1 -3
View File
@@ -734,9 +734,7 @@ RSpec.describe "Projects list filters", :js, with_settings: { login_required?: f
end
end
context "when filtering via calculated values",
with_ee: %i[calculated_values],
with_flag: { calculated_value_project_attribute: true } do
context "when filtering via calculated values", with_ee: %i[calculated_values] do
let(:projects_with_calculated_value) do
[project, public_project]
end
+1 -3
View File
@@ -273,9 +273,7 @@ RSpec.describe "Projects lists ordering", :js, with_settings: { login_required?:
projects_page.expect_project_at_place(project, 1)
end
context "when sorting calculated value custom fields",
with_ee: %i[calculated_values],
with_flag: { calculated_value_project_attribute: true } do
context "when sorting calculated value custom fields", with_ee: %i[calculated_values] do
let(:projects_with_calculated_value) do
[project, development_project, public_project, child_project_m, child_project_a]
end
@@ -521,9 +521,7 @@ RSpec.describe "Projects custom fields mapping via project settings", :js do
end
end
describe "calculated value fields",
with_ee: %i[calculated_values],
with_flag: { calculated_value_project_attribute: true } do
describe "calculated value fields", with_ee: %i[calculated_values] do
let!(:admin) do
create(:admin)
end
@@ -30,10 +30,7 @@
require "spec_helper"
RSpec.describe CustomFields::Inputs::CalculatedValue,
type: :forms,
with_ee: %i[calculated_values],
with_flag: { calculated_value_project_attribute: true } do
RSpec.describe CustomFields::Inputs::CalculatedValue, type: :forms, with_ee: %i[calculated_values] do
include_context "with rendered custom field input form"
let(:custom_field) { create(:calculated_value_project_custom_field, name: "Calculated value field", formula: "1 + 1") }
@@ -30,10 +30,7 @@
#
require "spec_helper"
RSpec.describe Projects::Settings::CustomFieldsForm,
type: :forms,
with_ee: %i[calculated_values],
with_flag: { calculated_value_project_attribute: true } do
RSpec.describe Projects::Settings::CustomFieldsForm, type: :forms, with_ee: %i[calculated_values] do
let(:string_project_custom_field) do
create(:string_project_custom_field, name: "String field", is_required: true, is_for_all: true)
end
@@ -42,8 +42,7 @@ RSpec.describe OpenProject::CustomFieldFormat do
context "for a 'Project' class" do
context "with some enterprise addons",
with_ee: %i[calculated_values weighted_item_lists custom_field_hierarchies],
with_flag: { calculated_value_project_attribute: true } do
with_ee: %i[calculated_values weighted_item_lists custom_field_hierarchies] do
it_behaves_like "custom field formats",
"Project",
%w[bool calculated_value date float hierarchy int link list string text user version weighted_item_list]
@@ -120,9 +119,7 @@ RSpec.describe OpenProject::CustomFieldFormat do
"excluding hierarchy",
%w[bool date float int link list string text user version empty]
context "with a calculated values ee",
with_ee: [:calculated_values],
with_flag: { calculated_value_project_attribute: true } do
context "with a calculated values ee", with_ee: [:calculated_values] do
it_behaves_like "available custom field formats",
"including calculated values",
%w[bool calculated_value date float int link list string text user version empty]
@@ -140,31 +137,16 @@ RSpec.describe OpenProject::CustomFieldFormat do
end
context "for a 'Project' class" do
context "with feature flags enabled", with_flag: { calculated_value_project_attribute: true } do
it_behaves_like "custom field formats",
"Project",
%w[bool calculated_value date float hierarchy int link list string text user version weighted_item_list]
end
context "with no feature flags enabled", with_flag: {} do
it_behaves_like "custom field formats",
"Project",
%w[bool date float hierarchy int link list string text user version weighted_item_list]
end
it_behaves_like "custom field formats",
"Project",
%w[bool calculated_value date float hierarchy int link list string text user version weighted_item_list]
end
end
describe ".disabled_formats" do
it "returns disabled formats" do
it "returns no disabled formats" do
formats = described_class.disabled_formats
expect(formats).to match_array(%w[calculated_value])
end
context "with feature flags enabled", with_flag: { calculated_value_project_attribute: true } do
it "returns no disabled formats" do
formats = described_class.disabled_formats
expect(formats).to be_empty
end
expect(formats).to be_empty
end
end
end
@@ -31,9 +31,7 @@
require "spec_helper"
require Rails.root.join("db/migrate/20251211160744_set_is_for_all_and_unset_required")
RSpec.describe SetIsForAllAndUnsetRequired, type: :model,
with_ee: %i[calculated_values],
with_flag: { calculated_value_project_attribute: true } do
RSpec.describe SetIsForAllAndUnsetRequired, type: :model, with_ee: %i[calculated_values] do
# Project custom fields to be migrated
shared_let(:required_project_cf) { create(:project_custom_field, :integer, is_required: true, is_for_all: false) }
shared_let(:optional_project_cf) { create(:project_custom_field, :integer, is_required: false, is_for_all: false) }
@@ -30,9 +30,7 @@
require "spec_helper"
RSpec.describe ActsAsCustomizable::CalculatedValue,
with_ee: %i[calculated_values],
with_flag: { calculated_value_project_attribute: true } do
RSpec.describe ActsAsCustomizable::CalculatedValue, with_ee: %i[calculated_values] do
using CustomFieldFormulaReferencing
include CalculatedValues::ErrorsHelper
@@ -30,9 +30,7 @@
require "spec_helper"
RSpec.describe CustomField::CalculatedValue,
with_ee: %i[calculated_values weighted_item_lists],
with_flag: { calculated_value_project_attribute: true } do
RSpec.describe CustomField::CalculatedValue, with_ee: %i[calculated_values weighted_item_lists] do
using CustomFieldFormulaReferencing
subject(:custom_field) { create(:calculated_value_project_custom_field, formula: "1 + 1") }
+2 -6
View File
@@ -204,9 +204,7 @@ RSpec.describe Project, "customizable" do
.to contain_exactly(text_custom_field, bool_custom_field)
end
describe "#valid?",
with_ee: %i[calculated_values],
with_flag: { calculated_value_project_attribute: true } do
describe "#valid?", with_ee: %i[calculated_values] do
let(:another_section) { create(:project_custom_field_section) }
let(:project) do
build(:project, custom_field_values: {
@@ -377,9 +375,7 @@ RSpec.describe Project, "customizable" do
.to eq("bar")
end
describe "#valid?",
with_ee: %i[calculated_values],
with_flag: { calculated_value_project_attribute: true } do
describe "#valid?", with_ee: %i[calculated_values] do
let!(:project) do
create(:project, custom_field_values: {
text_custom_field.id => "foo",
@@ -62,9 +62,7 @@ RSpec.describe CustomFields::CreateService, type: :model do
subject(:instance_call) { instance.call(attributes) }
describe "calculated value custom field",
with_ee: %i[calculated_values],
with_flag: { calculated_value_project_attribute: true } do
describe "calculated value custom field", with_ee: %i[calculated_values] do
using CustomFieldFormulaReferencing
shared_let(:project_custom_field_section) { create(:project_custom_field_section) }
@@ -430,9 +430,7 @@ RSpec.describe CustomFields::Hierarchy::HierarchicalItemService, with_ee: [:cust
end
end
context "with weighted item list and calculated values",
with_ee: %i[calculated_values weighted_item_lists],
with_flag: { calculated_value_project_attribute: true } do
context "with weighted item list and calculated values", with_ee: %i[calculated_values weighted_item_lists] do
current_user { create(:admin) }
let!(:project_using_one) { create(:project) }
@@ -65,9 +65,7 @@ RSpec.describe CustomFields::UpdateService, type: :model do
end
end
describe "calculated value custom field",
with_ee: %i[calculated_values],
with_flag: { calculated_value_project_attribute: true } do
describe "calculated value custom field", with_ee: %i[calculated_values] do
using CustomFieldFormulaReferencing
context "when updating not a calculated value" do
@@ -41,9 +41,7 @@ RSpec.describe ProjectCustomFieldProjectMappings::BulkCreateService do
let(:required_permission) { :select_project_custom_fields }
end
describe "calculated values",
with_ee: %i[calculated_values],
with_flag: { calculated_value_project_attribute: true } do
describe "calculated values", with_ee: %i[calculated_values] do
using CustomFieldFormulaReferencing
shared_let(:user) { create(:admin) }
@@ -190,9 +190,7 @@ RSpec.describe ProjectCustomFieldProjectMappings::BulkUpdateService do
end
end
describe "calculated values",
with_ee: %i[calculated_values],
with_flag: { calculated_value_project_attribute: true } do
describe "calculated values", with_ee: %i[calculated_values] do
using CustomFieldFormulaReferencing
shared_let(:user) { create(:admin) }
@@ -39,9 +39,7 @@ RSpec.describe ProjectCustomFieldProjectMappings::DeleteService do
end
end
describe "calculated values",
with_ee: %i[calculated_values],
with_flag: { calculated_value_project_attribute: true } do
describe "calculated values", with_ee: %i[calculated_values] do
using CustomFieldFormulaReferencing
shared_let(:user) { create(:admin) }
@@ -246,9 +246,7 @@ RSpec.describe ProjectCustomFieldProjectMappings::ToggleService do
end
end
describe "calculated values",
with_ee: %i[calculated_values],
with_flag: { calculated_value_project_attribute: true } do
describe "calculated values", with_ee: %i[calculated_values] do
using CustomFieldFormulaReferencing
shared_let(:user) { create(:admin) }
@@ -267,9 +267,7 @@ RSpec.describe(
end
end
context "with calculated custom fields",
with_ee: %i[calculated_values],
with_flag: { calculated_value_project_attribute: true } do
context "with calculated custom fields", with_ee: %i[calculated_values] do
using CustomFieldFormulaReferencing
let(:integer_custom_field) { create(:integer_project_custom_field, projects: [source]) }
let(:calculated_custom_field) do
@@ -315,9 +313,7 @@ RSpec.describe(
expect(calculated_cv.value).to eq "16"
end
context "with calculation errors",
with_ee: %i[calculated_values],
with_flag: { calculated_value_project_attribute: true } do
context "with calculation errors", with_ee: %i[calculated_values] do
let(:calculated_custom_field) do
create(:calculated_value_project_custom_field, :skip_validations,
projects: [source],
@@ -169,9 +169,7 @@ RSpec.describe Projects::CreateService, type: :model do
end
end
context "with for_all custom fields",
with_ee: %i[calculated_values],
with_flag: { calculated_value_project_attribute: true } do
context "with for_all custom fields", with_ee: %i[calculated_values] do
let!(:calculated_custom_field) do
create(:calculated_value_project_custom_field,
project_custom_field_section: section)
@@ -230,9 +228,7 @@ RSpec.describe Projects::CreateService, type: :model do
end
end
describe "calculated custom fields",
with_ee: %i[calculated_values],
with_flag: { calculated_value_project_attribute: true } do
describe "calculated custom fields", with_ee: %i[calculated_values] do
shared_let(:cf_static) { create(:integer_project_custom_field, is_for_all: true) }
let(:project) { create(:project) }
let!(:model_instance) { project }
@@ -82,9 +82,7 @@ RSpec.describe Projects::UpdateService, type: :model do
end
end
describe "calculated custom fields",
with_ee: %i[calculated_values],
with_flag: { calculated_value_project_attribute: true } do
describe "calculated custom fields", with_ee: %i[calculated_values] do
let(:project) { create(:project) }
let!(:model_instance) { project }
# Remove the set_attributes_service mocking to use the real service.
@@ -31,9 +31,7 @@
require "spec_helper"
RSpec.describe CustomFields::RecalculateValuesJob, type: :model do
describe "#perform",
with_ee: %i[calculated_values],
with_flag: { calculated_value_project_attribute: true } do
describe "#perform", with_ee: %i[calculated_values] do
using CustomFieldFormulaReferencing
shared_let(:user) { create(:admin) }