Project

General

Profile

Defect #6324 » 0001-Defer-plugin-requirements-evaluation.patch

Takashi Kato, 2023-04-25 00:31

View differences:

lib/redmine/plugin.rb
78 78
      end
79 79
    end
80 80
    def_field :name, :description, :url, :author, :author_url, :version, :settings, :directory
81
    attr_reader :id
81
    attr_reader :id, :requirements
82 82

  
83 83
    # Plugin constructor: instanciates a new Redmine::Plugin with given +id+
84 84
    # and make it evaluate the given +block+
......
169 169
      registered_plugins[id.to_sym].present?
170 170
    end
171 171

  
172
    def self.validate
173
      registered_plugins.each_value(&:validate)
174
    end
175

  
172 176
    def initialize(id)
173 177
      @id = id.to_sym
178
      @requirements = {}
174 179
    end
175 180

  
176 181
    def public_directory
......
269 274
    #   requires_redmine_plugin :foo, :version => '0.7.3'              # 0.7.3 only
270 275
    #   requires_redmine_plugin :foo, :version => ['0.7.3', '0.8.0']   # 0.7.3 or 0.8.0
271 276
    def requires_redmine_plugin(plugin_name, arg)
277
      @requirements[plugin_name] = ->{ validate_plugin_requirement(plugin_name, arg) }
278
    end
279

  
280
    def validate_plugin_requirement(plugin_name, arg)
272 281
      arg = {:version_or_higher => arg} unless arg.is_a?(Hash)
273 282
      arg.assert_valid_keys(:version, :version_or_higher)
274 283

  
......
305 314
      end
306 315
      true
307 316
    end
317
    private :validate_plugin_requirement
318

  
319
    def validate
320
      requirements.each_value(&:call)
321
    end
308 322

  
309 323
    # Adds an item to the given +menu+.
310 324
    # The +id+ parameter (equals to the project id) is automatically added to the url.
lib/redmine/plugin_loader.rb
105 105
      add_autoload_paths
106 106

  
107 107
      Rails.application.config.to_prepare do
108
        PluginLoader.directories.each(&:run_initializer)
108
        Redmine::PluginLoader.run_initializer
109
        Redmine::Plugin.validate
109 110

  
110 111
        Redmine::Hook.call_hook :after_plugins_loaded
111 112
      end
112 113
    end
113 114

  
115
    def self.run_initializer
116
      directories.each(&:run_initializer)
117
    end
118

  
114 119
    def self.setup
115 120
      @plugin_directories = []
116 121

  
test/fixtures/plugin_dependencies/a_plugin/init.rb
1
# frozen_string_literal: true
2

  
3
Redmine::Plugin.register :a_plugin do
4
  requires_redmine_plugin :d_plugin, '0.1.0'
5
  version '0.1.0'
6
end
test/fixtures/plugin_dependencies/b_plugin/init.rb
1
# frozen_string_literal: true
2

  
3
Redmine::Plugin.register :b_plugin do
4
  requires_redmine_plugin :d_plugin, '0.1.0'
5
  version '0.1.0'
6
end
test/fixtures/plugin_dependencies/c_plugin/init.rb
1
# frozen_string_literal: true
2

  
3
Redmine::Plugin.register :c_plugin do
4
  requires_redmine_plugin :a_plugin, '0.1.0'
5
  requires_redmine_plugin :b_plugin, '0.1.0'
6
end
test/fixtures/plugin_dependencies/d_plugin/init.rb
1
# frozen_string_literal: true
2

  
3
Redmine::Plugin.register :d_plugin do
4
  version '0.1.0'
5
end
test/unit/lib/redmine/plugin_test.rb
174 174
      test.assert requires_redmine_plugin(:other_plugin, other_version)
175 175
      test.assert_raise Redmine::PluginRequirementError do
176 176
        requires_redmine_plugin(:other_plugin, :version_or_higher => '99.0.0')
177
        validate
177 178
      end
178 179
      test.assert requires_redmine_plugin(:other_plugin, :version => other_version)
179 180
      test.assert requires_redmine_plugin(:other_plugin, :version => [other_version, '99.0.0'])
180 181
      test.assert_raise Redmine::PluginRequirementError do
181 182
        requires_redmine_plugin(:other_plugin, :version => '99.0.0')
183
        validate
182 184
      end
183 185
      test.assert_raise Redmine::PluginRequirementError do
184 186
        requires_redmine_plugin(:other_plugin, :version => ['98.0.0', '99.0.0'])
187
        validate
185 188
      end
186 189
      # Missing plugin
187 190
      test.assert_raise Redmine::PluginRequirementError do
188 191
        requires_redmine_plugin(:missing, :version_or_higher => '0.1.0')
192
        validate
189 193
      end
190 194
      test.assert_raise Redmine::PluginRequirementError do
191 195
        requires_redmine_plugin(:missing, '0.1.0')
196
        validate
192 197
      end
193 198
      test.assert_raise Redmine::PluginRequirementError do
194 199
        requires_redmine_plugin(:missing, :version => '0.1.0')
200
        validate
195 201
      end
196 202
    end
197 203
  end
198 204

  
205
  def test_requires_redmine_plugin_dependencies
206
    @klass.clear
207
    @klass.directory = Rails.root.join('test/fixtures/plugin_dependencies')
208
    Redmine::PluginLoader.directory = @klass.directory
209
    Redmine::PluginLoader.setup
210
    Redmine::PluginLoader.run_initializer
211
    Redmine::Plugin.validate
212
    assert_equal 4, Redmine::Plugin.registered_plugins.keys.size
213
  end
214

  
199 215
  def test_default_settings
200 216
    @klass.register(:foo_plugin) {settings :default => {'key1' => 'abc', :key2 => 123}}
201 217
    h = Setting.plugin_foo_plugin
(8-8/8)