Problem/Motivation

At the moment it is only possible to create an image derivative starting from a file URI. It would be good to have the possibility to do it from an already instantiated Image object. template_preprocess_image_style_preview() is e.g. getting an Image object, then handing over its source path to createDerivative() which just opens another Image instance for the same file. Also, in contrib you may want to create an Image programmatically and apply an image style to it without having to flush it to disk before.

Proposed resolution

Add two methods to ImageStyle, apply and applyAndSave. Final names of the methods to be decided (see comments #17.4, 21, 22, 23).

Remaining tasks

  • decide on how to introduce the two new methods, new interface or no interface (see comment #25)
  • decide on the methods' names (see comments #17.4, 21, 22, 23)
  • draft change record

User interface changes

None

API changes

Two methods added.

Comments

mondrake’s picture

Status: Active » Needs review
StatusFileSize
new3.53 KB

Patch.

Status: Needs review » Needs work

The last submitted patch, 1: 2359443_1.patch, failed testing.

mondrake’s picture

StatusFileSize
new4.4 KB
new1.46 KB

Fixed failure and changed a test to use createDerivativeFromImage() so that this method is tested explicilty

mondrake’s picture

Status: Needs work » Needs review

go bot

claudiu.cristea’s picture

Great idea and looks good.

+++ b/core/modules/image/src/Entity/ImageStyle.php
@@ -271,6 +272,14 @@ public function flush($path = NULL) {
+    $image = \Drupal::service('image.factory')->get($original_uri);

Not possible to inject?

mondrake’s picture

#5 from a quick research it may be possible to implement EntityHandlerInterface to ImageStyle: its createInstance method should be able to get the container and pass to the constructor individual services. A bit like ContainerFactoryPluginInterface for plugins.

But I'd leave that to a separate followup issue.

fietserwin’s picture

Status: Needs review » Needs work

Your idea is good, The current createDerivative() does too many things in 1 method, making it indeed hard to reuse functionality in unforeseen ways. However, I think that the new method should be named apply() (conforming with the image - toolkit - operation naming) or applyStyle() (conforming with applyEffect() on ImageEffect). I prefer the first, as IMO the latter should also be renamed to apply() (for reasons of consistency and DRY: do not repeat the name of the class on method names). This would be perfectly consistent as all apply() methods accept an ImageInterface as 1st argument (except on ImageInterface itself of course).

Regarding the comment in #5 and the answer in #6: I prefer to do it correct the 1st time, the patch will remain small and reviewable and as we are already in beta, structural/creational choices should be done correct by now.

Can we create a follow-up for ImageEfect?

mondrake’s picture

Version: 8.0.x-dev » 8.1.x-dev
Category: Task » Feature request

Changing to feature request and hence to 8.1.x queue.

mondrake’s picture

Status: Needs work » Postponed
mondrake’s picture

Version: 8.1.x-dev » 8.0.x-dev
Status: Postponed » Needs review
Issue tags: +Needs issue summary update
StatusFileSize
new22.42 KB
new22.41 KB

For later 8.1.x discussions...

This patch:

  • injects services in the constructor as per #5 - hence removed the procedural wrapper for file_uri_scheme (see also #2527726: Remove wrapper to procedural function in ImageStyle), other wrappers, adjusted PHPUnit tests, and changed deprecated functions file_uri_scheme and drupal_dirname to the new OO methods
  • per #7, changed from ::createDerivativeFromImage() to two methods ::applyAndSave, equivalent to ::createDerivativeFromImage(), and ::apply which just applies the effects to the Image object without IO
  • with that, the two only uses of ::createDerivative in non-test code have been optimised using the new ::applyAndSave method - since the image after saving has the relevant information 'fresh', there is no purpose to fetch the derivative image from the file system again just to get it. So I suggest to mark ::createDerivative for deprecation and keep it in 8 cycle for BC.
  • the uses of ::createDerivative in test-code: one I changed here to test ::applyAndSave, the others can be removed here or in a follow up
mondrake’s picture

Version: 8.0.x-dev » 8.1.x-dev
Status: Needs review » Postponed
mondrake’s picture

Status: Postponed » Needs review
mondrake’s picture

StatusFileSize
new22.34 KB

Reroll.

claudiu.cristea’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests, +Needs change record, +Performance

This is a nice change, I agree.

  1. +++ b/core/modules/image/image.admin.inc
    @@ -32,11 +32,11 @@ function template_preprocess_image_style_preview(&$variables) {
    +  $image = $image_factory->get($original_path);
    
    @@ -51,13 +51,15 @@ function template_preprocess_image_style_preview(&$variables) {
    +  else {
    +    $image = $image_factory->get($preview_file);
       }
    -  $preview_image = $image_factory->get($preview_file);
    

    Oh, very nice! This also deserves a 'performance' tag?

  2. +++ b/core/modules/image/src/Controller/ImageStyleDownloadController.php
    @@ -163,16 +163,23 @@ public function deliver(Request $request, $scheme, ImageStyleInterface $image_st
    +    if (file_exists($derivative_uri)) {
    ...
    +    else {
    +      // Generate the derivative image.
    +      $image = $this->imageFactory->get($image_uri);
    +      $success = $image_style->applyAndSave($image, $derivative_uri);
    +    }
    ...
         if ($success) {
    -      $image = $this->imageFactory->get($derivative_uri);
    

    So, in this case $image is the original image, right? Then inside if ($success) {...} we'll send headers with info from the original image pretending that is the derivative?

  3. +++ b/core/modules/image/src/Entity/ImageStyle.php
    @@ -94,6 +100,68 @@ class ImageStyle extends ConfigEntityBase implements ImageStyleInterface, Entity
    +  public function __construct(array $values, $entity_type, FileSystemInterface $file_system = NULL, ImageFactory $image_factory = NULL, PluginManagerInterface $image_effect_plugin_manager = NULL, StreamWrapperManagerInterface $stream_wrapper_manager = NULL, PrivateKey $private_key = NULL) {
    ...
    +    $this->fileSystem = $file_system ?: \Drupal::service('file_system');
    +    $this->imageFactory = $image_factory ?: \Drupal::service('image.factory');
    +    $this->effectManager = $image_effect_plugin_manager ?: \Drupal::service('plugin.manager.image.effect');
    +    $this->streamWrapperManager = $stream_wrapper_manager ?: \Drupal::service('stream_wrapper_manager');
    +    $this->privateKey = $private_key ?: \Drupal::service('private_key');
    

    Sorry, it's my fault from #5. We cannot do that because we are initialising all the services in constructor and maybe we don't need them every time. Let's use the static \Drupal::whatever() or, better, we can create some getters. See how \Drupal\editor\Editor::editorPluginManager() is used to lazy load the plugin.manager.editor service.

  4. +++ b/core/modules/image/src/Entity/ImageStyle.php
    @@ -177,7 +245,7 @@ protected static function replaceImageStyle(ImageStyleInterface $style) {
    -    $scheme = $this->fileUriScheme($uri);
    +    $scheme = $this->fileSystem->uriScheme($uri);
    
    @@ -205,7 +273,7 @@ public function buildUrl($path, $clean_urls = NULL) {
    -      $original_uri = file_uri_scheme($path) ? file_stream_wrapper_uri_normalize($path) : file_build_uri($path);
    +      $original_uri = $this->fileSystem->uriScheme($path) ? file_stream_wrapper_uri_normalize($path) : file_build_uri($path);
    
    @@ -225,8 +293,8 @@ public function buildUrl($path, $clean_urls = NULL) {
    -    if ($clean_urls === FALSE && file_uri_scheme($uri) == 'public' && !file_exists($uri)) {
    -      $directory_path = \Drupal::service('stream_wrapper_manager')->getViaUri($uri)->getDirectoryPath();
    +    if ($clean_urls === FALSE && $this->fileSystem->uriScheme($uri) == 'public' && !file_exists($uri)) {
    +      $directory_path = $this->streamWrapperManager->getViaUri($uri)->getDirectoryPath();
    
    @@ -253,7 +321,7 @@ public function flush($path = NULL) {
    -    $wrappers = \Drupal::service('stream_wrapper_manager')->getWrappers(StreamWrapperInterface::WRITE_VISIBLE);
    +    $wrappers = $this->streamWrapperManager->getWrappers(StreamWrapperInterface::WRITE_VISIBLE);
    
    @@ -330,7 +424,7 @@ public function getDerivativeExtension($extension) {
    -    return substr(Crypt::hmacBase64($this->id() . ':' . $this->addExtension($uri), $this->getPrivateKey() . $this->getHashSalt()), 0, 8);
    +    return substr(Crypt::hmacBase64($this->id() . ':' . $this->addExtension($uri), $this->privateKey->get() . $this->getHashSalt()), 0, 8);
    
    @@ -354,7 +448,7 @@ public function getEffect($effect) {
    -      $this->effectsCollection = new ImageEffectPluginCollection($this->getImageEffectPluginManager(), $this->effects);
    +      $this->effectsCollection = new ImageEffectPluginCollection($this->effectManager, $this->effects);
    
    @@ -399,26 +493,6 @@ public function setName($name) {
    -  protected function getImageEffectPluginManager() {
    -    return \Drupal::service('plugin.manager.image.effect');
    -  }
    ...
    -  protected function getPrivateKey() {
    -    return \Drupal::service('private_key')->get();
    -  }
    
    @@ -454,26 +528,6 @@ protected function addExtension($path) {
    -  protected function fileUriScheme($uri) {
    -    return file_uri_scheme($uri);
    -  }
    

    No, please! Are unrelated to this issue. Let's open another issue to handle those case.

  5. +++ b/core/modules/image/src/ImageStyleInterface.php
    @@ -113,10 +114,51 @@ public function flush($path = NULL);
    +   * @deprecated as of Drupal 8.1.0, will be removed in Drupal 9.0.0.
    

    I think, "... will be removed before Drupal 9.0.0." is more appropriate.

Overall:

  1. Revert changes not related to this issue. Open a followup for the other issue.
  2. We need a test to prove that we can create a derivative from a resource without having the original on disk.
  3. I grepped for 'createDerivative' and there are not too many occurrences in core, so let's convert them in this patch.
  4. We need a change notice. Draft for now.
  5. Followup to remove createDerivative() in 9.x?
mondrake’s picture

#14:

thanks for review @claudiu.cristea.

1. Revert changes not related to this issue. Open a followup for the other issue.

Done, added #2629600: Remove deprecated function calls from ImageStyle

2. We need a test to prove that we can create a derivative from a resource without having the original on disk.

Added.

3. I grepped for 'createDerivative' and there are not too many occurrences in core, so let's convert them in this patch.

Done.

4. We need a change notice. Draft for now.

Not done.

5. Followup to remove createDerivative() in 9.x?

Opened #2629598: Remove ImageStyle::createDerivative.

So, in this case $image is the original image, right? Then inside if ($success) {...} we'll send headers with info from the original image pretending that is the derivative?

$image opens with the original image, but after applyAndSave it has all the properties aligned to the derivative that was saved. See also the new test.

mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new20.78 KB
new15.16 KB

...and the patch...

claudiu.cristea’s picture

Status: Needs review » Needs work
Issue tags: -Needs tests
  1. +++ b/core/modules/image/src/Entity/ImageStyle.php
    @@ -309,6 +320,23 @@ public function createDerivative($original_uri, $derivative_uri) {
    +    // Apply the effects to the image object.
    +    foreach ($this->getEffects() as $effect) {
    +      $effect->applyEffect($image);
    +    }
    ...
    +    return TRUE;
    

    Only now I see this crap. So ImageEffectInterface::applyEffect() does return a success flag but we are not using it here. We just return TRUE regardless if the effects were applied correct. Is there a good reason for this? I don't remember. If there's a reason, we need to document it, otherwise we need something like:

    if (!$effect->applyEffect($image)) {
      return FALSE;
    }
    
  2. +++ b/core/modules/image/src/Entity/ImageStyle.php
    @@ -508,4 +536,23 @@ protected function fileDefaultScheme() {
    +  protected function getImageFactory() {
    +    return \Drupal::service('image.factory');
    +  }
    ...
    +  protected function getFileSystem() {
    +    return \Drupal::service('file_system');
    +  }
    

    So, we're not caching like in \Drupal\editor\Editor::editorPluginManager() in a protected variable? In the case the service is requested more than once per request, is there a cost to call again \Drupal::service()? I'm not sure, I think no and maybe there's no need to the protected cache var. Opinions?

  3. +++ b/core/modules/image/src/Tests/FileMoveTest.php
    @@ -36,7 +36,7 @@ function testNormal() {
    +    $style->applyAndSave(\Drupal::service('image.factory')->get($original_uri), $derivative_uri);
    
    @@ -52,4 +52,43 @@ function testNormal() {
    +    $image = \Drupal::service('image.factory')->get();
    ...
    +    $image = \Drupal::service('image.factory')->get($derivative_uri);
    
    +++ b/core/modules/image/src/Tests/ImageAdminStylesTest.php
    @@ -394,7 +394,7 @@ public function testFlushUserInterface() {
    +    $this->assertTrue($style->applyAndSave(\Drupal::service('image.factory')->get($image_uri), $derivative_uri));
    
    +++ b/core/modules/image/src/Tests/ImageStyleFlushTest.php
    @@ -31,7 +31,7 @@ function createSampleImage($style, $wrapper) {
    +    $derivative = $style->applyAndSave(\Drupal::service('image.factory')->get($source_uri), $derivative_uri);
    
    +++ b/core/modules/responsive_image/src/Tests/ResponsiveImageFieldDisplayTest.php
    @@ -276,7 +276,7 @@ protected function doTestResponsiveImageFieldFormatters($scheme, $empty_styles =
    +    $large_style->applyAndSave(\Drupal::service('image.factory')->get($image_uri), $large_style->buildUri($image_uri));
    
    @@ -501,7 +501,7 @@ private function assertResponsiveImageFieldFormattersLink($link_type) {
    +    $large_style->applyAndSave(\Drupal::service('image.factory')->get($image_uri), $large_style->buildUri($image_uri));
    

    In tests the container is available:

    $this->container->get('image.factory')->...
    </li>
    
  4. +++ b/core/modules/image/src/ImageStyleInterface.php
    @@ -113,10 +114,51 @@ public function flush($path = NULL);
    +   * Applies the style to an Image object.
    ...
    +   * Alter the source image applying all image effects.
    ...
    +  public function apply(ImageInterface $image);
    
    $image opens with the original image, but after applyAndSave it has all the properties aligned to the derivative that was saved.

    I'm not sure now that 'apply' verb is the best choice. We generally have the $image (the subject) and we 'apply' (the verb) something on it. See $image->apply('crop') —­ this makes perfectly sense. Here, the logic is reverted. "something" (image style) is the subject. Im not sure about the naming... Can we reflect more on this?

  5. +++ b/core/modules/image/src/Tests/FileMoveTest.php
    @@ -52,4 +52,43 @@ function testNormal() {
    +    $this->assertEqual($image->getFileSize(), NULL);
    ...
    +    $this->assertEqual($image->getFileSize(), NULL);
    

    We have $this->assertNull().

  6. +++ b/core/modules/image/src/Tests/FileMoveTest.php
    @@ -52,4 +52,43 @@ function testNormal() {
    +    $this->assertTrue(file_exists($derivative_uri), 'Derivative image is generated successfully.');
    

    This is just a recommendation: messages in assertions are obsolete.

mondrake’s picture

Issue summary: View changes
Status: Needs work » Needs review
StatusFileSize
new6.24 KB
new15.76 KB

Thanks @claudiu.cristea for #17.

1. The point is if we want to stop the derivative generation as soon as any effect fails, or (like now), just run all effects regardless of their failure, with each effect logging its own failure. A change here would be out of scope of this issue IMO. Let's have a separate issue for that, please.

2. Done like in Editor.

3. Done.

4. Any suggestion?

5. Done

6. OK, removed.

So to summarise remaining steps:

  • decide on the methods' names
  • update issue summary
  • draft change record
claudiu.cristea’s picture

The point is if we want to stop the derivative generation as soon as any effect fails, or (like now), just run all effects regardless of their failure, with each effect logging its own failure. A change here would be out of scope of this issue IMO. Let's have a separate issue for that, please.

I agree that this is off-topic. Also, I guess we still want to "show something" instead of nothing but also in this case we may want to return $image->isValid();.

OK, let's discuss this elsewhere.

mondrake’s picture

Re. #19, filed #2630224: ImageStyle::createDerivative should return fail if one of the style's effects fails.

(BTW I am fully in favour of #17.1 - IMHO we should not have a derivative at all if an effect fails - better that than a half baked derivative...)

claudiu.cristea’s picture

->applyToImage() ?

claudiu.cristea’s picture

I think, better: ->applyTo() and ->applyToAndSave(). What you think?

fietserwin’s picture

IMO, apply() is perfectly OK.

Most standard OO guidelines will tell us:
- method names are concise and clear.
- the combination of method name with object type and the name and type of arguments should be complete. Thus createDerivative() seems OK as create() alone is not enough.
- methods are preferably named using a single verb that tells what the object is doing (to or using the arguments of the method). Thus apply() is OK: the image style applies its effect to the (image) argument.
- method names do not repeat the type of the argument, thus not applyToImage() (or the shorter incomplete applyTo() that leaves out the type of the argument but still tries to connect the verb to the argument).
- method names that have 2 verbs indicate that the method does too much. Thus applyToAndSave() indicates that it would be better to split the method in a separate apply() and save() (I didn't look at the code if that is the case here).

Moreover, in this case we once decided that for consistency we would name all methods in the apply chain apply(). So better stick with that.

mondrake’s picture

Different problem now. We cannot add new methods to existing interfaces, not even in minor releases, it's a BC-break. See #2630242-6: Provide methods to retrieve EXIF image information via the Image object and following, and #1826362-46: ImageEffects of the same image style should be able to pass variables between them. Not sure how to deal with this now - a new interface just for the two methods?

EDIT - and if a new interface be, what name to give to it?

claudiu.cristea’s picture

Status: Needs review » Needs work

#24 is correct. I see two options:

  1. Create a new interface ImageStyleActionsInterface and make ImageStyle implements also ImageStyleActionsInterface. Add next statements into docblock of this interface: "@deprecated in Drupal 8.1.x, will be merged into \Drupal\image\ImageStyleInterface in Drupal 9.0.x" and "@todo Remove this interface and merge its methods into \Drupal\image\ImageStyleInterface in 9.0.x".
  2. Remove the methods from the interface, move their docblocks to ImageStyle and add "@todo Add this method to \Drupal\image\ImageStyleInterface in Drupal 9.0.x."

Which one? Maybe we should ask a core committer?

mondrake’s picture

Issue summary: View changes

Updated issue summary, with what's open for decision/discussion.

Re. methods' names, I am also in favor of keeping apply() and applyAndSave() as @fietserwin suggests.

@fietserwin re. #23:

applyToAndSave() indicates that it would be better to split the method in a separate apply() and save()

we already have an ImageStyle::save() method, which is used to save the ImageStyle configuration to storage - here the 'save' of the 'applyAndSave' is referring to the Image after 'application' of the style.

In fact I start to think that we should have a separate service where Image and ImageStyle are input to the building of the image derivative - rather than having all the logic into the ImageStyle config entity itself. But that would be something for D9 I believe.

mondrake’s picture

fietserwin’s picture

#24: technically correct, but I think this will result in nobody being able to:
- add new features unless we are talking completely self contained modules.
- refactor code, other then at the level of renaming internal variables and such.
- improve naming and staying BC by keeping the old method (explicit example in the docs about staying BC)
- extract services, out of existing code and referring to it.

Furthermore we are talking about:
- (IMO) a (to be) @internal API (https://www.drupal.org/node/2116841, https://www.drupal.org/node/2550249). I don't think that ImageStyleInterface is implemented in contrib by bypassing the ImageStyle core class (I even think it is not implemented at all in contrib)
- Not a disruptive change.

But let's indeed ask a core committer about the current consensus on this.

If the Interface has to remain locked for the whole D8 life cycle, I would go for the 1st option from @25 but not using @deprecated as there is no alternative so it doesn't make sense to have our IDEs warn us about something we can't change anyway.

[EDIT, crossposted]
re #26: If you can extract all this into a separate class, I would call that a new feature being allowed in a minor release.

mondrake’s picture

Status: Needs work » Needs review
StatusFileSize
new15.78 KB

Rerolled.

mondrake’s picture

Status: Needs review » Needs work

back to NW per #25

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.0-beta1 was released on March 2, 2016, which means new developments and disruptive changes should now be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.0-beta1 was released on August 3, 2016, which means new developments and disruptive changes should now be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.