Problem/Motivation

Currently, Drupal.org and various communication channels inform site owners of when the next important (and possibly more difficult) minor version update is scheduled, but this information is not available within Drupal itself.

In #2909665: [plan] Extend security support to cover the previous minor version of Drupal, we want to extended security coverage for the pervious minor version of Drupal for an extra release, so that if (e.g.) 8.6.2 is created with a security advisory in October, the security fixes in the advisory will be backported to (e.g.) 8.5.7, so that the site owner has more time to test minor updates while still keeping their site secure.

So for example the Drupal core minor 9.0.x would be supported until 9.2.0 is released and 9.1.x is supported until 9.3.x. This information is not available inside Drupal.

For Drupal releases before a new Drupal major this will different. For example 8.8.x will be supported until December 2, 2020 and 8.9.x, the LTS release will be supported until November 2021. This information also not available until inside Drupal

Related: This issue has some similarities to #2766491: Update status should indicate whether installed contributed projects receive security coverage, but it is not the same. That issue is about whether or not the whole contributed project has opted into security team support; this issue is about which minor versions of core currently have security team support.

Proposed resolution

Indicate to the site owner when:

  1. The site's minor version of Drupal core will have security coverage until a specific version of Drupal is released. This will be 2 minor releases. For instance if 9.0.2 is installed the will have security coverage until 9.2.0 is released
  2. The site receives security coverage but when the next minor version of Drupal is release their coverage will end. For example they are on 9.0.10 and 9.1.17 is the latest release. When 9.2.0 is released
    9.0.x will no longer receive security coverage.
  3. The site does not receive any support and they should update as soon as possible to have security coverage. They are on 9.0.10 and 9.2.0 has already been released.

Special logic for the minor releases 8.8.x and 8.9.x.

  1. 8.8.x will have security coverage until 2020-12-02. Sites on 8.8.x should be warned that they should update as soon as possible on 2020-6-02(this is that same as if they had 1 minor release to update)
  2. 8.9.x is the LTS release for Drupal. It will receive coverage until 2021-11-01. Sites on 8.9.x will not receive a update as soon as possible warning 6 months before the LTS term ends

Completed tasks

  1. Followup regarding the last minor of a release and/or the next major release (might be noted on #2608062: [META] Requirements for tagging Drupal 9.0.0-alpha1): #2998287: Provide accurate information on the security coverage of the 8.x final minor and LTS, and recommend updating to the next major version when appropriate
  2. Followup for potentially including minor coverage info/dates in the d.o XML data, rather than relying solely on the "supported minors" constant and handbook page: #2998285: Add information on later releases to updates.drupal.org
  3. Followup to discuss whether this should also add anything to the "General system information" header at the top: #2998289: Make security coverage more prominent on the Status Report
  4. Followup to discuss email notifications of being out of security coverage: #2998292: Send email when installed version no longer receives security coverage
  5. Followup #3107378: Deprecate hard-coded Drupal 8 dates from update logic for the status report once this information is provided by the infrastructure
  6. Followup #3110182: Provide localized date formatting in message about security coverage for the site's installed final 8.x or LTS releases
  7. Followup #3110186: Simplify the wording of messages on the status report about security coverage for the site's installed minor version
  8. Followup #3111463: Improve code documentation for \Drupal\update\ProjectSecurityData

Remaining tasks

User interface changes

Message screenshots
Minor 8.2. is supported, no warning. Next minor has not come out.
minor supported no warning
Minor 8.1 is supported, warning. Next minor 8.2 has come out

Minor 8.0 is unsupported. 8.2 has come out

Minor 8.8 supported based on date, no warning

Minor 8.8 , supported based on date, warning because within 6 months of support being over

Minor 8.8 , not supported based on date,

Minor 8.9 supported based on date, no warning. No warning will show based on nearness of support being over

Minor 8.9, support over

API changes

None

Data model changes

None

Release note snippet

Starting with Drupal 8.8.3, the status report will display a message about the security coverage for the current minor version. Drupal 8.8.x will receive security coverage until December 2, 2020.

CommentFileSizeAuthor
#248 diff-229-246.txt469 bytesbenjifisher
#246 2991207-246-8.8.patch56.46 KBtedbow
#243 2991207-8.8-243.patch73.87 KBtedbow
#243 interdiff-reroll-229-243.txt27.38 KBtedbow
#240 2991207-240.update.install.rej_.txt415 bytesdww
#240 2991207.229_240.rawdiff.txt1.36 KBdww
#240 2991207-240.8_8_x.patch56.42 KBdww
#232 2991207.229_232.interdiff.txt4.22 KBdww
#232 2991207-232.with-3111463.patch58.08 KBdww
#229 2991207-229.patch56.51 KBtedbow
#229 interdiff-225-229.txt1.34 KBtedbow
#225 2991207-225.patch56.44 KBtedbow
#225 interdiff-224-225.txt2.56 KBtedbow
#224 2991207-224.patch55.87 KBtedbow
#224 interdiff-223-224.txt5.17 KBtedbow
#223 2991207-222.patch57.25 KBtedbow
#223 interdiff-208-222.txt10.46 KBtedbow
#208 2991207-208.patch57.09 KBtedbow
#208 interdiff-207-208.txt4.08 KBtedbow
#207 2991207-207.patch57.2 KBtedbow
#207 interdiff-203-207.txt831 bytestedbow
#203 2991207-203.patch57.4 KBtedbow
#203 interdiff-202-203.txt4.63 KBtedbow
#202 2991207-202.patch57.78 KBtedbow
#202 interdiff-201-202.txt20.96 KBtedbow
#201 2991207-201.patch64.04 KBtedbow
#201 interdiff-197-201.txt4.22 KBtedbow
#197 2991207-197.patch64.03 KBtedbow
#197 interdiff-195-197.txt17.55 KBtedbow
#195 2991207-195.patch63.21 KBtedbow
#195 interdiff-193-195.txt975 bytestedbow
#193 2991207-193.patch63.17 KBtedbow
#193 interdiff-188-193.txt7.04 KBtedbow
#188 2991207-188.patch63.23 KBtedbow
#188 interdiff-179-188.txt977 bytestedbow
#188 minor_warning_fixed.png95.75 KBtedbow
#187 minor_unsupported.png92.78 KBtedbow
#187 minor_warning.png96.16 KBtedbow
#187 minor_supported.png56.84 KBtedbow
#187 minor_88_supported.png55.01 KBtedbow
#187 minor_88_warning.png82.52 KBtedbow
#187 minor_88_unsupported.png93.48 KBtedbow
#187 minor89_supported.png56.28 KBtedbow
#187 minor_89_unsupported.png92.71 KBtedbow
#184 2991207.183_184.interdiff.txt743 bytesdww
#184 2991207-184.WITH-3110223.DO-NOT-COMMIT.patch70.7 KBdww
#184 2991207-184.NEEDS-3110223.DO-NOT-TEST-YET.patch62.84 KBdww
#183 2991207.178_183.interdiff.txt2.3 KBdww
#183 2991207-183.WITH-3110223.DO-NOT-COMMIT.patch70.7 KBdww
#183 2991207-183.NEEDS-3110223.DO-NOT-TEST-YET.patch62.84 KBdww
#179 2991207-178.patch63.23 KBtedbow
#179 interdiff-172-178.txt14.55 KBtedbow
#172 2991207-171.patch62.68 KBtedbow
#172 interdiff-170-171.txt1.91 KBtedbow
#170 2991207-170.patch62.68 KBtedbow
#170 interdiff-168-170.txt5.86 KBtedbow
#168 2991207-167.patch62.44 KBtedbow
#168 interdiff-164-167.txt786 bytestedbow
#164 2991207-164.patch62.44 KBtedbow
#164 interdiff-163-164.txt2.25 KBtedbow
#163 interdiff.txt451 bytesgábor hojtsy
#163 2991207-163.patch62.29 KBgábor hojtsy
#161 2991207-161.patch62.24 KBtedbow
#161 interdiff-156-161.txt20.82 KBtedbow
#156 2991207-156.patch60.34 KBtedbow
#156 interdiff-152-156.txt3.34 KBtedbow
#152 interdiff-147-152.txt10.01 KBtedbow
#152 2991207-152.patch59.77 KBtedbow
#147 2991207-147.patch59.46 KBtedbow
#147 interdiff-132-147.txt15.39 KBtedbow
#146 8.8.x-support.png121.6 KBtedbow
#142 2991207-142.patch45.61 KBtedbow
#142 interdiff-132-142.txt20.35 KBtedbow
#135 2991207-132-8.8.x.patch58.43 KBtedbow
#132 2991207-132.patch58.51 KBspokje
#128 2991207-128.patch58.47 KBbnjmnm
#128 interdiff_125-128.txt2.73 KBbnjmnm
#125 interdiff-120-125.txt570 bytesspokje
#125 2991207-125.patch58.47 KBspokje
#120 2991207-120.patch58.47 KBtedbow
#120 interdiff-111-120.txt23.13 KBtedbow
#116 interdiff-non-test-107-113.txt1.49 KBtedbow
#114 2991207-110-assert-fix-only-FAIL.patch63.13 KBtedbow
#113 2991207-111.patch60.97 KBtedbow
#113 2991207-110-assert-fix-only-FAIL.patch63.24 KBtedbow
#111 2991207-110.patch61.04 KBtedbow
#111 interdiff-107-110a.txt10.23 KBtedbow
#111 interdiff-assert-fix-only.txt5.17 KBtedbow
#111 2991207-110-assert-fix-only-FAIL.patch63.27 KBtedbow
#107 2991207-107.patch60.63 KBtedbow
#107 interdiff-104-106.txt1.7 KBtedbow
#104 2991207-104.patch60.59 KBtedbow
#104 interdiff-102-104.txt2.48 KBtedbow
#102 2991207-102.patch60.23 KBtedbow
#102 interdiff-99-103.txt20.4 KBtedbow
#96 coverage_8.9_after_2021-11-01.png26.94 KBtedbow
#96 coverage_8.9.png15.81 KBtedbow
#96 coverage_8.8.png15.89 KBtedbow
#96 coverage_8.8_after_6_2_2020.png22.03 KBtedbow
#96 coverage_8.7_most_recent_8.7.png21.06 KBtedbow
#96 coverage_8.6_most_recent_8.7.png33.29 KBtedbow
#96 coverage_8.5_most_recent_8.7_no_coverage.png33.66 KBtedbow
#94 2991207-94.patch50.77 KBtedbow
#94 interdiff-93-94.txt7.76 KBtedbow
#93 2991207-93.patch53.7 KBtedbow
#93 interdiff-92-93.txt1.47 KBtedbow
#92 2991207-91.patch53.62 KBtedbow
#92 interdiff-89-92.txt12.61 KBtedbow
#89 2991207-89.patch54.47 KBtedbow
#89 interdiff-87-89.txt4.91 KBtedbow
#89 drupal.coreupdate.xml_.txt177.37 KBtedbow
#87 2991207-87.patch54.45 KBtedbow
#87 interdiff-85-87.txt5.79 KBtedbow
#85 2991207-85.patch53.55 KBtedbow
#85 interdiff-82-85.txt13.09 KBtedbow
#82 2991207-82.patch53.36 KBtedbow
#82 interdiff-77-82.txt34.45 KBtedbow
#77 2991207-77.patch52 KBtedbow
#77 interdiff-75-77.txt1.88 KBtedbow
#75 2991207-75.patch51.96 KBtedbow
#75 interdiff-66-75.txt30.97 KBtedbow
#74 2991207-74.patch52.08 KBtedbow
#74 interdiff-66-74.txt31.25 KBtedbow
#67 2991207-67.patch65.55 KBtedbow
#67 interdiff-66-67.txt34.14 KBtedbow
#66 2991207-66.patch37.78 KBtedbow
#66 interdiff-66.txt10.45 KBtedbow
#65 2991207-65.patch37.58 KBtedbow
#65 interdiff-61-65.txt14.38 KBtedbow
#61 2991207-61.patch36.94 KBtedbow
#61 interdiff-57-61.txt6.6 KBtedbow
#58 security-message-8.6.0.png70.61 KBbenjifisher
#58 security-message-8.5.7.png144.05 KBbenjifisher
#58 security-message-8.4.8.png193.54 KBbenjifisher
#57 interdiff-2991207--54-57.txt1.3 KBrobpowell
#57 2991207--57.patch31.36 KBrobpowell
#37 interdiff-30-37.txt12.74 KBtedbow
#55 local-85-display-notification.png216.3 KBrobpowell
#30 interdiff-2991207-28-30.txt6.71 KBsamuel.mortenson
#55 interdiff-2991207--54-55.txt1.3 KBrobpowell
#30 2991207-30.patch20.53 KBsamuel.mortenson
#55 2991207-55.patch31.1 KBrobpowell
#28 2991207-28.patch16.3 KBsamuel.mortenson
#54 2991207-54.patch31.1 KBtedbow
#26 2991207-minor-unsupported.png78.97 KBsamuel.mortenson
#54 interdiff-50-54.txt5.77 KBtedbow
#54 8.4.x_before_8.6.0.png85.17 KBtedbow
#20 2991207-20.patch18.88 KBsamuel.mortenson
#25 interdiff-2991207-23-25.txt11.05 KBsamuel.mortenson
#51 8_4_error.png79.67 KBxjm
#16 interdiff-11-16.txt14.56 KBtedbow
#51 good_luck_updating_to_8_7.png66.84 KBxjm
#50 2991207-50.patch29.91 KBtedbow
#11 coverage_message.png38.83 KBtedbow
#50 interdiff-43-50.txt14.08 KBtedbow
#16 2991207-16.patch18.17 KBtedbow
#41 2991207-41.patch12.7 KBtedbow
#44 8.3.png74.79 KBxjm
#44 8.4.png69 KBxjm
#41 interdiff-39-41.txt14.62 KBtedbow
#23 interdiff-2991207-20-23.txt7.08 KBsamuel.mortenson
#23 2991207-23.patch18.76 KBsamuel.mortenson
#44 8.5.png52.43 KBxjm
#39 2991207-39.patch21.53 KBtedbow
#43 2991207-43.patch21.16 KBtedbow
#11 2991207-11.patch10.4 KBtedbow
#39 interdiff-37-39.patch3.22 KBtedbow
#8 status-8.5.6.png130.24 KBbenjifisher
#43 interdiff-41-43.txt13.81 KBtedbow
#37 2991207-37.patch21 KBtedbow

Comments

xjm created an issue. See original summary.

xjm’s picture

xjm’s picture

Issue summary: View changes
xjm’s picture

One way of solving this would be to add status report messages, e.g.:

  • If the site is on the most recent stable minor (let's call it 8.N), add an info message that says their version of core receives security coverage and will continue to for another release.
  • If their site is on the second-to-most-recent stable minor (8.N-1) add a warning that their site receives security coverage, but no regular bugfixes, and that they should plan to update in time for the next minor release of 8.N+1.
  • If the site is more out of that date (8.N-2 or lower), display a warning? Error? That their version of Drupal does not receive security updates and they should update to a covered version as soon as possible.

As I see it, there are two tricky parts to this issue:

  1. Communicating to the user the difference between "receives security updates" and "is secure". I.e., as of the day we released SA-CORE-2018-002, Drupal 8.3.9 was totally secure, but it no longer had security coverage. Or, the reverse, if someone was on 8.5.0 the day we issued that advisory, their site was insecure, but it certainly had security coverage.
  2. How we put the actual dates into Drupal. We know our release schedule in advance. It might be nice for site owners to see a clear message along the lines of "You are on an older release and should plan to update to B.N or higher by $release_date_of_8.N+1." We know those dates in advance, but we've never tried to maintain them in Drupal before. An intermediate step might be just linking the release cycle overview, which will have the most up-to-date release date info.
xjm’s picture

Something else that came up in the context of discussing this on the UX meeting today is that when a site is on 8.4.8 and planning to update to 8.5.6, they probably want to read the 8.5.0 release notes as least as much they want to read the relevant security advisories.

xjm’s picture

Issue summary: View changes
benjifisher’s picture

StatusFileSize
new130.24 KB

Where does the release schedule live? It seems to me like a bad idea to hard-code future release dates. Are the future dates in (or can they be added to) updates.drupal.org? Or the server that supplies composer package information?

Unless the answer is that the future dates are already available from some such source, I think for this issue we should settle for links to one or both of

or other documentation pages.

Here is a screenshot of (part of) the status report:

 status report (/admin/reports/status)

There is room in the "General System Information" section for more information. Some suggestions for what to put there, probably no more than two items:

  • How long this version will be fully supported (fixes for bugs and security issues)
  • How long this version will be supported (fixes for security issues only)
  • Link to release notes for the latest stable version
  • Link to a documentation page, such as one of those listed above

For this issue, "how long" may be expressed as "until version 8.N is released".

We already have the update status provided by the update module (if it is enabled). I guess we do not want to add to that: it is already complicated (wow!) and the update module may not be enabled. So we should be thinking of adding an additional status message, probably from the system module.

To address Question 5.1, I suggest thinking in terms of the severity levels defined by hook_requirements:

  • REQUIREMENT_ERROR
  • REQUIREMENT_WARNING
  • REQUIREMENT_OK
  • REQUIREMENT_INFO

Error: the installed version is insecure or does not receive security coverage.

Warning: the installed version is secure, but only receives security fixes

Info: the installed version is secure, and it receives bug fixes and security fixes

I guess what I am saying is that we do not have to convey the difference between "receives security updates" and "is secure". Instead, we should convey the recommended action and the urgency of that recommendation. The urgency is communicated by the severity and by whatever schedule we can communicate in the status message.

drumm’s picture

The API updates.drupal.org exposes for #2766491: Update status should indicate whether installed contributed projects receive security coverage already has per-release data. Since alpha/beta/etc of an otherwise-covered project are not covered, and rules can always change in the long run.

It looks like that API needs some work to support core:

<release>
  <name>drupal 8.1.10</name>
  <version>8.1.10</version>
  …
  <security covered="1">Covered by Drupal's security advisory policy</security>
</release>

(Those changes would be implemented in a non-core-specific way, so the same rules apply to semantically-versioned contrib.)

See also #2687957: Improve Update Status messaging for End of Life in Drupal 7(and Drupal 8 and later)

tedbow’s picture

Since this issue is about displaying if and for how long a site's minor version of Drupal will be supported not individual releases I think we will need something outside the <release> tag in the update XML.

Right now I don't think we have any meta information about minors just majors, recommend and supported, and individual releases, supported , covered, etc.

It seems like from the "Proposed resolution" that we would need either.

  1. Have information in the drupal.org XML that tells how long the minor will be supported.

    Something like

    <recommended_major>8</recommended_major>
    <supported_majors>8</supported_majors>
    <default_major>8</default_major>
    <minors>
      <minor>
        <name>8.7</name>
        <major_version>8</major_version>
        <minor_version>7</minor_version>
        <security covered='1' end_date='223456'>This minor version is covered</security>
      </minor>
      <minor>
        <name>8.6</name>
        <major_version>8</major_version>
        <minor_version>6</minor_version>
       <security covered='1' end_date='123456'>This minor version is covered</security>
      </minor>
      <minor>
        <name>8.5</name>
        <major_version>8</major_version>
        <minor_version>6</minor_version>
       <security covered='0' end_date='023456'>This minor version is not covered</security>
      </minor>
    </minors>
    

    This seems like it be very hard to do in generic because I don't think the drupal security team covers specific minors of contrib projects.

  2. Or hard code estimate end dates for core minors in to Drupal core directly.

    I don't know what the timeframe for #2909665: [plan] Extend security support to cover the previous minor version of Drupal is but hard coding be the only way if the goal is sooner than we could get the changes to drupal.org done

tedbow’s picture

Issue summary: View changes
Status: Active » Needs review
StatusFileSize
new38.83 KB
new10.4 KB

Here is an attempt to add "Security coverage" message for Drupal core.

The current message if a site was on 8.5.6 would be

The current minor version of Drupal core, 8.5, will be supported until the release of 8.6.0. 8.6.0 is currently in the pre-release stage. The latest pre-release is 8.6.0-rc1.

Security coverage message
I added the bit about the pre-release to alert the user that version they will have to update by is coming soon. If no pre-release is available the the message would just be the first sentence.

If the site currently needs a security update I don't put any message about coverage because it seemed to confusing to have both messages.

Status: Needs review » Needs work

The last submitted patch, 11: 2991207-11.patch, failed testing. View results

tedbow’s picture

Version: 8.5.x-dev » 8.7.x-dev
Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 11: 2991207-11.patch, failed testing. View results

tedbow’s picture

Status: Needs work » Needs review
tedbow’s picture

StatusFileSize
new18.17 KB
new14.56 KB
  1. Fix the errors in #11
  2. Add an error class if in pre-release for the release when security coverage will drop for existing version
  3. Added coverage_message to test cases for core
xjm’s picture

So I think this issue should add information to the site status report, not the update status report, because it's telling them something about the state of their site that is not specifically an update. #2990476: If the site is on an insecure version of an old minor and there is a secure version of that old minor available, the update status report should link that release will address the update status report. See #8.

larowlan’s picture

This is looking good.

I note however that we already have https://github.com/composer/semver in our dependencies, so we might be able to use a lot of its utilities for parsing version numbers etc, instead of creating our own.

  1. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,249 @@
    +      throw new \Exception("@todo New version of Drupal, handle it!");
    

    This still to be done?

  2. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,249 @@
    +    elseif ((int) $latest_full_release['version_major'] === $security_supported_release_info['version_major']) {
    

    no need for elseif if previous hunk throws an exception, if will do

  3. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,249 @@
    +    $support_until_release['version'] = $support_until_release['version_major'] . '.' . $support_until_release['version_minor'] . '.' . $support_until_release['version_patch'];
    

    could use implode('.', $support_until_release)?

  4. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,249 @@
    +    $pre_release_types = ['alpha', 'rc', 'beta'];
    

    should these strings be constants?

xjm’s picture

Status: Needs review » Needs work

NW for #17 and #18. Main change is that this should go on the status report rather than the update status report, and then we can work on the internals.

Some more review points:

  1. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,249 @@
    +  private static function getMostRecentFullRelease(array $releases) {
    +    foreach ($releases as $release) {
    +      if (empty(static::getPreReleaseType($release)) && static::isRecommendableRelease($release)) {
    +        return $release;
    +      }
    +    }
    +    return NULL;
    ...
    +  /**
    +   * Gets the pre-release type.
    +   *
    +   * @param array $release
    +   *   Release information as return by update_get_available().
    +   *
    +   * @return string|null
    +   *   The pre-release type or NULL.
    +   */
    +  public static function getPreReleaseType(array $release) {
    +    $pre_release_types = ['alpha', 'rc', 'beta'];
    +    if (!empty($release['version_extra'])) {
    +      foreach ($pre_release_types as $pre_release_type) {
    +        if (stripos($release['version_extra'], $pre_release_type) === 0) {
    +          return preg_replace('/[0-9]+/', '', $release['version_extra']);
    +        }
    +      }
    +    }
    +    return NULL;
    +  }
    ...
    +  /**
    +   * The most recent pre-release for a version major and minor.
    +   *
    +   * @param int $major
    +   *   The version major.
    +   * @param int $minor
    +   *   The version minor.
    +   * @param array $releases
    +   *   Releases as returned by update_get_available().
    +   *
    +   * @return array|null
    +   *   The most recent pre-release if found, otherwise NULL.
    +   */
    +  private static function getMostRecentPreReleaseForRelease($major, $minor, array $releases) {
    +    foreach ($releases as $release) {
    +      if ((int) $release['version_major'] === $major && (int) $release['version_minor'] === $minor
    +        && !empty(static::getPreReleaseType($release))
    +        && static::isRecommendableRelease($release)) {
    +        return $release;
    +      }
    +    }
    +    return NULL;
    +  }
    

    I think we probably don't need this functionality (or it's at least a separate issue scope). We already have the $release['version_extra'] to check whether it's a full release or not, and the update module already has its own logic for presenting pre-release versions vs. stable release versions. We should reuse the logic that's already there (possibly moving it into the helper and making the update report use it). See below points about the pre-release versions.

  2. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,249 @@
    +        $existing_pre_release_type = static::getPreReleaseType($project_data['existing_release']);
    +        if (empty($existing_pre_release_type) || $existing_pre_release_type === 'rc') {
    +          $message = t(
    

    We shouldn't special-case the RC here. Only core RCs receive security coverage, and that's a policy and probably should not be hardcoded.

  3. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,249 @@
    +            'The current minor version of %project, %version, will be supported until the release of %coverage_version.',
    

    The old minor isn't supported; it just receives security fixes. "Current" is also ambiguous.

    If the user is on the current minor, I think it should be something like:

    The installed minor version of %project, %version, will receive security fixes until the release of %coverage_version.
    

    For the current minor, it'll be an info message. For the previous minor, we'll make it a warning and add:

    <a href=":update_status_report">Update to %next_minor or higher soon</a> to continue receiving security fixes.
    

    And if it's core, then add:

    <a href="https://www.drupal.org/core/release-cycle-overview">release cycle overview</a> for more information on supported releases.

    We can work on the message with UX reviewers, but that's the content we should present.

  4. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,249 @@
    +            'The current minor version of %project, %version, will be supported until the release of %coverage_version.',
    ...
    +          if (!empty($security_info['pre_release'])) {
    +            $message .= ' ' .
    +              t(
    +                '%coverage_version is currently in the pre-release stage. The latest pre-release is %pre_release.',
    +                [
    +                  '%coverage_version' => $security_info['supported_until']['version'],
    +                  '%pre_release' => $security_info['pre_release']['version'],
    +                ]
    +              );
    +          }
    +        }
    

    I don't think we should include this message. Directing them to the update status report in the previous message should be sufficient since that already includes its own logic around how to display pre-release versions.

  5. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,249 @@
    +        $message = t(
    +          'The current minor version of %project, %version, is longer supported and will not receive security updates. You should update <em>immediately</em>.',
    +          [
    +            '%project' => $project_data['title'],
    +            '%version' => "$major.$minor",
    

    For this message, the first sentence looks good. Let's change the second sentence to:

    <a href=":update_status_report">Update immediately to receive future security updates.</a>
    

    This one will be an error on the status report.

Thanks!

samuel.mortenson’s picture

Status: Needs work » Needs review
StatusFileSize
new18.88 KB

Here's a straight re-roll of #16.

samuel.mortenson’s picture

I'm not sure how to address #17 - with the way this is written, any project could provide a security coverage message, so to me showing these on the site status report could be quite verbose. If we want this, I'm not sure where it should go - do we implement hook_requirements for that?

samuel.mortenson’s picture

I'm going to move forward assuming this is meant for core only, and address the other review as well.

samuel.mortenson’s picture

StatusFileSize
new18.76 KB
new7.08 KB

Addressed #17 and #18 (except #18.1, I don't know the answer to that), need more time on #19.

FYI - There are a few formatting/markup bugs here that will be addressed in the next patch.

Status: Needs review » Needs work

The last submitted patch, 23: 2991207-23.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

samuel.mortenson’s picture

Status: Needs work » Needs review
StatusFileSize
new16.09 KB
new11.05 KB

Addressed #19, still need test coverage for unsupported minors. Also, here are screenshots of what the info/error message looks like now.

samuel.mortenson’s picture

StatusFileSize
new78.97 KB
new39.71 KB

Status: Needs review » Needs work

The last submitted patch, 25: 2991207-25.patch, failed testing. View results

samuel.mortenson’s picture

Status: Needs work » Needs review
StatusFileSize
new16.3 KB

Re-roll.

Status: Needs review » Needs work

The last submitted patch, 28: 2991207-28.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

samuel.mortenson’s picture

Status: Needs work » Needs review
StatusFileSize
new20.53 KB
new6.71 KB

I removed all the pre-release code per #19, but I'm wondering if we want to check if "version_extra" is not empty and not "rc", and if so do not show users the message about their minor being supported (the info message). Another way to say this is that alpha and beta users should not be led to believe that they have security coverage.

Also changing test coverage to use a fixture that's easy to use, since these new status messages only show up if there are no security updates.

Status: Needs review » Needs work

The last submitted patch, 30: 2991207-30.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

tedbow’s picture

  1. +++ b/core/modules/update/tests/src/Functional/UpdateTestBase.php
    @@ -165,6 +167,11 @@ protected function assertSecurityUpdates($project_path_part, array $expected_sec
    +    if ($coverage_message) {
    +      $this->drupalGet('admin/reports/status');
    +      $this->assertSession()->pageTextContains($coverage_message);
    +    }
    

    Should we always be checking admin/reports/status even if $coverage_message is empty. If we explicitly don't want to to show a message about coverage if core is not currently secure could check to make sure "Drupal core security coverage" doesn't appear.

  2. +++ b/core/modules/update/update.compare.inc
    @@ -425,6 +427,17 @@ function update_calculate_project_update_status(&$project_data, $available) {
    +  if (!empty($project_data['security updates'])) {
    +    // If we found security updates, that always trumps any other status.
    +    $project_data['status'] = UPDATE_NOT_SECURE;
    +  }
    

    Was this added back intentionally in #28?

    This was removed in #2804155: If the next minor version of core has a security release, status still says "Security update required!" even if the site is on an equivalent, secure release already because it was determined we could rely on Drupal insecure tag.

    Since #28 was labeled as re-rolled I don't think it was intentional

samuel.mortenson’s picture

#32.2 was not intentional, no.

samuel.mortenson’s picture

Also wanted to note that the messages added in this patch only shows up if there _isn't_ a security update, that was ported over from the previous logic of the patch.

xjm’s picture

These messages should appear regardless from whether there is a security update or not.

So here are the screenshots from #26 that had not been embedded yet:

xjm’s picture

The second message seems to be missing the link, and it actually looks like it should be a warning instead of an update.

So as of the release of 8.6.0:

  • If you are on 8.3.0, you get the error telling you to update to continue receiving security fixes. I'm not sure of the value of the second paragraph about the release dates there.
  • If you are on 8.5.0, you get a warning using the text/links proposed in #19, and it recommends you update soon.
  • If you're on 8.6.0, you should just get a plain white infor message about how long it will be supported (but I still think it needs the release cycle page there)
tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new12.74 KB
new21 KB
  1. I talked with @xjm who mentioned the assertion for coverage on /admins/reports/status should be in it's own test. I am not doing that in this patch to minimize changes while I address another issue.
  2. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
    @@ -311,8 +326,23 @@ public function securityUpdateAvailabilityProvider() {
    +      '1.0, supported' => [
    +        'site_patch_version' => '1.0',
    +        'expected_security_releases' => [],
    +        'expected_update_message_type' => static::UPDATE_NONE,
    +        'coverage_message' => 'The installed minor version of Drupal, 8.1, will receive security fixes until the release of 8.2.0.',
    +        'fixture' => 'sec.2.0',
    +      ],
    

    This is should actually have unsupported coverage message because in the fixture 8.2.0 is already released so 8.1.0 is out of coverage(I assume we are not accounting for the small window of overlap?)

  3. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,190 @@
    +      'version_minor' => ((int) $existing_release['version_minor']) + static::CORE_MINORS_SUPPORTED + 1,
    

    We don't need the +1 here. I think this is why test case that should have been "unsupported" was passing as supported.

  4. re #36

    If you are on 8.3.0, you get the error telling you to update to continue receiving security fixes. I'm not sure of the value of the second paragraph about the release dates there.

    Are you talking about the

    Visit the release cycle overview for more information on supported releases.

    paragraph. I still think this is good even if you are out of security coverage. Because it explains why your version is not going to receive updates. So you can keep up to date next time.

  5. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
    @@ -167,15 +167,17 @@ public function testMajorUpdateAvailable() {
    +   * @param string $coverage_message
    +   *   The expected coverage message.
    

    Changing this to an array of message so we can check for the "Visit the release cycle overview for ...." text. I don't think \Behat\Mink\WebAssert::pageTextContains() works for text split into paragraphs.

Status: Needs review » Needs work

The last submitted patch, 37: 2991207-37.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new3.22 KB
new21.53 KB
  1. +++ b/core/modules/update/update.install
    @@ -105,6 +107,22 @@ function _update_requirement_check($project, $type) {
    +  // Return early if there isn't a core update and there is a coverage message.
    +  if ($type == 'core' && $status !== UpdateManagerInterface::NOT_SECURE && !empty($project['security_coverage_info'])) {
    +    if ($security_coverage_message = UpdateHelper::getSecurityCoverageMessage($project)) {
    +      $requirement['description'] = $security_coverage_message;
    

    One of the test failures was coming from _update_cron_notify because it calls update_requirements() directly and it was looking for a reason.

    I don't think we should place our new requirement in this function because it is made to return only 1 requirement so would have to change existing functionality. Because there is so little testing for this I think we could break something we missed.

    For instance _update_cron_notify sends out emails based on update_core requirement and we would have been not been changing the requirement in some cases.

    It is very likely that site admins have automated processes that handle these emails about needing updates.

    So I think we should leave _update_requirement_check the way it is and add \Drupal\update\UpdateHelper::getSecurityCoverageRequirement() and have a new requirement index.

  2. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,190 @@
    +  const CORE_MINORS_SUPPORTED = 1;
    

    I know this issue is part of #2909665: [plan] Extend security support to cover the previous minor version of Drupal but I am assuming there is other work to be done before this is fully implemented. If we change this to 2 now committing this patch would effectively be implementing the new policy.

    Currently we are on stage 5 of 6 in #2909665.

    If we commit this patch with CORE_MINORS_SUPPORTED = 1 then we everything else is complete. we can update it to 2.

    Should we make a follow up to set it to 2 or do that now.

The last submitted patch, 39: interdiff-37-39.patch, failed testing. View results

tedbow’s picture

StatusFileSize
new14.62 KB
new12.7 KB

This patch does

  1. Moves the testing coverage for message to its own test method.
  2. Uses an existing fixture file for the test and removes the new one that was added for this issue
  3. Checks to make sure there is no message if we are on pre-release or dev version

Re @samuel.mortenson on #30

Also changing test coverage to use a fixture that's easy to use, since these new status messages only show up if there are no security updates.

This is not longer true since I changed it to be its own requirement. See #39.1

We could still not show the message but I think it makes sense to show it in either case.
For instance if there are there is security release for you current minor and the next one. If we don't give you the message that your current minor will still be security updates you may think this is either the last 1 or an exception(which we have done right?). That would influence about whether you would pick the current minor security release or the next minor's.

xjm’s picture

Status: Needs review » Needs work

Thanks @tedbow and @samuel.mortenson!

  1. If we commit this patch with CORE_MINORS_SUPPORTED = 1 then we everything else is complete. we can update it to 2.

    Should we make a follow up to set it to 2 or do that now.

    This is worth considering. Let's have it at 2 for now though so that we can test this patch based on the intended end result.
     

  2. We still need a warning when the user is on not-the-latest minor as discussed in #8, #19, #36, and the IS.
    Newest minor: info
    Previous minor: warning saying to plan to update soon.
    Unsupported minor: error, update as soon as possible.
     

  3. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,222 @@
    +    if ((int) $latest_full_release['version_major'] > $security_supported_release_info['version_major']) {
    +      throw new \Exception("@todo New version of Drupal, handle it!");
    +    }
    

    We also need to figure out what to do here still. Edit: There is probably precedent for this elsewhere in the Update module.

tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new13.81 KB
new21.16 KB
  1. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,222 @@
    +          'The installed minor version of %project, %version, is no longer supported and will not receive security updates. <a href=":update_status_report">Update to the next minor or higher soon</a> to continue receiving security fixes.',
    

    Changing the second sentence to remove "next minor to

    Update to a supported minor soon to continue receiving security fixes.

    which will have a link to the update status page.

    The site could be multiple minors behind so "next minor" may still result in an unsupported minor.

  2. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
    @@ -344,6 +344,69 @@ public function securityUpdateAvailabilityProvider() {
    +    if ($coverage_messages) {
    +      foreach ($coverage_messages as $coverage_message) {
    

    This if is left over from when this was in \Drupal\Tests\update\Functional\UpdateTestBase::assertSecurityUpdates we don't need it anymore. it will always be an array, though it may be empty.

  3. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
    @@ -344,6 +344,69 @@ public function securityUpdateAvailabilityProvider() {
    +    else {
    +      $assert_session->pageTextNotContains('Drupal core security coverage');
    +    }
    

    Since we have conditional logic to display the sentence about updating to the next minor I think we need to check that the sentence is not there when it should not be.

    Adding $not_contains_messages parameter to the test method to check for these. Which means we can remove this else and just check that no $not_contains_messages show.

  4. re #42.1 changed CORE_MINORS_SUPPORTED to 2
xjm’s picture

Issue summary: View changes
Issue tags: +Needs usability review
StatusFileSize
new52.43 KB
new69 KB
new74.79 KB

All the changes in #43 look good to me, thanks @tedbow! I think this is probably at a point where we can get a usability review once we post some updated screenshots.

A couple questions for UX reviewers:

  1. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -141,18 +141,30 @@ public static function getSecurityCoverageMessage(array $project_data) {
    -          'The installed minor version of %project, %version, is no longer supported and will not receive security updates. <a href=":update_status_report">Update to the next minor or higher soon</a> to continue receiving security fixes.',
    +          'The installed minor version of %project, %version, is no longer supported and will not receive security updates. <a href=":update_status_report">Update to a supported minor soon</a> to continue receiving security fixes.',
    

    I wonder if this one should say "as soon as possible!" or such. That's a question we can ask during the UX review.
     

  2. I'm also wondering about "to continue receiving security fixes". Technically, you will still receive security fixes on your update status report -- it's just that there's an increase chance that intervening changes might break your site. I'm not sure if we should (a) try explaining that here, or (b) let the handbook page explain it (and maybe update the handbook page with a clearer section about it). (I also considered whether hook_help() would be an option but am leaning toward "No" since these are policies that will evolve over time and a handbook page is likely to fall out of date.)
     

Here are the screenshots (demoing with real release data as of Aug. 31):

When the site is on the latest minor:

When the site is on an older, but supported minor:

When the site is on an unsupported minor:

xjm’s picture

Status: Needs review » Needs work

Looks like there is an off-by-one error in the warning case. In my screenshot it says "update to 8.6 or higher soon", which is impossible since 8.6 hasn't been released for production yet. It should say "8.5 or higher", I think.

xjm’s picture

Also it looks like "Drupal core security coverage" is both the header and the value (notice how it's repeated in both the left and right columns in the screenshot). In other status report items it's a short description of the status; e.g. "Drupal core update status" might say "Not secure!"; "Access to update.php" might say "Protected" or "Not protected", etc.

xjm’s picture

Issue tags: +Needs followup

Oh, I think we also could file followups for the earlier proposal from @benjifisher and @drumm about using the XML data to improve this, and for @benjifisher's other suggestion about maybe including an abbreviated representation of the coverage in the "General system information" section at the top.

xjm’s picture

@tedbow and I discussed what the behavior should be when we are coming up on the final minor release of a major release series. For example, if 8.10.x is the last minor release of Drupal 8, then a message that 8.10.x will be supported until the release of 8.12.0 is misleading and wrong.

For now, I suggested only displaying this coverage message on the latest major version, since we're fairly confident that at least 8.x won't continue getting new minors after 9.0.0, and presumably 8.LTS should have its own special message (TBD). That doesn't help us with the second-to-last minor version, but at least it minimizes incorrect messages and reduces the extent of potential release blockers for 9.0.0.

We should probably file a followup and put in an @todo also. Added to the IS.

xjm’s picture

Assigned: Unassigned » tedbow
Issue summary: View changes

Another thing we might want to do is send the site owner an email notification when their minor security coverage ends. That's a separate fix though. Added a note to the IS to consider a followup for that.

@tedbow has some work that he will post this weekend.

tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new14.08 KB
new29.91 KB
  1. +++ b/core/modules/update/tests/modules/update_test/drupal.sec.2.0.xml
    @@ -0,0 +1,133 @@
    +            <name>Drupal 8.3.0</name>
    +            <version>8.3.0</version>
    +            <tag>DRUPAL-8-3-0</tag>
    +            <version_major>8</version_major>
    +            <version_minor>2</version_minor>
    +            <version_patch>0</version_patch>
    

    This release was added by mistake we don't need 8.3.0 in the fixture. The only reason the tests weren't failing is because the actual version_minor value was 2 not 3.

  1. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,237 @@
    +      $info['supported_until'] = $support_until_release;
    

    After we get the supported release we should be checking if the next major version is available and the supported release has not been. If so we can't provide a good coverage message so return empty.

  2. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,237 @@
    +      if (static::isRecommendableRelease($release)) {
    

    We should not be checking isRecomendableRelease() which check if it is unsupported or insecure.

    We are trying to find the full release to determine if the "supported till" release is already released. It may have been release but is not insecure. that would still mean the installed version is not covered.

xjm’s picture

Issue summary: View changes
Status: Needs review » Needs work
StatusFileSize
new66.84 KB
new79.67 KB

We discussed this issue today in the usability meeting. It sounds like overall the messaging we're using is good. The one point of usability feedback that we still should address is making the message consistently three separate paragraphs. (Currently, for unsupported minor versions, it's only two.)

I also noticed a bug while testing the latest patch. Currently, if I set my version to the latest minor version as of today, it's displaying a warning still:

And the N-1 minor release is currently an error instead of a warning:

xjm’s picture

Issue tags: -Needs usability review
xjm’s picture

tedbow’s picture

Assigned: tedbow » Unassigned
Issue summary: View changes
Status: Needs work » Needs review
StatusFileSize
new85.17 KB
new5.77 KB
new31.1 KB
  1. Update \Drupal\update\UpdateHelper::getSecurityCoverageMessage() to always split the message into paragraphs. This required test changes so it good because our previous tests would fail.
  2. Addressed the problem of 8.4.x showing it was not under security coverage. This was because \Drupal\update\UpdateHelper::getMostRecentFullRelease() was not checking for version_extra being empty so it was picking up the 8.6.0-rc1.
    So with this patch
    screenshot showing 8.4.x still covered
    When I ran this 8.6.0 hadn't come out yet.

    I updated the test feature to include rc release to emulate this.

robpowell’s picture

StatusFileSize
new31.1 KB
new1.3 KB
new216.3 KB
  1. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,267 @@
    +  const CORE_MINORS_SUPPORTED = 2;
    

    I think this is supposed to have a docblock

  2. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,267 @@
    +                '%next_minor' => $support_until_release['version_major'] . '.' . $support_until_release['version_minor'],
    
    

    this will always return the future release ie 8.7. Since the future release won't be available, we want to show the current release that the user should update to. This is the bug identified in #45

Here is a screenshot of the results after the patch. I am running 8.5.5 and it is notifying me to update to 8.6 rather than 8.7.

benjifisher’s picture

Issue summary: View changes

I added four follow-up issues. See the updated issue summary.

robpowell’s picture

StatusFileSize
new31.36 KB
new1.3 KB

helps if you update the patch :/. interdiff is the same from above

benjifisher’s picture

StatusFileSize
new193.54 KB
new144.05 KB
new70.61 KB

Here are some screenshots using the patch from #57.

The patch did not apply cleanly to Drupal 8.4.8 nor 8.5.7. I removed the diffs to one of the test files, and I had to apply one hunk manually. For the record, this one:

diff --git a/core/modules/update/update.compare.inc b/core/modules/update/update.compare.inc
index dd658120ef..380d00533a 100644
--- a/core/modules/update/update.compare.inc
+++ b/core/modules/update/update.compare.inc
@@ -425,6 +427,8 @@ function update_calculate_project_update_status(&$project_data, $available) {
     $project_data['recommended'] = $project_data['latest_version'];
   }
 
+  $project_data['security_coverage_info'] = UpdateHelper::getSecurityCoverageInfo($project_data, $available['releases']);
+
   if (isset($project_data['status'])) {
     // If we already know the status, we're done.
     return;

I made these screenshots a few days after the release of 8.6.0.

Installed version 8.6.0:
Supported minor version notice Installed version 8.5.7:
Supported minor version warning Installed version 8.4.8:
Unsupported minor version error

Good news: Drupal is no longer telling me to upgrade to 8.7.0. Thanks, @robpowell!

My screenshots include the "Drupal Core update status" message, also from the Update Manager module. (One screenshot also includes the Trusted Host Settings error. Sorry about that.) Looking at these together, I think there is some duplicated information.

  1. In the warning message (8.5.7), "Update to 8.6 or higher soon" links to /admin/reports/updates/update, same as the link "available updates" in the next message. I do not like having two links to the same page, with different link text. (Although same text, different destinations would be even worse.) Maybe make "Update to 8.6 or higher soon" plain text, not a link. Or we can just delete this line.
  2. In the error message (8.4.8), I see "security updates" and "security fixes". The warning message uses "security fixes". I have a slight preference for "security updates", but I care more that we use the same phrase consistently.
  3. In the error message (8.4.8), "Update to a supported minor soon" is again a link to /admin/reports/updates/update, so again it duplicates the "available updates" link in the next message. Same suggestions as before.
  4. In all three messages, we use "release cycle overview" as the link text for https://www.drupal.org/core/release-cycle-overview. It is a little confusing that the title of that page does not match the URL and link text here. Maybe we should change the title of that page to "Release Cycle Overview", with the current title as a subtitle.
benjifisher’s picture

Status: Needs review » Needs work

I am setting the status to "needs work" because of the issues I raised in #58.

I am open to other suggestions, and maybe we should discuss this again at the weekly UX meeting, but I think the following would be acceptable:

  1. Use either "security fixes" or "security updates" consistently.
  2. Make "Update to 8.6 or higher soon" (in the warning message) and "Update to a supported minor soon" (In the error message) plain text, and add a second sentence: "See the available updates page for more information." Make "available updates" a link as in the "Drupal Core Update Status" message.
  3. In the error message, change "soon" to "as soon as possible". The text should make clear that this is more urgent than the warning case. (The fact that this is an error should reinforce the urgency.)

I am not really happy with (2), since there is even more duplication. My goals here are to make a clear recommendation, to convey the level of urgency, and to avoid confusion (two links with the same target but different link text).

I forgot to mention (3) in my previous comment.

benjifisher’s picture

Issue tags: -Needs followup

I forgot to remove the "Needs followup" tag when I added the followup issues (Comment #56). Done.

When I wrote Comment #8, I did not notice that the Component is set to update.module. What if the Update Manager module is not enabled? Do we want any sort of message? We could have a static message with a link to a handbook page, or we could recommend enabling the Update Manager module to get information about EOL.

I mentioned in #8 that the existing code in the Update Manager module is already complex. That is why we are adding a new message instead of modifying the existing one. The results, as I said in #58 and #59, are not really satisfactory. Maybe it is time to do the hard work of refactoring that complex code. Yet another follow-up?

tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new6.6 KB
new36.94 KB
  1. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -12,6 +12,12 @@
    +   * How many minor versions of Drupal are supported.
    +   *
    +   * This constant is used to determine if the installed version is still
    +   * supported with security updates.
    

    I don't think we need the second part here.

  2. @robpowell thanks for catching that it was prompting to update to 8.7
  3. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -163,11 +169,12 @@ public static function getSecurityCoverageMessage(array $project_data) {
    +          $suggested_update_version = current($project_data['releases']);
    

    We should avoid using array pointers.

    This gets the first release here but that will only work if we because right now we don't have RC or other prelease for 8.7.x. if we did that would be the first release. Though also I don't think we can guarantee that for instance if there was security release only for 8.5.x that would probably put it to the top.

    Since we know that the installed version is only supported for 1 more minor what we really want is
    $current_minor + 1

    Fixing

  4. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
    @@ -344,6 +344,140 @@ public function securityUpdateAvailabilityProvider() {
    +      '1.0, supported' => [
    +        'site_patch_version' => '1.0',
    +        'requirements_section' => 'Warnings found',
    +        'fixture' => 'sec.2.0',
    +        'coverage_messages' => [
    +          'The installed minor version of Drupal, 8.1, will receive security fixes until the release of 8.3.0.',
    +          'Update to 8.3 or higher soon to continue receiving security fixes.',
    +          $release_coverage_message,
    +        ],
    

    Our test expectation was actually wrong here.

    In the fixture 8.3.0 has not come out yet so we should be prompting to update to 8.2 or higher.

    The tests didn't fail in #57 because there was 8.3.0-rc1 release so this passed.

    Updating the message and also adding a new fixture which doesn't have the rc1 release so we can test both cases.

benjifisher’s picture

Status: Needs review » Needs work

@tedbow:

Thanks for fixing those problems.

Please address the points I raised in #58 and #59. I am setting this issue back to NW for that. If you disagree with my suggestions, please explain.

In #59.2, I recommended making "Update to 8.6 or higher soon" (in the warning message) and "Update to a supported minor soon" (In the error message) plain text. If you disagree with that, then please at least move "soon" out of the links.

So far, I have concentrated on UX review, not code review. Looking through the code, I have a few suggestions:

  1. The getSecurityCoverageMessage() has a bunch of conditionals. Please add some code comments to help orient anyone reading the code.
  2. Most of that method is inside a big if block. The only code outside that block is $message = ''; before and return Markup::create($message); after. Consider changing the return type to string so that we can invert the conditional and exit early, then have the main part of the method indented one fewer level. Of course, make adjustments when calling the method.

Again, I do not like duplicating so much information, but improving that may be outside the scope of this issue. I plan to bring this up at the next UX meeting.

webchick’s picture

Priority: Major » Critical

While we made the Extended Security Support policy change last year, we still haven’t completed this issue, which is critical to to ensure users know about security coverage for their minor and make the right choice in response to security releases. After talking to @xjm, escalating to critical.

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.

tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new14.38 KB
new37.58 KB

re #62 @benjifisher thanks for the reviews. Sorry it has taken soooo long to get back to this issue.

re #58

  1. [UPDATE] I don't think fully understood this see my response to #59.2

    I agree that having the 2 texts that lead to the same path is not ideal but I think because they are in 2 different message rows it is not that bad because

    • Some user might just read one of the message rows and not the other. Because of that it is good to have the link to the updates page in each message row.
    • Without a much larger refactoring than this patch is currently doing I don't think we can assume that if one message row that other one will also be there. Even if that the case now we could easily update the logic and that not be the case and then we would lose the link to the update page.

    Maybe make "Update to 8.6 or higher soon" plain text, not a link. Or we can just delete this line.

    For the above reasons I think we should keep this a link.

  2. Nice catch! Changed to "security updates" everywhere
  3. I think it works that way it is because of reasons in 1)
  4. Seems like good idea. made the suggestion here https://www.drupal.org/core/release-cycle-overview#comment-13245570

    Seems like we won't have to wait till this issue is committed though to make this change.

re #59

  1. fixed
  2. Fixed. I didn't fully understand this suggestion in #58. Added the new sentence "See the available updates page for more information."
  3. fixed

re #62

  1. Added comments
  2. I did the check in the beginning and if
    !isset($project_data['security_coverage_info']['additional_minors_coverage'])
    I returned an empty string. I didn't change the return type so if we add others to this method we don't have to remember to call Markup:create()

I also had to make some changes \Drupal\Tests\update\Functional\UpdateCoreTest::testSecurityCoverageMessage() and it's dataprovider.

+++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
@@ -344,6 +344,163 @@ public function securityUpdateAvailabilityProvider() {
+    foreach ($coverage_messages as $coverage_message) {
+      $assert_session->pageTextContains($coverage_message);
+    }
+    foreach ($not_contains_messages as $not_contains_message) {
+      $assert_session->pageTextNotContains($not_contains_message);
+    }

Here we were checking that messages are/aren't on the entire page. But now that we are using the same message that appears on the page elsewhere as per #59.2 we should only be checking the security coverage section.

We probably should have been checking this section anyways since that is what the test is suppose to cover.

tedbow’s picture

StatusFileSize
new10.45 KB
new37.78 KB

I did some review since it has been awhile

  1. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,275 @@
    +    if ((int) $latest_full_release['version_major'] > $security_supported_release_info['version_major']) {
    

    there are a number of these comparisons where we use (int) on 1 side and not on the other. Since we are getting this from update_get_available() which is well document and gets its in data from outside XML I think it is not a bad idea to be paranoid about this data and also cast $security_supported_release_info array values to int.

  2. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,275 @@
    +  public static function getSecurityCoverageMessage(array $project_data) {
    

    This does not need to be public

  3. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
    @@ -345,6 +345,161 @@ public function securityUpdateAvailabilityProvider() {
    +   * @param string $site_patch_version
    +   *   The patch version to set the site to for testing.
    +   * @param array $coverage_messages
    +   *   The expected coverage messages.
    +   * @param array $not_contains_messages
    +   *   Messages that should not appear in the coverage section.
    +   * @param string $fixture
    +   *   The test fixture that contains the test XML.
    +   *
    +   * @dataProvider securityCoverageMessageProvider
    +   */
    +  public function testSecurityCoverageMessage($site_patch_version, $requirements_section, $fixture,  array $coverage_messages = [], array $not_contains_messages = []) {
    

    requirements_section was not in the function @param's. Also they were out of order.

    Changing the name and also just making it always a string and not sometimes NULL.

tedbow’s picture

Title: Drupal core should inform the user of the security coverage for the site's installed minor version » Drupal core should inform the user of the security coverage for the site's installed minor version including final 8.x LTS releases
Related issues: +#2998287: Provide accurate information on the security coverage of the 8.x final minor and LTS, and recommend updating to the next major version when appropriate
StatusFileSize
new34.14 KB
new65.55 KB

Talked with @xjm about and we agreed that we should merge #2998287: Provide accurate information on the security coverage of the 8.x final minor and LTS, and recommend updating to the next major version when appropriate into this issue.

This current issue we had hoped would be in by 8.6.x(🤷‍♂️) but since this issue is targeted for 8.8.x the first sites that will use this logic will be affected by the need LTS logic. There is no point in committing this issue without 8.8.x/LTS specific logic. Because currently it would tell users that 8.8.0 will be supported until 8.10 which we know is not true.

So here is the patch from #2998287-6: Provide accurate information on the security coverage of the 8.x final minor and LTS, and recommend updating to the next major version when appropriate which was built on #66

tedbow’s picture

Added the commented I had for the patch on #2998287-6: Provide accurate information on the security coverage of the 8.x final minor and LTS, and recommend updating to the next major version when appropriate

In this patch I provided the the 8.9 LTS as a hard-coded. But it will only use it if a LTS for Drupal 8 is not available in update XML. If one is in the update XML will use that.

This could allow #2998285: Add information on later releases to updates.drupal.org to be delayed or even not done for LTS purposes if the 8.9 plan stays the same. If the 8.9 support end changes or if another release will be the LTS then drupal.org would have to provide LTS release information.

I just realized I didn't actually implement what #2998285 was suggesting exactly. It was suggesting putting future release in the releases array that is provided in the XML. In this patch I added support for lts_releases as a top-level item in the update XML. This would have less information than regular releases but would provide a support_end value.

I didn't implement this differently on purpose from the suggestion in #2998285 but this way may be simplier for drupal.org to implement. I am not sure.

The current patch allows:

  1. 1 LTS per major
  2. The LTS does not have to be in the releases array provided by drupal.org xml.
  3. If no LTS for a major is provided in the XML 8.9.0 with support end of 11/01/2021 is used as a fallback. Additional future major version LTS versions can be added to \Drupal\update\UpdateHelper::setFallBackLts()
  4. If a release is 1 minor version before the LTS then it will be assumed that it will be supported until the next major is released. For example 8.8 will be assumed to be supported until 9.0.0(unless a different LTS is provided)
  5. Since \Drupal\update\UpdateFetcher::buildFetchUrl() includes \Drupal::CORE_COMPATIBILITY in URL only releases for the current major are returned. Therefore we can't rely on 9.0.0 release information being included to determine if it has been released and 8.8 no longer being supported. Therefor this patch looks at supported_majors in the XML. I assumed that if a major is in this list then that MAJOR.0.0 has been released. Is that true? I assume this would not be added before this release. Is that true?

I have added some test coverage which includes lts_releases provided in the XML to prove this works and that we can override the Fallback LTS of 8.9. But I would like some feedback on this idea in general before I add more test coverage.

andypost’s picture

Would be great to have test presence status as addition or follow up
Having "green scheeld" does not mean tests works and pass - it could lead to some d-org page about how to find and contribute to issue to help resolve it

drumm’s picture

For Drupal.org, we’ll first need to store the new data somewhere. I think this would be a new field on tagged releases for the support end date, if it is empty, it is not an LTS release. (We could make this available to contrib, too.)

I’d like to get away from

+        <version_major>8</version_major>
+        <version_minor>10</version_minor>
+        <version_patch>0</version_patch>

It is redundant with the version number. And for contrib, version_minor & version_patch are swapping as we introduce semver. IIRC, last time we looked, we found that core actually didn’t use the existing version_* elements. I don’t recommend starting to use them.

Since \Drupal\update\UpdateFetcher::buildFetchUrl() includes \Drupal::CORE_COMPATIBILITY in URL only releases for the current major are returned.

That needs to stop using \Drupal::CORE_COMPATIBILITY ASAP. Use all like https://updates.drupal.org/release-history/token/all. See #3074993: Use "current" in update URLs instead of CORE_COMPATIBILITY to retrieve all future updates

drumm’s picture

Are these really LTS “releases” or releases on LTS branches? This data could also be something like versions falling in certain version constraints are LTS.

tedbow’s picture

@drumm

Are these really LTS “releases” or releases on LTS branches?

Yes they are really LTS branches

I think this would be a new field on tagged releases for the support end date, if it is empty, it is not an LTS release. (We could make this available to contrib, too.)

So because it is branches it probably can't be on an individual release.

This is also true for core because it would be super helpful to be able to designate LTS branch before there were actually any releases for that branch.

For instance because this issue is trying display a message about security coverage for 2 core minors, ie "you are on drupal 9.1 which is supported until 9.3.0 is released" this will be affected by LTS branches.

if we don't factor in LTS branch logic then the 8.8.x branch would be supported until 8.10.0.
But

  1. we know 8.9.x will be the last branch for 8.x.
  2. As soon as 8.8.0 is released there needs to be something in the update xml(or hard-coded in core) that tells us that 8.9.x will be the LTS branch. This allows us to say "You are on 8.8 which will be supported until 9.0.0" because with our 2 minors support policy + 8.9 being the last minor or 8.x we know this.
  3. But at the time 8.8.0 is released the 8.9.0 release will not be out.

So @drumm, is there someone we can store this on the project level?

When I look at one of my projects I see

Which has "Recommended major version" for each branch
Is this stored on the project itself? maybe we could have a multi-value field "LTS-Minors". The you could have 1 minor and 1 end for each major branch that has any releases.

So right now for core it could have a "8 lts branch" and "8 lts end date". Then as soon as 9.0.0 is released you could add a "9 lts branch" and "9 lts end data", though you won't have too.

tim.plunkett’s picture

Just some random observations while reading though.

  1. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,397 @@
    +          throw new \LogicException('::getAdditionalSecuritySupportedMinors() should never bee called before checking ::isNextMajorReleasedWithoutSupportedReleased().');
    

    never bee called

  2. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,397 @@
    +      'version_major' => (int) $existing_release['version_major'],
    

    There's SO much casting to int throughout. Is it at all possible to ensure they are ints before returning them?

  3. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,397 @@
    +   * @param string|null $major
    

    int|null?

  4. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,397 @@
    +          'support_end' => '11/01/21',
    

    YYYY MM DD please (see https://xkcd.com/1179)

  5. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,397 @@
    +   * @return array
    

    array|null?

tedbow’s picture

StatusFileSize
new31.25 KB
new52.08 KB

@tim.plunkett thanks for the review.

  1. Fixed. I will 🐝 careful of this in the future
  2. Sorry about that. I casted much of these away and this patch goes from 22 (int) instances to 7.
  3. Fixed
  4. Fixed. I feel like real programmer now! (see https://xkcd.com/378)
  5. fixed

This patch also does a bunch of refactoring. I talked with @xjm about this and the changes from that discussion are

  1. Took out all logic that reads LTS information from the xml. we can add this in follow once it is determine what drupa.org should provide. We will probably want to get that in ASAP after this issue because if doesn't get in before 8.8.0 is released then any site that is on 8.8.0 and doesn't update to patch releases will not get any updated information about 8.8.0 overage window. though maybe this is unlikely to change. If it is likely to change but be extended at least we won't be telling them they are covered when they are not.
  2. limited the LTS logic here to hard-coding the dates for 8.9 and 8.8.
  3. I also did not now that 8.8 is really security covered for a year and the coverage window is not strictly connected to other releases.
  4. I added a extra warning when 8.8 is six months away from being unsupported like there is for other release in this patch that covered for 2 minors. In those cases a warning if given if it is 1 minor(six months roughly) away from losing coverage.
  5. Per discussion with @xjm I did not add warning based on 8.9, the LTS, being six months away from coverage expiring.

Another possible change that didn't get into this patch is that the current update XML from Drupal.org does have supported_majors which could be helpful
Presumably if is 8 is not in that list then the LTS(and all other drupal 8 releases are unsupported). So this maybe a way now we could put logic in cover the unlikely scenario that the 8.9 LTS window is shortened.

If supported_majors does not contain 8 we could give an unsupported message regardless of whether we are in the hard coded LTS dates.

I am including an interdiff from #66 because most the changes in #67aren'trelevantt anymore.

tedbow’s picture

StatusFileSize
new30.97 KB
new51.96 KB
+++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
@@ -345,6 +345,259 @@ public function securityUpdateAvailabilityProvider() {
+    file_put_contents('/Users/ted.bowman/Sites/www/test.html', $this->getSession()->getPage()->getOuterHtml());

🤦‍♂️😞 sorry

Interdiff from 66 again to see all in 1 file

On the positive side the patch just got a little smaller!!! 🎉🎊🥳

Status: Needs review » Needs work

The last submitted patch, 75: 2991207-75.patch, failed testing. View results

tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new1.88 KB
new52 KB
  1. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,387 @@
    +            '%project' => $project_data['title'],
    

    This another instance should be $project_data['name'] not 'title'. fixed which caused test fail

  2. +++ b/core/modules/update/src/UpdateHelper.php
    @@ -0,0 +1,387 @@
    +    if ($project_data['project_type'] == 'core') {
    

    Should be ===

tedbow’s picture

drumm’s picture

Which has "Recommended major version" for each branch
Is this stored on the project itself? maybe we could have a multi-value field "LTS-Minors". The you could have 1 minor and 1 end for each major branch that has any releases.

So right now for core it could have a "8 lts branch" and "8 lts end date". Then as soon as 9.0.0 is released you could add a "9 lts branch" and "9 lts end data", though you won't have too.

This is stored in a D5-era efficient custom table. Drupal.org doesn’t exactly have any sort of real entity for a “branch” that’s extended with fields. Release nodes are sometimes dev releases, and those do have fields. And/or we can extend that old table.

I’m thinking we’ll just do a one-off settings.php variable to store this on Drupal.org:

$conf['drupalorg_core_lts'] = [
  '8.8.x' => ['end' => 'future date', 'message' => 'maybe a message too?'],
];

With whatever data is needed to support this.

benjifisher’s picture

Status: Needs review » Needs work
  1. I would like to see the class of helper functions replaced with something more object-oriented:
        +  public static function getSecurityCoverageInfo(array $project_data, array $releases) {
        +  private static function getSupportUntilReleaseInfo(array $project_data, array $releases) {
        +  private static function getSecurityCoverageMessage(array $project_data) {
        +  public static function getSecurityCoverageRequirement(array $project_data) {
        +  private static function getLtsRequirement(array $project_data) {
        +  private static function createRequirementForSupportEndDate(array $project_data, $end_date_string, $warn_at = '') {
        

    That is a lot of functions passing around $project_data. If we make that a class property, then it will simplify things a little. It would also mean you only have to write one doc block for the $projectData variable. That would give us an opportunity to give some helpful documentation about the expected structure of this variable instead of the minimal "The project data" description.

    In fact, as I try to review this patch, I am frustrated by not knowing what sort of information to expect in that variable. I think that adding such documentation is more important than simplifying the code by not passing around the variable all the time. The documentation would also help when the time comes to update the XML feed that (I think) ends up populating that array.

    I would create a ProjectData helper class, with a $projectData property that is set in the constructor. This class would have the responsibility of "knowing" the update data about a project, and answering questions via its methods.

    All of the methods I listed above would be part of this class. There are a few other methods in the current UpdateHelper class that do not seem to use $project_data. I am not sure what to do with them: leave them in the class or move them somewhere else.

    If there is existing code that uses the same project data, then we should consider moving it into the new class in a follow-up issue.

  2. +  private static function getAdditionalSecuritySupportedMinors(array $security_supported_release_info, array $releases) {
    +  private static function getSupportUntilReleaseInfo(array $project_data, array $releases) {
    +  private static function getMostRecentFullRelease(array $releases, $major = NULL) {
    +  private static function getSecurityCoverageMessage(array $project_data) {
    +  private static function isNextMajorReleasedWithoutSupportedReleased(array $releases, array $security_supported_release_info) {
    +  private static function getLtsRequirement(array $project_data) {
    +  private static function getVersionNotSupportedMessage($project, $minor_version) {
    +  private static function getAvailableUpdatesMessage() {
    +  private static function createRequirementForSupportEndDate(array $project_data, $end_date_string, $warn_at = '') {
        

    Why all the private functions? Normally we make everything public or protected, in case someone needs to extend our class and override some of them.

tedbow’s picture

Assigned: Unassigned » tedbow

@benjifisher thanks for the review!

I am working a refactor that is along the lines of what you asked for.

tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new34.45 KB
new53.36 KB

re #80

@benjifisher thanks again for the review!

  1. I would like to see the class of helper functions replaced with something more object-oriented:

    Yep, I agree. the helper class started out as just way not mess to the functions in update.compare.inc but they have gotten more complicated.

  2. +++ b/core/modules/update/update.compare.inc
    @@ -425,6 +428,8 @@ function update_calculate_project_update_status(&$project_data, $available) {
    +  $project_data['security_coverage_info'] = UpdateHelper::getSecurityCoverageInfo($project_data, $available['releases']);
    +
    
    +++ b/core/modules/update/update.install
    @@ -36,6 +37,10 @@ function update_requirements($phase) {
    +      if ($core_coverage_requirement = UpdateHelper::getSecurityCoverageRequirement($data['drupal'])) {
    +        $requirements['coverage_core'] = $core_coverage_requirement;
    +      }
    

    I realized that this helper class was actually handling 2 different tasks

    1) calculating the security coverage information and 2) constructing the security coverage message for hook_requirments based on that and other project data.

    I thought these 2 tasks called some common functions but I was wrong.

    So split UpdateHelper into 2 new classes.

    1) ProjectSecurityCoverageCalculator which needs the $project_data and $releases and exposes getSecurityCoverageInfo().

    2) ProjectSecurityRequirement which using the coverage and other project information to create the info that hoo_requirments needs for the security coverage requirement.

  3. Why all the private functions? Normally we make everything public or protected

    I think this is case where we really don't want this to extensible. This is logic that is tied to the Drupal projects security coverage policy. I think we should lock this down as much as possible and not encourage developer to extend or alter this.

    If a developer really wants to alter this they can implement hook_update_status to alter the security coverage info, really not a good idea but possible

    These are not services as of now and I don't think they should be. This is not something that should be swapped out. So having the methods as private I don't think is that big a deal.

    We do use private methods in some cases in core.

    As far as changing the security coverage requirement from update_requirments() this is not possible but this the same for all results of hook_requirments. Again I don't think a developer should do this but there is an existing issue to allow it #309040: Add hook_requirements_alter()

tedbow’s picture

+++ b/core/modules/update/src/ProjectSecurityRequirement.php
@@ -0,0 +1,235 @@
+  private function getLtsRequirement() {
+    if (!($this->projectData['project_type'] === 'core' && $this->projectData['name'] === 'drupal' && (int) $this->projectData['existing_major'] === 8)) {
+      return [];
+    }
+    $minor_version = explode('.', $this->projectData['existing_version'])[1];
+    $requirement = [];
+    if ($minor_version === '8') {
+      $requirement = $this->createRequirementForSupportEndDate('2020-12-02', '6 months');
+    }
+    elseif ($minor_version === '9') {
+      $requirement = $this->createRequirementForSupportEndDate('2021-11-01');
+    }
+    return $requirement;
+  }

I think this logic should probably be moved to a new \Drupal\update\ProjectSecurityCoverageCalculator::getSupportUntilDateInfo()

That way the all the determine about when support should end whether it is based on a date(hard-code for now) or would be in ProjectSecurityCoverageCalculator

and then \Drupal\update\ProjectSecurityRequirement::getSecurityCoverageRequirement() could just evaluate that and make the requirement.

working on that now.

tedbow’s picture

Status: Needs review » Needs work
tedbow’s picture

StatusFileSize
new13.09 KB
new53.55 KB
  1. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
    @@ -0,0 +1,235 @@
    + private function getAvailableUpdatesMessage() {

    This can be a static function

  2. Also fixing #83
tedbow’s picture

Status: Needs work » Needs review

whoops

tedbow’s picture

StatusFileSize
new5.79 KB
new54.45 KB
+++ b/core/modules/update/src/ProjectSecurityRequirement.php
@@ -0,0 +1,220 @@
+    $time = \Drupal::service('datetime.time');
...
+      $date_formatter = \Drupal::service('date.formatter');

Implemented ContainerInjectionInterface to get rid of these

benjifisher’s picture

Assigned: tedbow » Unassigned
Status: Needs review » Needs work

Thanks for these updates! It is looking a lot easier to review now, although right now I only have time for a few comments.

In the long run (follow-up issues) I would like to see the documentation moved from UpdateManagerInterface::getProjects() and update_process_project_info() to the new class.

I am looking at ProjectSecurityCoverageCalculator.

  /**
   * Constructs a ProjectUpdateData object.
   *
   * @param array $project_data
   *   Project data form Drupal\update\UpdateManagerInterface::getProjects().
   * @param array $releases
   *   Project releases as returned by update_get_available().
   */
  public function __construct(array $project_data, array $releases) {

I suggested a class named ProjectData, and apparently you considered ProjectUpdateData before settling on ProjectSecurityCoverageCalculator. As a general rule, shorter is better. According to Object-oriented code,

Classes and interfaces should have names that stand alone to tell what they do without having to refer to the namespace, read well, and are as short as possible without losing functionality information or leading to ambiguity.
...
If necessary for clarity or to prevent ambiguity, include the last component of the namespace in the name.

So I guess ProjectUpdateData might be better than my original suggestion.

The one public method in the class (other than the constructor) is getSecurityCoverageInfo(), so I think it is redundant to include "security coverage" in the class name. That also makes it hard to add other public methods to the class. Please consider reverting to a name based on the data the class contains rather than the information we get out of it.

There is a typo in the dock block ("form" instead of "from").

Please mention in the @param comment that $project_data is also modified by update_process_project_info(). I got as far as seeing that is where the existing_version key is added.

Please be consistent in @var and @see comments about including the leading backslash. We usually leave it off, don't we?

I will continue my review later.

tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new177.37 KB
new4.91 KB
new54.47 KB
  1. Please be consistent in @var and @see comments about including the leading backslash. We usually leave it off, don't we?

    It appears we usually have it if it is referring to a namespaced item but for no namespaced items we don't have it.
    so it should be removed here
    * @see \update_get_available()
    fixed

  2. Please mention in the @param comment that $project_data is also modified by update_process_project_info(). I got as far as seeing that is where the existing_version key is added.

    fixed

  3. There is a typo in the dock block ("form" instead of "from").

    fixed

  4. Please consider reverting to a name based on the data the class contains rather than the information we get out of it.

    Right now I am changing the class name to ProjectSecurityData and the method name to getCoverageInfo().

    I think this removes the redundant info from the method name.

    I don't think we should name it ProjectUpdateData because the class is already pretty complicated with security only logic. I addition this only covers the current policy for security coverage for minor and the LTS logic for core. When have to extract the LTS dates from the XML it will be even more complicated. If contrib adds security coverage there will probably some minor changes between core and contrib which make it more complicated.

    I don't think we want to have this class take over extracting all information about project updates.

    I have uploaded an xml document that is just for Drupal core that the update module receives.

    If the goal of this class was represent all update data would eventually have to add all of these public methods

    getTitle()
    getReleases()
    getSupportedMajors()
    isCurrentMajorSupported()
    getDefaultMajor()
    getExistingRelease()
    getTerms()
    getApiVersion()
    getDevelopmentStatus()
    isActivelyMaintained()
    getMaintenanceStatus()
    isActivelyMaintained()
    getProjectType()
    

    Above is all the methods just from reading the existing xml if we want to move all the logic that is done elsewhere into this class like getCoverageInfo() we would also have to add methods like

    getInstallType()
    getStatusReason()
    getProjectStatus()
    getLatestVersion()
    getRecommendVersion()
    getLatestDevVersion()
    

    These just the things I saw in update.compare.inc. This probably stuff elsewhere. I would prefer to keep this class focused just on security.

Taking another look at ProjectSecurityRequirement too.

  1. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
    @@ -0,0 +1,248 @@
    +   * Constructs ProjectUpdateData object.
    

    Class name needs updating

  2. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
    @@ -0,0 +1,248 @@
    +   *   The 'security_coverage_info' key should be set calling this method.
    

    Adding referece to setting this key from ProjectSecurityData::getCoverageInfo()

  3. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
    @@ -0,0 +1,248 @@
    +  public function getSecurityCoverageRequirement(array $project_data) {
    

    Changing to getRequirment() to remove redundant info from class name.

  4. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
    @@ -0,0 +1,248 @@
    +   *   An array if there is security coverage requirement, otherwise NULL.
    

    Changing to

    Requirements array as specified by hook_requirements().

    This will never be null.

tim.plunkett’s picture

  1. +++ b/core/modules/update/src/ProjectSecurityData.php
    @@ -0,0 +1,217 @@
    +    if (empty($this->releases[$this->projectData['existing_version']])) {
    +      return [];
    +    }
    +    $existing_release = $this->releases[$this->projectData['existing_version']];
    +
    +    if (!empty($existing_release['version_extra'])) {
    +      return [];
    +    }
    +    // Minors 8.8 and 8.9 have special logic for security support.
    

    Super nit, but the blank lines are weird here. Usually I see a blank line after any guard condition (one that returns early).

  2. +++ b/core/modules/update/src/ProjectSecurityData.php
    @@ -0,0 +1,217 @@
    +   * @param array $security_supported_release_info
    +   *   Release information as return by update_get_available().
    

    It would have been very nice if update_get_available() returned data objects instead of ArrayPI, but that's not this patch's fault. However, is it worth *not* typehinting array in cases where it's not a iterable set?

  3. +++ b/core/modules/update/src/ProjectSecurityData.php
    @@ -0,0 +1,217 @@
    +   * @throws \Exception
    ...
    +          throw new \LogicException('::getAdditionalSecuritySupportedMinors() should never be called before checking ::isNextMajorReleasedWithoutSupportedReleased().');
    

    This should say when it is thrown on the next line, and also have the more specific LogicException

  4. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
    @@ -0,0 +1,250 @@
    +  public function getRequirement(array $project_data) {
    +    $this->projectData = $project_data;
    

    This is a problem for me. Unlike the other class, which takes $project_data in the constructor, this one mutates the state via a public method.

    While the class continues to only have the one public method, that is probably fine. But the minute another method is added, that statefulness can start to cause very odd bugs.

    I understand the desire to use ContainerInjectionInterface, so I'm not sure what to suggest instead...

  5. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
    @@ -0,0 +1,250 @@
    +        $requirement['title'] = t('Drupal core security coverage');
    

    $this->t(), here and throughout

  6. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
    @@ -0,0 +1,250 @@
    +      $message = '<p>' . t(
    +          'The installed minor version of %project, %version, will receive security updates until the release of %coverage_version.',
    +          [
    +            '%project' => $this->projectData['title'],
    +            '%version' => "$major.$minor",
    +            '%coverage_version' => $security_info['support_end_version'],
    +          ]
    +        ) . '</p>';
    

    The line breaks and indents here are weird and hard to read. Perhaps creating local variable of the array of % args, and then the rest can be a oneliner?

  7. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
    @@ -345,6 +345,258 @@ public function securityUpdateAvailabilityProvider() {
    +  public function testSecurityCoverageMessage($site_patch_version, $requirements_section_message, $fixture, array $coverage_messages = [], array $not_contains_messages = [], $mock_date = '') {
    

    I understand why there's a functional test, but is it also possible to have a unit test for the more straightforward parts of the logic?

Status: Needs review » Needs work

The last submitted patch, 89: 2991207-89.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new12.61 KB
new53.62 KB

@tim.plunkett thanks for the review!

  1. fixed
  2. I don't think we should make the distinct. I get a phcs error "missing parameter type" if I leave this out.
  3. Fixed but I wondering if we even need isNextMajorReleasedWithoutSupportedReleased() now. I think this was stop gap when this patch didn't include logic for the drupal 8 LTS release. Will update the issue after I chat with @xjm
  4. Yeah didn't like this change especially. Changing it back not use ContainerInjectionInterface
  5. fix.
  6. Changed to onliner to fix. Also created $next_minor variable so the next use of $this->t() can be a 2 liner.
  7. will work on the test. Uploading the rest of the changes for now.
tedbow’s picture

StatusFileSize
new1.47 KB
new53.7 KB
  1. +++ b/core/modules/update/tests/modules/update_test/drupal.sec.2.0_9.xml
    @@ -0,0 +1,157 @@
    +            <name>Drupal 8.3.0</name>
    +            <version>8.3.0</version>
    +            <tag>DRUPAL-8-3-0</tag>
    +            <version_major>8</version_major>
    +            <version_minor>2</version_minor>
    

    version_minor is wrong here

  2. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
    @@ -345,6 +345,258 @@ public function securityUpdateAvailabilityProvider() {
    +    if ($requirements_section_message) {
    ...
    +    else {
    +      $this->assertEmpty($coverage_messages, 'If messages are expected a requirements section most be provided');
    +      $this->assertEmpty($not_contains_messages, 'If messages to confirm do not exist are provided a requirements section most be provided');
    +    }
    

    This else here basically just tests if the provided arguments aren't wrong not the test output. If $requirements_section_message is not provided there is no section on the status report for core security coverage so we can't test if something is or isn't there.

    but we should check to make sure "Drupal core security coverage" doesn't appear on the page at all. Since we don't expect there to a section.

  3. I have another patch that addresses my question in #92.3 but either way these 2 points need to be fixed.
tedbow’s picture

StatusFileSize
new7.76 KB
new50.77 KB

re #92.3

ProjectSecurityData currently has logic to check if the next major version has been released and the version the installed version is suppose to be covered until has not been released. In that case we don't show any message because this wasn't suppose to happen so we we don't know that coverage.

but now that we have explicit coverage dates for 8.8.x and 8.9.x we probably can get rid of that. This could only effect 8.6.x and 8.7.x because any other minor release has already had the version they are supported to released. For 8.6.x 8.8.0 should be released in December so there is no way it won't be released before 9.0.0. So that only leaves 8.7.x which should be supported until 9.0.

If the logic I mentioned is removed then 9.0.0 is released and 8.9.0 has not been released 8.7.x installs would still get supported until 8.9.0 message. Of course this assumes that this patch is backported to 8.7.x

Here is a patch with that logic removed. You can see the changes in the test cases. It makes ProjectSecurityData much simpler.

tedbow’s picture

Assigned: Unassigned » tedbow
Issue summary: View changes

Updated the proposed solution

I will next update the screenshots in the summary

tedbow’s picture

Added update screenshots to summary

tedbow’s picture

StatusFileSize
new15.83 KB
new57.64 KB
  1. +++ b/core/modules/update/src/ProjectSecurityData.php
    @@ -0,0 +1,148 @@
    +    if ($minor_version === '8') {
    +      $info['support_end_date'] = '2020-12-02';
    +      $info['support_ending_warn_date'] = '2020-6-02';
    +    }
    +    elseif ($minor_version === '9') {
    

    This logic if we didn't update it in the Drupal 9 cycle would have cause these dates to be used for 9.9 and 9.8 messages.

    also we could have not found out about it until 9.8 because there was test coverage.

  2. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
    @@ -345,6 +345,266 @@ public function securityUpdateAvailabilityProvider() {
    +      '0.0, unsupported' => [
    +        'site_patch_version' => '0.0',
    

    All of the test case assumed 8.x.x

    changing to send complete version number so we can test 9.8 and 9.9

  3. Adding test for 9.9 and 9.8 to prove they follow the 2 minors pattern.

Status: Needs review » Needs work

The last submitted patch, 97: 2991207-97.patch, failed testing. View results

tedbow’s picture

Assigned: tedbow » Unassigned
Status: Needs work » Needs review
StatusFileSize
new1.52 KB
new57.54 KB
+++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
@@ -345,6 +345,296 @@ public function securityUpdateAvailabilityProvider() {
+    $test_cases['8.9, lts 6 month'] = $test_cases['8.9, lts'];

I forgot to update the key for the test case here so got an undefined index error.

+++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
@@ -345,6 +345,296 @@ public function securityUpdateAvailabilityProvider() {
+      file_put_contents('/Users/ted.bowman/Sites/www/test.html', $this->getSession()->getPage()->getOuterHtml());

also whoops

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.

benjifisher’s picture

Version: 8.9.x-dev » 8.8.x-dev
Status: Needs review » Needs work

@tedbowman, thanks for your continued work on this. I am sorry my promised review is so long delayed.

I also apologize for the mix of nit-picks among the other comments. It is the result of how I review a patch.

  1. Fixing all the technical debt in the Update module is way outside the scope of this issue. The problem is that this debt is making it hard for me to see what is going on and do an honest review. I think the changes you have already made will help when we decide to reduce that debt in future issues. For now, what would really help is more documentation on the projectData and releases properties. Even if you just document the keys that the new classes expect and add, that would make it much easier to review this issue. You can add a disclaimer, "Other keys are ignored" or something. The @see references are helpful, but the functions they reference do not document these keys. Adding documentation there seems out of scope for this issue.
  2. Sorry for nit picking. You can leave it as is if you disagree.
    @@ -36,6 +37,10 @@ function update_requirements($phase) {
           $data = update_calculate_project_data($available);
           // First, populate the requirements for core:
           $requirements['update_core'] = _update_requirement_check($data['drupal'], 'core');
    +      if ($core_coverage_requirement = (new ProjectSecurityRequirement($data['drupal']))->getRequirement()) {
    +        $requirements['coverage_core'] = $core_coverage_requirement;
    +      }
        

    Generally, we try to keep code lines under 80 characters. We can do that by making the assignment outside the conditional:

          $requirement = (new ProjectSecurityRequirement($data['drupal']))
            ->getRequirement();
          if ($requirement) {
            $requirements['coverage_core'] = $requirement;
          }
        

    Since the variable is never referenced again, I think it is OK to give it a short name. Alternatively,

          $project = new ProjectSecurityRequirement($data['drupal']);
          if ($requirement = $project->getRequirement()) {
            $requirements['coverage_core'] = $requirement;
          }
        
  3. +++ b/core/modules/update/update.compare.inc
    @@ -296,6 +298,7 @@ function update_calculate_project_update_status(&$project_data, $available) {
       foreach ($available['releases'] as $version => $release) {
         // First, if this is the existing release, check a few conditions.
         if ($project_data['existing_version'] === $version) {
    +      $project_data['existing_release'] = $release;
           if (isset($release['terms']['Release type']) &&
               in_array('Insecure', $release['terms']['Release type'])) {
             $project_data['status'] = UPDATE_NOT_SECURE;
    @@ -425,6 +428,8 @@ function update_calculate_project_update_status(&$project_data, $available) {
         $project_data['recommended'] = $project_data['latest_version'];
       }
     
    +  $project_data['security_coverage_info'] = (new ProjectSecurityData($project_data, $available['releases']))->getCoverageInfo();
        

    I hate this function. The doc block is 61 lines long, and the body (before this patch) is 311 lines long. Fixing it is outside the scope of this issue, but I hope that the classes we add here will make it easier to refactor this function.

    This function adds several keys to the $project array (passed by reference). If the doc block described the existing keys, then adding the two new ones would be in scope for this issue. Maybe it is in scope for this issue to describe all the keys.

    Same nit as in #2 (but leave it as is if you disagree): I would like to see the long line broken up.

  4. +++ b/core/modules/update/src/ProjectSecurityData.php
    @@ -0,0 +1,148 @@
    +<?php
    +
    +namespace Drupal\update;
    +
    +/**
    + * Calculates a projects security coverage information.
        

    Another nit: it should be "project's" (possessive).

  5. +  /**
    +   * Constructs a ProjectUpdateData object.
    ...
    +  public function __construct(array $project_data, array $releases) {
        

    There is still a mismatch between the class name and the doc block comment.

  6. +  public function getCoverageInfo() {
    +    $info = [];
    +    if (!($this->projectData['project_type'] === 'core' && $this->projectData['name'] === 'drupal')) {
    +      // Only Drupal core has an explicit coverage range.
    +      return [];
    +    }
    +    $minor_version = explode('.', $this->projectData['existing_version'])[1];
    +    // Support for Drupal 8's LTS release and the version before are based on
    +    // specific dates.
    +    if ($this->projectData['existing_major'] === '8' && $minor_version === '8') {
        

    I think that $projectData['existing_major'] is the major version of Drupal that a project (in this case, Drupal core itself) is compatible with. Isn't that information likely to change now that other projects can be compatible with more than one version of Drupal core? Since this code just deals with Drupal core, I think it will be more reliable, and clearer, to get the major and minor versions from the same key as in ProjectSecurityRequirement::getVersionEndCoverageMessage():

          list($major_version, $minor_version) = explode('.', $this->projectData['existing_version']);
          if ($major_version === '8' && $minor_version === '8') {
          // ...
        

    Or maybe we can get the major and minor versions from $this->releases[$this->projectData['existing_version']]?

  7. +      $info['support_ending_warn_date'] = '2020-6-02';
        

    Use "06" instead of "6".

  8. +   * @return array
    +   *   The release information.
    +   */
    +  private function getSupportUntilReleaseInfo() {
        

    Document the keys and their types: version_major, version_minor, and version_patch are type int and version is string. If the information is not available, then the function returns an empty array.

  9. +  /**
    +   * Gets the number of additional minor releases supported.
    +   *
    +   * @param array $security_supported_release_info
    +   *   The security supported release.
    +   *
    +   * @return int
    +   *   The number of additional supported minor releases.
    +   */
    +  private function getAdditionalSecuritySupportedMinors(array $security_supported_release_info) {
        

    The @param comment should include "as returned by getSupportUntilReleaseInfo()".

  10. +    if (isset($latest_minor)) {
    +      if ($security_supported_release_info['version_minor'] <= $latest_minor) {
    +        return -1;
    +      }
    +      return $security_supported_release_info['version_minor'] - $latest_minor;
    +    }
    +    return NULL;
        

    I think this would be clearer:

        return isset($latest_minor)
          ? $security_supported_release_info['version_minor'] - $latest_minor
          : NULL;
        

    Then adjust the code where this value is used to test $value <= 0 instead of $value == -1. In fact, this value is checked in ProjectSecurityRequirement and the test is $value > 0, so perhaps no adjustment is needed.

  11. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
    @@ -0,0 +1,214 @@
    +  /**
    +   * Drupal project data..
    ...
    +  protected $projectData;
        

    Nit: remove the extra '.'.

  12. +  /**
    +   * Gets the security coverage requirement if any.
    +   */
    +  public function getRequirement() {
        

    Document the return value. The same comment as on getVersionEndRequirement() and getDateEndRequirement() would be fine.

  13. +  public function getRequirement() {
    +    if ($this->projectData['project_type'] === 'core' && $this->projectData['name'] === 'drupal') {
    +      if (!empty($this->projectData['security_coverage_info'])) {
    ...
    +      }
    +    }
    +    return NULL;
    +  }
        

    I would rather have two early return NULL; lines.

  14. Can you rearrange the helper functions in a more logical order? After the public getRequirement() refers to getVersionEndRequirement(), I expect to see that function next. Instead, it is at the end of the file.
  15. +        $requirement['title'] = $this->t('Drupal core security coverage');
    +        if (isset($this->projectData['security_coverage_info']['support_end_version'])) {
    +          $requirement += $this->getVersionEndRequirement();
    +        }
    +        elseif (isset($this->projectData['security_coverage_info']['support_end_date'])) {
    +          $requirement += $this->getDateEndRequirement();
    +        }
        

    Maybe pass $requirement by reference? It would save a couple of lines in each of the helper functions and make this snippet a little simpler.

  16. +   * @param string $minor_version
    +   *   The installed minor version.
    ...
    +   */
    +  private function getVersionNotSupportedMessage($minor_version) {
        

    Since this method is called with the argument "$major.$minor", I would call the variable $version.

  17. +  private function getDateEndRequirement() {
    +    $requirement = [];
    +    list(, $minor_version) = explode('.', $this->projectData['existing_version']);
    +    $current_minor = "{$this->projectData['existing_major']}.$minor_version";
        

    Same comment as in #6: shouldn't we get both major and minor versions from $this->projectData['existing_version']? Also, I think $current_version would be a clearer variable name than $current_minor since it includes both major and minor versions.

    We might even consider making all of these (major, minor, combined) into class properties, set in the constructor.

  18. +  private function getDateEndRequirement() {
    ...
    +    /** @var \Drupal\Component\Datetime\Time $time */
    +    $time = \Drupal::service('datetime.time');
    +    $request_time = $time->getRequestTime();
    ...
    +      /** @var \Drupal\Core\Datetime\DateFormatterInterface $date_formatter */
    +      $date_formatter = \Drupal::service('date.formatter');
        

    I see in the last few comments that you have been struggling with whether to inject the service container. Calling \Drupal::service() from OO code is discouraged, but I am not sure what the best solution is.

  19. +    if ($end_timestamp <= $request_time) {
    ...
    +      $requirement['severity'] = SystemManager::REQUIREMENT_ERROR;
    ...
    +    else {
    ...
    +      $requirement['severity'] = SystemManager::REQUIREMENT_WARNING;
    ...
    +    }
        

    It looks as though getDateEndRequirement() always returns an error or a warning. Is this what we want? What if the installed version is the latest available?

tedbow’s picture

Version: 8.8.x-dev » 8.9.x-dev
Status: Needs work » Needs review
StatusFileSize
new20.4 KB
new60.23 KB

@benjifisher thanks for the through review!

  1. Added the documentation projectData in both classes and for releases
  2. There is exception for control structures

    Control structure conditions may exceed 80 characters, if they are simple to read and understand:

    I think it is readable the way it is.

  3. I share your dislike for this function.

    If the doc block described the existing keys, then adding the two new ones would be in scope for this issue. Maybe it is in scope for this issue to describe all the keys.

    But it adds by my count 14 keys title, link, status, extra, reason, project_status, fetch_status, also, releases, latest_version, dev_version, recommended, security updates, latest dev
    And some of these have sub-keys. Documenting all of those would be a major amount of work.

    I think we should create a follow up to either, 1) document all added keys, or 2) Create class and split the logic into multiple methods that each add a set of keys that are related. But probably before we did that we should make sure we have very comprehensive test coverage of the existing functionality so didn't accidently change anything.

    +++ b/core/modules/update/update.compare.inc
    @@ -296,6 +298,7 @@ function update_calculate_project_update_status(&$project_data, $available) {
    +      $project_data['existing_release'] = $release;
    

    I made a change to \Drupal\update\ProjectSecurityRequirement::getVersionEndCoverageMessage() which is the only place we read this so we don't actually need this change. I figure with the amount of keys this function already adds we should avoid adding more than we need to.

    Added a comment in the docblock to detail the remaining 'security_coverage_info' key.

    Same nit as in #2 (but leave it as is if you disagree): I would like to see the long line broken up.

    Changed to

    $security_data = new ProjectSecurityData($project_data, $available['releases']);
      $project_data['security_coverage_info'] = $security_data->getCoverageInfo();

    The first line is a couple chars over 80 but I think this is fine the standards mention exceptions for longer var names.
    I would rather have the var name be more descriptive then hit 80 exactly.

  4. fixed
  5. whoops. thought I fixed that. Fixed
  6. I think that $projectData['existing_major'] is the major version of Drupal that a project (in this case, Drupal core itself) is compatible with.

    No this is the major version of the project itself. See update_process_project_info()

    // Figure out what the currently installed major version is. We need
    // to handle both contribution (e.g. "5.x-1.3", major = 1) and core
    // (e.g. "5.1", major = 5) version strings.
    $matches = [];
    if (preg_match('/^(\d+\.x-)?(\d+)\..*$/', $info['version'], $matches)) {
    $info['major'] = $matches[2];
    }

    At the end of the function it is assigned to 'existing_major'

    But we can as you point out get this info from $this->releases[$this->projectData['existing_version']]. So this avoids exploding the string here I think it is good.

    Also now have to add

    if (empty($this->releases[$this->projectData['existing_version']])) {
          // If the existing version does not have a release we cannot get the
          // security coverage information.
          return [];
        }

    Otherwise the test would have an exception -dev version don't have a release. They were already not getting a message because version_extra would not have been empty.
    Fixed.

    UPDATE: this actually exposed problem with the tests.
    core/modules/update/tests/modules/update_test/drupal.sec.9.0.xml
    didn't actually have a 8.8.0 release but it was being used to test sites being on 8.8.0. Because before it was using 'existing_version' we didn't actually check if the release existed. fixed this.

  7. fixed
  8. Added but removed version_patch because this never used this is private method.
  9. fixed
  10. NIce, much more concise. Fixed
  11. Fixed
  12. Fixed
  13. I added 1 early return and realized I really didn't need
    if (!empty($this->projectData['security_coverage_info'])) {

    Because the next 2 ifs actually check if 2 other keys are set under 'security_coverage_info'. If they aren't it doesn't matter if security_coverage_info is empty or not. so return NULL after that.

    I think your intention was to get rid of the all code being nested in 2 ifs. which this does.

  14. I looked at the order and I think just the one mentioned needs reordering. Fixed.
  15. I rearranged the code in this block earlier in 13) here to not use += and not assign title until we are sure we have a requirement. Otherwise it looked like you could return a requirement with just a title. so I think passing by reference doesn't make sense anymore
  16. Fixed and updated the comment.
  17. Fixing here we don't have releases though so slightly different fix.

    We might even consider making all of these (major, minor, combined) into class properties, set in the constructor.

    I made existingMajor and existingMinor but then say were used multiple times as "{$this->existingMajor}.{$this->existingMinor} and the only other place to figure out the next minor.

    So I just made class properties existingVerion and nextVersion.

  18. See @tim.plunkett's comment in #90.4 and my response in #92.4

    I think this better that using ContainerInjectionInterface which would get rid of \Drupal::service() but also not allow setting the project data in the constructor.

    I think the current solution in the lesser of 2 evils.

  19. I am not sure about this. When I talked to @xjm she said that she didn't want to change the message with 8.9 lts as we got closer to ending support. So in this case I don't think we want to change from info to warning if we aren't changing the message.

    I don't think using info for the whole LTS period seems correct so I choose warning.

    If are using warning for the whole LTS I think we should also for 8.8 which only supported a year.

    My personal opinion is that we should change the message 6 months before LTS ends and change from info to warning.

tim.plunkett’s picture

Only nits left. The last couple interdiffs have been great.

  1. +++ b/core/modules/update/src/ProjectSecurityData.php
    @@ -0,0 +1,167 @@
    + * @internal
    

    I think this is supposed to explain _why_ it's internal (here and elsewhere)

  2. +++ b/core/modules/update/src/ProjectSecurityData.php
    @@ -0,0 +1,167 @@
    +   * @var array
    ...
    +   * @var array
    

    Can these be string[]? Not essential, just know that it might get asked by a committer.

  3. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
    @@ -0,0 +1,239 @@
    +      $translation_arguments = [
    +        '%project' => $this->projectData['name'],
    +        '%version' => $this->existingVersion,
    +        '%coverage_version' => $security_info['support_end_version'],
    +      ];
    +      $message = '<p>' . $this->t('The installed minor version of %project, %version, will receive security updates until the release of %coverage_version.', $translation_arguments) . '</p>';
    ...
    +      $requirement['description'] = '<p>' . $this->t(
    +          'The installed minor version of %project, %version, will receive security updates until %date.',
    +          [
    +            '%project' => $this->projectData['name'],
    +            '%version' => $this->existingVersion,
    +            '%date' => $date_formatter->format($end_timestamp, 'html_date'),
    +          ]
    +        ) . '</p>';
    

    The first one is SO much more legible than the second one... But that's just a nit.

tedbow’s picture

StatusFileSize
new2.48 KB
new60.59 KB
  1. fixed.
  2. I don't think so. The keys in the array that we using are all strings but there so many places these get processed along the way. Some of the value are arrays themselves and with alter hook we can't guarantee anything.
  3. legibility is good. Fixed
xjm’s picture

Can these be string[]? Not essential, just know that it might get asked by a committer.

🎱🔮Signs point to yes.

benjifisher’s picture

Status: Needs review » Needs work

Only nits left. The last couple interdiffs have been great.

I agree. We are getting close!

1. Document the types (string and int) of the array returned by getCoverageInfo(). If you do not, then someone will inevitably ask whether @return array can be changed to @return string[]. ;)

2. It still seems odd to me that the LTS version is always marked as a warning.

My personal opinion is that we should change the message 6 months before LTS ends and change from info to warning.

I agree.

      if (isset($security_info['support_ending_warn_date']) && \DateTime::createFromFormat('Y-m-d', $security_info['support_ending_warn_date'])->getTimestamp() <= $request_time) {
        $requirement['description'] .= '<p>' . $this->t('Update to a supported minor version soon to continue receiving security updates.') . '</p>';
      }

This seems like the right time to use SystemManager::REQUIREMENT_WARNING instead of SystemManager::REQUIREMENT_INFO. But if you have already discussed it with @xjm, then I guess it is settled.

I have not looked at the tests at all, and I also want to do some manual testing.

tedbow’s picture

Status: Needs work » Needs review
StatusFileSize
new1.7 KB
new60.63 KB
  1. fixed
  2. @xjm is this what you meant we talked about this? Or should we use info the whole time or info and then warning at 6 months till end of LTS
xjm’s picture

Uhh I have absolutely no memory of requiring the LTS coverage message to be a warning for 18 months, so I think there's a miscommunication somewhere.

tedbow’s picture

Assigned: Unassigned » xjm
Status: Needs review » Needs work

@xjm yeah sorry that is not what I meant.

When I talked to @xjm she said that she didn't want to change the message with 8.9 lts as we got closer to ending support. So in this case I don't think we want to change from info to warning if we aren't changing the message.
I don't think using info for the whole LTS period seems correct so I choose warning.

I few questions

  1. Should we change the message if a site is on LTS and if it is 6 months until the LTS period is over? My memory is you said no. Currently in the patch all other releases get additional message
    +++ b/core/modules/update/src/ProjectSecurityRequirement.php
    @@ -0,0 +1,240 @@
    +        // If the installed minor version will only be supported for 1 newer
    +        // minor core version encourage the site owner to update soon.
    +        $message .= '<p>' . $this->t('Update to %next_minor or higher soon to continue receiving security updates.', ['%next_minor' => $this->nextVersion])
    +          . ' ' . static::getAvailableUpdatesMessage() . '</p>';
    +      }
    

    For versions that are supported for 2 minor version we warn when they are 1 minor version away from not being supported(roughly 6 months)

    +++ b/core/modules/update/src/ProjectSecurityRequirement.php
    @@ -0,0 +1,240 @@
    +      if (isset($security_info['support_ending_warn_date']) && \DateTime::createFromFormat('Y-m-d', $security_info['support_ending_warn_date'])->getTimestamp() <= $request_time) {
    +        $requirement['description'] .= '<p>' . $this->t('Update to a supported minor version soon to continue receiving security updates.') . '</p>';
    +      }
    

    For 8.8.x which is supported for 1 year, not directly tied to other minor releases, we warn when support is 6 months from ending.

    If we follow this pattern we say "Update to a supported minor version soon to continue receiving security updates." when the LTS release is 6 months from ending.

    Of course we may want to change this message because there will be no more minor releases of Drupal 8(probably). Though we could leave it as 9.0.0 is a minor release.

  2. If we don't want to add an extra ""Update to a supported...." message should the message still change from the info to warning section at 6 months?
  3. if we don't want to change the message section from info to warning within 6 months if we aren't adding an extra message do we want always have the message be an Info message right up till the day before they lose support.
tedbow’s picture

Assigned: xjm » Unassigned
Status: Needs work » Needs review

I wanted to address some questions in #109 but I found a testing error while I was looking at it. So fixing that first and then will come back to #109

  1. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
    @@ -345,6 +345,295 @@ public function securityUpdateAvailabilityProvider() {
    +      $assert_session->elementExists('css', "div:contains('$requirements_section_message') summary:contains('Drupal core security coverage')");
    

    I realize this is not testing what I thought it was.

    What I wanted to check was, make sure Drupal core security coverage was under the same div as the heading, $requirements_section_message('Warnings found', 'Errors found').

    What it was actually checking: Assert that there is at least 1 div that contains "Warnings found" and also contains a summary that contains Drupal core security coverage.

    Of course the top level div of the page would satisfy this regardless of whether "Warnings found" and Drupal core security coverage were under the same section.

    This can't be done 1 elementExists() call which is fine. This patch breaks it up into multiple asserts with comments.

    There are couple cases where $requirements_section_message was "Errors found" when it should have been "Warnings found". This was only passing because there was another message under "Errors found". In my case locally "Trusted Host Settings" I assume this is the same on Drupalci.
    I am also going to check $requirements_section_message

  2. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
    @@ -345,6 +345,295 @@ public function securityUpdateAvailabilityProvider() {
    +   * @param string $requirements_section_message
    +   *   The requirements section method.
    

    I am going to change this parameter name to $requirements_section_heading to be more clear.

  3. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
    @@ -345,6 +345,295 @@ public function securityUpdateAvailabilityProvider() {
    +        'requirements_section_message' => 'Warnings found',
    

    Also changing all of these to be 'requirements_section_heading'

  4. I am including a patch that fixes the test assert but does not fix the "Errors found" -> "Warnings Found" to prove these test cases would fail.
tedbow’s picture

Weird my patches didn't upload. Maybe because I left the tab open overnight?

Well anyways here they are 🕺

Status: Needs review » Needs work

The last submitted patch, 111: 2991207-110.patch, failed testing. View results

tedbow’s picture

StatusFileSize
new63.24 KB
new60.97 KB

wow I am nailing it today 😜

  1. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
    @@ -350,6 +350,301 @@ public function securityUpdateAvailabilityProvider() {
    +      file_put_contents('/Users/ted.bowman/Sites/www/test.html', $this->getSession()->getPage()->getOuterHtml());
    

    Whoops. removing.

  • from 2991207-110-assert-fix-only-FAIL.patch
    +++ b/core/drupalci.yml
    @@ -3,57 +3,13 @@
    +        testgroups: '--class "Drupal\Tests\update\Functional\UpdateCoreTest::testSecurityCoverageMessage"'
    

    whoops. Should have just referenced the class


  • for interdiffs see #110

    tedbow’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new63.13 KB

    third time is the charm

    Status: Needs review » Needs work

    The last submitted patch, 114: 2991207-110-assert-fix-only-FAIL.patch, failed testing. View results

    tedbow’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new1.49 KB

    I realize now I did make the changes in regards to questions in #109. I including an interdiff for the non-test changes since #107 that are in the latest working patch in #113

    1. re #109.3

      Now currently I have changed both the 8.9 LTS and the 8.8 messages to be an info message not a warning

    2. The 8.9 LTS message does not change when it is 6 months from being unsupported so it is in INFO message until the day they are unsupported, at that point it turns into an error
    3. the 8.8 message changes when they 6 months away from being unsupported. At that point it changes to warning. when the support is over it changes to an error.

    Changing back to Needs Review because #114 was expected to fail

    benjifisher’s picture

    Status: Needs review » Needs work

    The non-test changes since #104 look like what I suggested in #106, so +1 for that.

    This part of the interdiff in #116 looks very suspicious:

    +++ b/core/modules/update/src/ProjectSecurityRequirement.php
    @@ -187,7 +187,7 @@ private function getDateEndRequirement() {
    ...
    -      $requirement['severity'] = SystemManager::REQUIREMENT_WARNING;
    +      $requirement['severity'] = REQUIREMENT_INFO;
    

    We still need SystemManager::, right? See also getVersionEndRequirement().

    I will start looking at the tests now, but I do not plan to post a comment until tomorrow.

    benjifisher’s picture

    I looked at the tests, and I have some suggestions:

    1. +++ b/core/modules/update/tests/modules/update_test/drupal.sec.2.0.xml
      +++ b/core/modules/update/tests/modules/update_test/drupal.sec.2.0_3rc1.xml
      +++ b/core/modules/update/tests/modules/update_test/drupal.sec.2.0_9.xml
      +++ b/core/modules/update/tests/modules/update_test/drupal.sec.9.0.xml
      +++ b/core/modules/update/tests/modules/update_test/drupal.sec.9.9.0.xml
          

      What is the naming convention for these fixtures? (If there is none, can we come up with something more consistent and rename these files?)

      Please add a comment to the data provider, explaining what each fixture should include. See the code comment in securityUpdateAvailabilityProvider() for example.

    2. +++ b/core/modules/update/tests/modules/update_test/src/DateTime/TestTime.php
          

      Change the directory name to "Datetime" (only one uppercase letter) to be consistent with the core class this overrides. Make the corresponding change to the namespace and to update.services.yml.

      I know that PHP does not care, and the tests will work just as well either way. But this can be confusing, and when it does lead to problems, they can be very hard to spot. I noticed the discrepancy when I searched for "DateTime" in core.services.yml.

      Leave \DateTime as is.

    3. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
      @@ -350,6 +350,300 @@ public function securityUpdateAvailabilityProvider() {
           return $test_cases;
         }
       
      +  /**
      +   * Tests the Update Manager module when a security update is available.
      +   *
      +   * @param string $site_patch_version
      +   *   The patch version to set the site to for testing.
      +   * @param string $requirements_section_heading
      +   *   The requirements section heading.
      +   * @param string $fixture
      +   *   The test fixture that contains the test XML.
      +   * @param array $coverage_messages
      +   *   The expected coverage messages.
      +   * @param array $not_contains_messages
      +   *   Messages that should not appear in the coverage section.
      +   *
      +   * @dataProvider securityCoverageMessageProvider
      +   */
      +  public function testSecurityCoverageMessage($site_version, $requirements_section_heading, $fixture, array $coverage_messages = [], array $not_contains_messages = [], $mock_date = '') {
          

      Add an @param comment for $mock_date.

    4. Many of the test cases explicitly set 'mock_date' => '',, but two omit this key, relying on the default value. Can we be consistent here?
    5. Instead of the two lists of messages, $coverage_messages and $not_contains_messages, can we have a single message and assertEqual() the expected and actual messages? Something like this (untested):
            $this->assertEqual($coverage_message, $all_requirements_details->find('css', 'div.description')->getText());
          
    6. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
      @@ -350,6 +350,300 @@ public function securityUpdateAvailabilityProvider() {
      ...
      +  public function testSecurityCoverageMessage($site_version, $requirements_section_heading, $fixture, array $coverage_messages = [], array $not_contains_messages = [], $mock_date = '') {
      ...
      +    if ($requirements_section_heading) {
      +      $this->assertNotEmpty($coverage_messages, 'If a requirements section is provided expected message must be provided');
      ...
      +    }
      +    else {
      +      $assert_session->pageTextNotContains('Drupal core security coverage');
      +      $this->assertEmpty($coverage_messages, 'If messages are expected a requirements section most be provided');
      +      $this->assertEmpty($not_contains_messages, 'If messages to confirm do not exist are provided a requirements section most be provided');
      +    }
          

      It looks as though the assertEmpty() and assertNotEmpty() lines are testing the data provider. Do we need this? If not (and maybe even if we do) then I suggest negating the test condition and exiting early:

          if (empty($requirements_section_heading)) {
            $assert_session->pageTextNotContains('Drupal core security coverage');
            return;
          }
          $cover_message_locator = 'details.system-status-report__entry:contains("Drupal core security coverage")';
          ...
          
    benjifisher’s picture

    For 118.2: if you are using a Mac with the default filesystem, then neither mv DateTime Datetime nor git mv DateTime Datetime will work. The work-around is git mv DateTime Foo && git mv Foo Datetime.

    tedbow’s picture

    StatusFileSize
    new23.13 KB
    new58.47 KB

    @benjifisher thanks for the review again!

    re #117 SystemManager::REQUIREMENT_INFO doesn't exist. Changing to SystemManager::REQUIREMENT_OK works but that is a different constant value.

    \Drupal\Core\Render\Element\StatusReport::preRenderGroupRequirements() has

    requirement_severity = (int) $requirement['severity'] === REQUIREMENT_OK ? REQUIREMENT_INFO : (int) $requirement['severity'];
    

    So it basically converts but with comment a why. and REQUIREMENT_INFO === SystemManager::REQUIREMENT_OK so this works

    I looked into this further and actually no other module is using the SystemManager::REQUIREMENT_* constants although these seem to be what should be used for. Changing to use the global constant because that is what all core modules do for there hook_requirments implementations.

    re #118

    1. What is the naming convention for these fixtures?

      The name conventions follows the naming convention of the the existing XML fixtures drupal.sec.[MINOR].[PATCH]-[EXTRA].xml. Where the version numbers are for the expected security release. If there is "_" in between 2 version then there are 2 releases that could considered applicable security releases depending on the site installed version. That would be either a security release 2 minors or 2 majors. The version after the "_" here didn't have the both minor and patch so I will fix that.

      The convention didn't have a [MAJOR] in the file name because up until no we didn't have and xml files that had Drupal 9 releases. I think assume that is there is 2 parts it is the existing major and we can include the major in a version if it is not 8.

      If we want we could file a follow up to add "8." to all fixture xmls.

      Added the comment to the data provider about the fixtures and releases

    2. Good catch! Fixed
    3. fixed
    4. Added mock_date to all test cases
    5. Good call. That had gotten very convoluted. Fixed
    6. Yes this asserting the test provider not sending bad test cases. I would rather not do that is but I would like to safeguard to make sure bad test cases aren't added in the future. If the test case provide no section header but provided no messages to check without these checks the test would still pass. Unfortunately if we aren't careful bad tests can get committed as #2992005: Remove duplicate test cases provider by dataProvider methods and prevent new ones. shows.

      But think exiting early is good idea. I will do that.

      Also I will change it to this at the end:

      $actual_message = $requirements_details->find('css', 'div.description')->getText();
      $this->assertNotEmpty($actual_message);
      $this->assertEquals($message, $actual_message);
      

      That we are explicitly testing that the message displayed was not empty instead of testing the provider. Effectively it is the same thing but I this is better.

    couple other things I changed after updating the other parts.

    1. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
      @@ -350,6 +350,300 @@ public function securityUpdateAvailabilityProvider() {
      +   * @param string $site_patch_version
      +   *   The patch version to set the site to for testing.
      

      This is no longer just the patch version changed it.

    2. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
      @@ -350,6 +350,300 @@ public function securityUpdateAvailabilityProvider() {
      +        'requirements_section_heading' => 'Errors found',
      +        'fixture' => 'sec.2.0_3rc1',
      +        'coverage_messages' => [
      +          'The installed minor version of Drupal, 8.0, is no longer supported and will not receive security updates.',
      

      After the other change to just test for the message it seemed clear to me that it would be better if order of the parameters was: $installed_version, $fixture, $requirements_section_heading, $message

      That was 2 things to set up the test, installed_version and fixture, are first and next to each other.

      And also the 2 things to check for that are both text are next to each other. Seems easier to read.

    tedbow’s picture

    Status: Needs work » Needs review
    tedbow’s picture

    +++ b/core/modules/update/src/ProjectSecurityRequirement.php
    @@ -132,7 +132,7 @@ private function getVersionEndCoverageMessage() {
    -        '%project' => $this->projectData['name'],
    +        '%project' => $this->projectData['title'],
    

    Forgot to mention this in #120

    Change to title because this is the human readable name. Only noticed this because the tests cases were failing. Was the different between "drupal" and "Drupal" it seems elementTextContains() was used before the change to assert the whole message is not case sensitive.

    benjifisher’s picture

    +++ b/core/modules/update/update.install
    @@ -7,6 +7,7 @@
     
     use Drupal\Core\Link;
     use Drupal\Core\Url;
    +use Drupal\update\ProjectSecurityRequirement;
     use Drupal\Update\UpdateFetcherInterface;
     use Drupal\Update\UpdateManagerInterface;
    

    I was going to apologize for nit-picking and complain that we usually do a case-sensitive sort of the use statements. Then I realized that the namespace Drupal\Update should be Drupal\update. It looks as though these lines were committed earlier today: #3015810: Properly deprecate UPDATE_* constants.

    benjifisher’s picture

    Status: Needs review » Needs work

    #3015810: Properly deprecate UPDATE_* constants was just updated, so this patch will need a reroll.

    spokje’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new58.47 KB
    new570 bytes

    Rrrrrrrrr-reroll of #120

    benjifisher’s picture

    @Spokje, thanks for the reroll. I was reviewing the latest patch at the same time.

    @tebow, thanks for these updates. I like all of these changes! Besides the reroll, there are just a few more little fixes.

    1. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      @@ -0,0 +1,241 @@
      +<?php
      +
      +namespace Drupal\update;
      +
      +use Drupal\Core\Render\Markup;
      +use Drupal\Core\StringTranslation\StringTranslationTrait;
      +use Drupal\Core\Url;
      +use Drupal\system\SystemManager;
      

      We no longer need the last use statement. (I noticed that when searching for "SystemManager" to check that all the constants had been updated. Then I looked at the testbot results, and of course the testbot caught it, too.)

    2. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
      @@ -350,6 +350,206 @@ public function securityUpdateAvailabilityProvider() {
           return $test_cases;
         }
       
      +  /**
      +   * Tests the Update Manager module when a security update is available.
      +   *
      +   * @param $installed_version
      

      Missing parameter type.

    3. +    $all_requirements_details = $this->getSession()->getPage()->findAll('css', 'details.system-status-report__entry:contains("Drupal core security coverage")');
      

      Can we break the long line at ->findAll()?

    4.         'message' => "The installed minor version of Drupal, 8.0, is no longer supported and will not receive security updates.$update_asap_message $see_available_message$release_coverage_message",
      

      This looks odd because there is no space before $update_asap_message nor $release_coverage_message. I guess the explanation is that we have stripped HTML tags. On the actual status report page, are these messages in separate paragraphs?

    5. +        'mock_date' => '2020-6-01',
      ...
      +        'mock_date' => '2020-6-02',
      

      Should those be "06"?

    6. I was pleased but a little surprised comparing the line counts for #111 and #120. The difference is that we have replaced multi-line arrays of message fragments with single-line messages. Those lines tend to be long (but not complex). But we really did make the patch smaller: wc reports that the patch in #120 is 59877 characters, down from 62431. Or we can look at the file size of the patches.
    spokje’s picture

    Status: Needs review » Needs work

    Back to Needs Work as per the excellent review from @benjifisher
    in #126

    bnjmnm’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new2.73 KB
    new58.47 KB

    This addresses 1-3, 5 of #126
    I also confirmed the explanation in #126.4 is correct. The messages are in separate paragraphs, there's no space in the asserts because html tags are stripped.

    benjifisher’s picture

    Status: Needs review » Reviewed & tested by the community

    I did not re-test, but of course the testbot did. (And the testbot did not find any problems with coding standards.)

    I did compare the latest patch to #120 (the last one I reviewed) and I confirmed that it addresses the points I raised.

    Obviously @tedbow did the lion's share of the work on this issue, but thanks also to @Spokje and @bnjmnm for taking care of the last few changes. Good team effort!

    benjifisher’s picture

    I see that @tedbow added the "Needs issue summary update" tag in #78, then updated the summary (including new screenshots) in #95 and #96. I do not have time to do it today, but someone should review the issue summary before the final review.

    xjm’s picture

    Status: Reviewed & tested by the community » Needs work

    No longer applies, unfortunately. 😿 Sorry, I'd been on vacation since this was RTBCed.

    spokje’s picture

    StatusFileSize
    new58.51 KB

    No longer applies, unfortunately. 😿

    Let's see if some 🎅 can make the 😿 all better...
    Reroll of #128

    spokje’s picture

    Status: Needs work » Reviewed & tested by the community

    Back to RTBC per #129

    I'm unsure what @benjifisher meant by his comment in #130:

    I see that @tedbow added the "Needs issue summary update" tag in #78, then updated the summary (including new screenshots) in #95 and #96. I do not have time to do it today, but someone should review the issue summary before the final review.

    To me the Issue Summary seems fine, but maybe that's because I've looked at the code.
    I'll leave a decision on that to Bigger Brains.

    tedbow’s picture

    @Spokje thanks for the reroll. It looks good to me🎉

    re #130
    I think @benjifisher just meant that I have updated the summary since he added the Needs issue summary update tag but he hasn't actually looked the updates\

    To me the Issue Summary seems fine, but maybe that's because I've looked at the code.
    I'll leave a decision on that to Bigger Brains.

    That the summary reflects the code is good!

    tedbow’s picture

    StatusFileSize
    new58.43 KB

    Here is patch for 8.8.x. It does apply because #3015810: Properly deprecate UPDATE_* constants and #3096078: Display core compatibility ranges for available module updates were not backported to 8.8.x

    #132 applies to 9.0.x without a reroll and I set the test to run on 9.0.x

    benjifisher’s picture

    I reviewed the patches from #128, #132, and #135. The only differences are context lines and a single blank line, so it looks as though the last two are proper rerolls of the first. +1 for RTBC.

    @tedbow, I think you are the one who added the "Needs issue summary update" tag in #78, not I.

    @Spokje, if you are confident that the issue summary is up to date, then you can remove the tag.

    tedbow’s picture

    Issue summary: View changes
    Issue tags: -Needs issue summary update

    @tedbow, I think you are the one who added the "Needs issue summary update" tag in #78, not I.

    Yep, sorry I didn't actually scroll back and check.

    I just check the summary and it looks good. I remove the "Needs Usability Review" from remaining items as the tag was removed in #51 and @xjm remarked in #50 that we discussed this the UX meeting. @benjifisher has also been giving feedback on the wording on this issue.

    tedbow’s picture

    Crediting a few more people that did reviews and provided feedback

    catch’s picture

    +++ b/core/modules/update/src/ProjectSecurityData.php
    @@ -0,0 +1,171 @@
    +    }
    +    $existing_release = $this->releases[$this->projectData['existing_version']];
    +    // Support for Drupal 8's LTS release and the version before are based on
    +    // specific dates.
    +    if ($existing_release['version_major'] === '8' && $existing_release['version_minor'] === '8') {
    +      $info['support_end_date'] = '2020-12-02';
    +      $info['support_ending_warn_date'] = '2020-06-02';
    +    }
    +    elseif ($existing_release['version_major'] === '8' && $existing_release['version_minor'] === '9') {
    +      $info['support_end_date'] = '2021-11-01';
    +    }
    +    elseif ($support_until_release = $this->getSupportUntilReleaseInfo()) {
    +      $info['support_end_version'] = $support_until_release['version'];
    +      $info['additional_minors_coverage'] = $this->getAdditionalSecuritySupportedMinors($support_until_release);
    +    }
    +    return $info;
    +  }
    

    I'm not sure about hard-coding the very specific dates in here.

    Having said that, my only counter-suggestion would be somehow tying this to Drupal 9 release windows - since there'll be a final security release window which will match specific Drupal 9 versions. But since we don't know which Drupal 9 versions we'll be dealing with at that point, I don't think we can do that now.

    So maybe a follow-up? Either to try to make this depend on releases later on or tied it to some new information we add on Drupal.org itself?

    +++ b/core/modules/update/src/ProjectSecurityData.php
    @@ -0,0 +1,171 @@
    +    }
    +    $existing_release = $this->releases[$this->projectData['existing_version']];
    +    // Support for Drupal 8's LTS release and the version before are based on
    +    // specific dates.
    +    if ($existing_release['version_major'] === '8' && $existing_release['version_minor'] === '8') {
    +      $info['support_end_date'] = '2020-12-02';
    +      $info['support_ending_warn_date'] = '2020-06-02';
    +    }
    +    elseif ($existing_release['version_major'] === '8' && $existing_release['version_minor'] === '9') {
    +      $info['support_end_date'] = '2021-11-01';
    +    }
    

    This part of the patch doesn't need to go into Drupal 9, could we have a version without that? Might need test coverage changes too.

    +++ b/core/modules/update/src/ProjectSecurityRequirement.php
    @@ -0,0 +1,240 @@
    +class ProjectSecurityRequirement {
    

    Worth adding final?

    drumm’s picture

    some new information we add on Drupal.org itself?

    That would be #2998285: Add information on later releases to updates.drupal.org. Now that work has gone into the basic function of update status for the near future, #3074993: Use "current" in update URLs instead of CORE_COMPATIBILITY to retrieve all future updates, we have a bit more of a foundation to build on.

    tedbow’s picture

    re #139.1

    Here are some ideas

    1. Just put a link to "Information about LTS releases". I guess we would need this for both 8.8.x and 8.9.x branches although just 8.9.x is possible LTS. From my understanding 8.8 won't covered based on 2 minor versions(like other releases)

      We could hard-code 8.8.x and above get the LTS link. Or expect something from drupal.org in the XML.

      We could base the url on major version so we could different messages for each major.. So something like
      drupal.org/lts-info-8
      drupal.org/lts-info-9
      If decide we should have 1 page for both drupal.org could just redirect

    2. We could just have text message based on the branch you were on 8.8.x, 8.9.x etc sent in the XML.

      I don't think this would be acceptable because of translations. But if that wasn't an issue that would the must flexible and would get site admins the most updated info.

    3. in #2998285: Add information on later releases to updates.drupal.org drupal.org could add meta info about branch security coverage endings.

      This seems like a good idea but would require more work on the drupal.org side.

    My suggestion would be to do 1) with a follow-up for 3)

    That way for 8.8.x onward would have a message that they need to look at the docs to figure out how long they are supported.

    tedbow’s picture

    Status: Reviewed & tested by the community » Needs review
    StatusFileSize
    new20.35 KB
    new45.61 KB

    re #139.2

    Here is patch for 9.0.x it takes out the code mentioned and all code that deals with specific logic.

    This should pass against 8.9.x also but has no special case for 8.8.x and 8.9.x.

    benjifisher’s picture

    Status: Needs review » Needs work
    Related issues: +#2998285: Add information on later releases to updates.drupal.org

    Referring to the interdiff attached to #142:

    1. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -10,7 +10,7 @@
      ...
      -class ProjectSecurityData {
      +final class ProjectSecurityData {
          

      Why make this change? Is it just a nice-to-have that can be done because of the minimal PHP version required by Drupal 9? If so, then I would rather not make that change as part of this issue. We need separate patches for 8.8, 8.9, and 9.0, and I think it makes sense to keep those three patches as similar as possible.

      Oh, I see that was specifically requested in #139. I also checked https://www.php.net/manual/en/language.oop5.final.php, and I see that it has nothing to do with the PHP version. I do not have an opinion on whether we want to do this, but I do think we should use it or not consistently in all the patches for this issue.

    2. @@ -79,12 +79,6 @@ public function __construct(array $project_data, array $releases) {
          *   - additional_minors_coverage (int): The number of additional minor
          *     releases after the latest full release the existing version will be
          *     supported.
      -   *   If the support is based on support until a specific date the array will
      -   *   have the following keys:
      -   *   - support_end_date (string): The date support will end for the existing
      -   *     version in the format 'YYYY-MM-DD'
      -   *   - (optional) support_ending_warn_date (string): The date after which a
      -   *     warning should be displayed about upgrading to another version.
          */
          

      Same idea: do we need to make this change? In the long run, we hope to get the data we need from drupal.org, and eventually support projects other than core. Even if we are not using dates currently (in the patch for 9.0) we may want to support the option. It seems like a shame to rip it out.

    I will stop there. There is at least one other class marked final, there are code changes corresponding to the docblock changes I quoted, and there are changes to the tests.

    I think the patch in #144 goes well beyond the changes requested in #139. I would like to see the changes limited to removing the hard-coded dates that will never apply for 9.0.

    In fact, I would like to push back a bit on those requested changes. Can we postpone them to a follow-up issue? This issue is marked critical, and I would like to see it go in sooner rather than later. Removing the lines that will be unnecessary cruft in 9.0 seems much less urgent.

    As for the other request in #139, the follow-up is already there, as pointed out in #140. That issue already references this one, and I am adding a reference in the other direction.

    xjm’s picture

    Going back to my last activity on the issue and responding to a few things:

    1. #109.1:

      Of course we may want to change this message because there will be no more minor releases of Drupal 8(probably). Though we could leave it as 9.0.0 is a minor release.

      I think we need to tell them to update to Drupal 9 to continue receiving support. It won't be 9.0, either, because 9.0 will be out of security coverage before 8.9. So the text for LTSes could be "Update to a supported release of the next major version soon..."

    2. #109.2 and .3:

      if we don't want to change the message section from info to warning within 6 months if we aren't adding an extra message do we want always have the message be an Info message right up till the day before they lose support.

      So I think the reasoning for recommending people update to the next minor when it's got 6 months to live is that (a) their release no longer has bugfix support, (b) there is a newer release available, (c) the extended coverage doesn't do them as much good if they don't know about it.

      (a) does not apply to LTSes, but (b) and (c) do, so maybe it does make sense to implement the same behavior, even though it's not exactly a new minor release triggering the change. If that's how other minors are already implemented, which I am unclear on. :) I think it's the existence of a new release that triggers the message for a normal minor?

    3. #116:

      ...So basically I guess I just recommended undoing that whole change, sorry!

    4. Re: #139 and #142:

      I discussed this with @catch and @Gábor Hojtsy.

      For me, what's problematic with the earlier version is coding a specific day of the month that is not documented anywhere else. Our EOL is tied to SF3's. They don't specify a day of the month on their policy, but their releases usually happen in the second to third week of November, so I'm assuming we'd provide coverage until they do. Thus, I think it'd be better to say "November 2021" than inventing a specific day of the month that does not exist yet. I think telling them the month and year is still important information.

      @catch said this:

      Ahh I was actually just thinking we should ideally have the dates on Drupal.org somehow (per branch?) and not in Drupal core. I really do not know what to do about the actual dates.

      ...which is our followup in #2998285: Add information on later releases to updates.drupal.org, but I don't think we should wait on that because there are many, many infrastructure changes that are more critical and must to be made prior to Drupal 9's release. Edit: The metadata followup is more of a should-have-some-day kinda thing, but less important than semver etc.

      @catch added:

      Ideally we would say something like 'will stop getting official security support after $date' instead of 'is supported until' which might then make putting a month a bit more honest.

      I'd be fine with that rewording.

      (@catch also said:

      Also.. I don't think we can drop Drupal 7 support until migrate is actually 100% stable, but I guess we could extend it and change the hard-coded date if we really have to.

      ...but that does not apply here since we're only making this change in D8+.)

      I propose that we put the month in the Drupal status report, but also link the core release cycle overview for the most up-to-date info in case our specific dates change, and since we don't have an official exact day for D8's EOL atm anyway. Gábor +1ed that suggestion.

      Edit: Some of the screenshots in the IS show the link to the release cycle overview, but not others, and I'm confused on or have forgotten why it isn't in some cases.

    xjm’s picture

    I'm also unsure about removing LTS logic from the 9.0.x version of the patch, because Drupal 9 will probably have an LTS version as well. Hopefully by then we'll have the dates as metadata from d.o rather than hardcoded, but I think we should keep the logic and test coverage in place until such time as we refactor the thing for new d.o metadata.

    I think the only thing that might be worth removing from 9.0.x is specific logic for Drupal 8 specifically. But I would also be fine with a 9.0.x-only followup for that, in order to avoid juggling two versions of the patch while we make other changes.

    tedbow’s picture

    Issue summary: View changes
    StatusFileSize
    new121.6 KB

    @xjm thanks for reviews.

    I am working on a updated patch. But just a couple questions while I am working on it.

    I guess this questions are for @xjm and @catch as release managers.

    1. re #144.4

      For me, what's problematic with the earlier version is coding a specific day of the month that is not documented anywhere else.

      The version with specific dates also had a specific date 8.8.x end of support. I got that here https://www.drupal.org/core/release-cycle-overview

      screenshot showing 8.8.x support end
      In all 3 cases it shows 8.8.x support ending on December 2, 2020.

      Do we need to leave the exact date for 8.8.x.?

      If so then we will need logic displaying the message with month granularity and day granularity.

    2. I got the LTS date from that page but now I see that it says "No later than November 2021" for 8.9.x(or 8.10 if that is the LTS)

      re new wording

      'will stop getting official security support after $date' instead of 'is supported until'

      so $date would be a month.

      From my reading we should say "after October 2021". If we put "after November 2021" that implies to me that on 11/30/2021 I would get support but on 12/01/2021.

      Does that sound correct?

    3. Ultimately even though we will be displaying a month and not a specific day in the month the code including the tests have to specify a specific date at which the sites on 8.9.x(and 8.8.x) will start showing the "unsupported" message.

      From my reading of the above:

      For sites on 8.8.x
      Dec 1, 2020 -> show warning
      Dec 2, 2020 -> show unsupported

      For sites on 8.9.x it seems more unclear what date we would pick but my thoughts
      Oct 31 2021 -> show warning
      Nov 1 2021 -> show unsupported

      Even if we never show them "unsupported" and always show them the warning with the projected month date. It seems at some date we would want to move this "errors" section. So we still would need a specific date in the code/tests.

    tedbow’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new15.39 KB
    new59.46 KB

    I chatted with @xjm about this. This is tricky stuff to talk about so I might have gotten something wrong but I think this was our consensus.

    I am only addressing date related stuff day vs month and when we should show warnings vs unsupported.

    1. re #146.1

      Do we need to leave the exact date for 8.8.x.?

      If so then we will need logic displaying the message with month granularity and day granularity.

      Yes since the exact date is documented for 8.8.x supported ending we should use this.

      This wasn't as hard as I thought. Just required getting the request time in the same format as support end specified either YYYY-MM-DD or YYYY-MM. This can then just be compared as string.

      So 8.9.x will still use the support end of 2021-11

    2. If we put "after November 2021" that implies to me that on 11/30/2021 I would get support but on 12/01/2021.

      We are not sure when exactly support will end within this month. I am displaying this message but it will display "unsupported" 11/01/201.

      It is better so show it has unsupported when it actually is supported than to show supported when it actually isn't.

    3. I have update the test cases in \Drupal\Tests\update\Functional\UpdateCoreTest::securityCoverageMessageProvider()
      • I reordered them in so all 8.8.x are grouped together and all 8.9.x are grouped together.
      • in those groups I ordered the cases by the "mock_date" so it is easier to see the case progress in the tested date.
      • I added "last day" test cases to show when exactly a message will flip from the warning to unsupported.

      Hopefully this help showing what the user will actually see on different days.

    4. the interdiff is from 132 because it takes out the changes in #142 as we need the dates again. I will see if there is anything else should be pulled back in
    xjm’s picture

    +1 for the changes in #147.

    One outstanding question I have is why we're not linking the d.o handbook page in all cases, or which cases we're not linking it in?

    xjm’s picture

    Status: Needs review » Needs work

    NW for #148, although @tim.plunkett might have additional points of review.

    benjifisher’s picture

    Not everyone has commented, but I think we have consensus (Comments 143, 145, 147) to leave in the code that checks specifically for 8.8.x and 8.9.x. So I created a follow-up to remove that from the 9.0.x branch: #3107378: Deprecate hard-coded Drupal 8 dates from update logic for the status report once this information is provided by the infrastructure.

    That was one of the requests from Comment 139. Another (with the caveat "maybe") was to declare at least one of the new classes final. Do we want to do that? If so, will it happen as part of this issue or in a follow-up?

    From Comment 145:

    But I would also be fine with a 9.0.x-only followup for that, in order to avoid juggling two versions of the patch while we make other changes.

    (The followup refers to #3107378.) We already need two versions of the patch, for 8.9.x and 8.8.x. Since we are leaving in the hard-coded dates for 8.8.x and 8.9.x, we do not need a third version of the patch!

    The patch in #147 applies to the current 8.9.x but not to 8.8.x. Maybe that is OK: once we fix this issue for 8.9.x, we can port the patch to 8.8.x. That might be less trouble than managing two versions of every patch from now on.

    benjifisher’s picture

    1. I find the date comparisons in #147 hard to follow. Maybe it would help to use $date_formatter a few times as soon as it is declared, creating helpfully named variables; then use those variables later in the code instead of using $date_formatter again.
    2. Does $date_formatter->format($end_timestamp, 'custom', 'F Y') work well with translation?
    3. </ol>+++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
      @@ -379,6 +379,8 @@
      ...
      +    $u = "$installed_version-$fixture-$mock_date";
      +
      

      This variable does not seem to be used later.

    4. I think we need to update the screenshots again. I will add issue tags for that.
    tedbow’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new59.77 KB
    new10.01 KB
    1. Made the 2 non-test classes final. Remove the comment in both saying they shouldn't be extended as they can no longer be extended.
    2. #151.1 I assigned the formatted dates to variables and re-order them to be more readable. One of the assigned variables is further down to be closer to the if statement where it is used.
    3. #151.2 I stepped through this to be sure. This calls \Drupal\Core\Datetime\DrupalDateTime::format() which does translate the individual parts of the date and there is specific logic for "F". As long as the current language translation supports the months of the year it will work.
    4. #151.3 Fixed. This was left from debugging.
    5. #148 I added a link the release cycle page for all times any security message is returned.

    Some other self review things I noticed while making these updates.

    1. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      @@ -0,0 +1,241 @@
      +    if ($this->projectData['project_type'] === 'core' && $this->projectData['name'] === 'drupal') {
      +      // Provide a link to the Drupal core documentation on release cycles
      +      // if the installed Drupal core minor is not supported.
      +      $message .= '<p>' . $this->t(
      +          'Visit the <a href=":url">release cycle overview</a> for more information on supported releases.',
      +          [
      +            ':url' => 'https://www.drupal.org/core/release-cycle-overview',
      +          ]
      +        ) . '</p>';
      +    }
      +
      

      We don't need to test if this is core because the only public method will return earlier if it is not and since it is final nothing can extend it and get here another way.

      If we ever use this class for non-core projects there will need to be other changes.

    2. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      @@ -0,0 +1,241 @@
      +    $date_format = count(explode('-', $security_info['support_end_date'])) === 3 ? 'Y-m-d' : 'Y-m';
      

      Instead of doing count(explode()) substr_count() can just be used to determine the format. Probably faster, and more readable

    3. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      @@ -0,0 +1,241 @@
      +  private static function getAvailableUpdatesMessage() {
      +    return t(
      +      'See the <a href=":update_status_report">available updates</a> page for more information.',
      +      [':update_status_report' => Url::fromRoute('update.status')->toString()]
      +    );
      +  }
      

      If this is not a static function we can use $this-t()

    larowlan’s picture

    Issue summary: View changes
    tedbow’s picture

    Issue summary: View changes
    Issue tags: -Needs issue summary update

    Updated the summary. Changed examples to use 9.x examples as some of the 8.6.x examples no longer apply as that is out of security coverage.

    Holding off on screenshots till I get a review from @tim.plunkett as wordings in the patch might change.

    jibran’s picture

    +++ b/core/modules/update/src/ProjectSecurityData.php
    @@ -0,0 +1,171 @@
    +    if ($existing_release['version_major'] === '8' && $existing_release['version_minor'] === '8') {
    +      $info['support_end_date'] = '2020-12-02';
    +      $info['support_ending_warn_date'] = '2020-06-02';
    ...
    +    elseif ($existing_release['version_major'] === '8' && $existing_release['version_minor'] === '9') {
    +      $info['support_end_date'] = '2021-11';
    

    These dates should be class constant so that they are easy to update. I also think we should name them in a logical way. Something like: SUPPORT_END_DATE_88 and SUPPORT_END_WARN_DATE_88 and then use constant('SUPPORT_END_DATE_' . $version_major . $version_minor ) so that we can add more dates later without updating the code.

    tedbow’s picture

    StatusFileSize
    new3.34 KB
    new60.34 KB

    @jibran great suggestion. Done

    tim.plunkett’s picture

    Status: Needs review » Needs work

    Some nits here, a couple requests. The core logic of the code looks sound, and the test coverage looks great!

    1. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      @@ -0,0 +1,250 @@
      +   * - existing_version (string): The version of the project that is installed
      +   *   on the site.
      +   * - security_coverage_info (array): The security coverage information as
      +   *   returned by \Drupal\update\ProjectSecurityData::getCoverageInfo().
      +   * - project_type (string): The type of project.
      +   * - name (string): The project machine name.
      ...
      +    $this->projectData = $project_data;
      +    if (isset($this->projectData['existing_version'])) {
      +      list($major, $minor) = explode('.', $this->projectData['existing_version']);
      +      $this->existingVersion = "$major.$minor";
      +      $this->nextVersion = "$major." . ((int) $minor + 1);
      +    }
      

      It's odd to me that this has two properties for some of the projectData info, but not the other keys. Especially since this docblock explains the specific array keys that are used.

    2. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      @@ -0,0 +1,250 @@
      +  public function __construct(array $project_data) {
      

      On the off-chance that someday we replace the magic array from getProjects with a value object, should this constructor be made private and introduce a static factory method, similar to ModuleVersion?

    3. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      @@ -0,0 +1,250 @@
      +   * @return array
      ...
      +  public function getRequirement() {
      ...
      +      return NULL;
      ...
      +      return NULL;
      

      array|null

    4. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      @@ -0,0 +1,250 @@
      +   * Get the requirements array based on support to a specific version.
      

      Gets

    5. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      @@ -0,0 +1,250 @@
      +  private function getVersionEndCoverageMessage() {
      ...
      +    $message .= $this->getReleaseCycleLink();
      ...
      +  private function getDateEndRequirement() {
      ...
      +    if (isset($requirement['description'])) {
      +      $requirement['description'] = Markup::create($requirement['description'] . $this->getReleaseCycleLink());
      +    }
      

      It's not clear why, but in one the cycle link is always added and not in the other. I would have expected the second instance to be something more like

      if (!isset($requirement['description'])) {
        $requirement['description'] = '';
      }
      $requirement['description'] = Markup::create($requirement['description'] . $this->getReleaseCycleLink());
      
    6. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      @@ -0,0 +1,250 @@
      +      $requirement['description'] = '<p>' . $this->t('The installed minor version of %project, %version, will stop receiving official security support after  %date.', $translation_arguments) . '</p>';
      

      double space after "after" before "%date"

    7. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      @@ -0,0 +1,250 @@
      +      . $this->t(
      +        'Update to a supported minor as soon as possible to continue receiving security updates.')
      

      I've ignored all the other weird line breaks throughout, but this one is just too weird for me

    8. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      @@ -0,0 +1,250 @@
      +  private function getReleaseCycleLink(): string {
      

      This looks like a PHPStorm auto-addition. I didn't think we were doing strict typing yet?

    9. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      @@ -0,0 +1,250 @@
      +    return '<p>' . $this->t(
      +        'Visit the <a href=":url">release cycle overview</a> for more information on supported releases.',
      +        [
      +          ':url' => 'https://www.drupal.org/core/release-cycle-overview',
      +        ]
      +      ) . '</p>';
      

      This is over-indented, and the args array can be one line.

    10. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
      @@ -357,6 +357,224 @@ public function securityUpdateAvailabilityProvider() {
      +  public function securityCoverageMessageProvider() {
      

      Similar to \Drupal\Tests\update\Unit\ModuleVersionTest::providerVersionInfos(), this should explain the data provider values in this method

    benjifisher’s picture

    benjifisher’s picture

    I reviewed the patch in #156, and it addresses the points I raised in #151.

    One of the assigned variables is further down to be closer to the if statement where it is used.

    Good choice.

    Thanks for tracking down how the date is translated. Given the answer, I feel that the question was a reasonable one!

    tedbow’s picture

    Assigned: Unassigned » tedbow

    @tim.plunkett thanks for the review! in the process of addressing it

    tedbow’s picture

    Assigned: tedbow » Unassigned
    Status: Needs work » Needs review
    StatusFileSize
    new20.82 KB
    new62.24 KB

    re #157

    1. I changed this and ProjectSecurityData to have properties for the keys needed and not store $projectData at all
    2. I made this changed this and \Drupal\update\ProjectSecurityData to use static factory create methods. I conjunction with 1) moved the check for if the project is actually drupal core into the factory methods. This allows nothing having properties for name and type
    3. I changed this to return an empty array if no requirement can be determined and update the doc to explain this
    4. fixed
    5. Looking at the logic again $requirement['description'] will always be set so there is no need for this check.
    6. fixed
    7. fixed
    8. fixed. Thanks fixed my PHPStorm setting which changed when I update to php 7.3
    9. fixed
    10. In this case all the test cases have array keys that are the same as the @param names for testSecurityCoverageMessage() the 1 place they are used. And that method documents the @param's. this would just be duplicating that text. Not adding it now but can if still needed.

    re #158 This patch does the re-roll. Since we no longer have version_major in the xml and I used \Drupal\update\ModuleVersion::getMajorVersion. We don't have version_minor but adding to ModuleVersion is more complicated because it would have to handle both contrib 8.x-1.0 form and semantic. Also it would cause our docs to be out of sync because use PatchLevel instead of minor for contrib. We only need minors for core versions here so just added the private method \Drupal\update\ProjectSecurityData::getCoreMinorVersion(). This returns an int because in this class we had to cast to int 2 out of the 3 places used.

    re #159. @benjifisher thanks for checking back on those points.

    tim.plunkett’s picture

    Status: Needs review » Needs work
    Issue tags: -Needs reroll
    +++ b/core/modules/update/src/ProjectSecurityData.php
    @@ -0,0 +1,204 @@
    +  /**
    +   * @var string|null
    +   */
    +  protected $existingVersion;
    

    Missing one-line description. Should also include an example of what the string could be.

    I think that's the only remaining thing? The rest of the changes look great.

    Also, this is still tagged "needs screenshots"

    gábor hojtsy’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new62.29 KB
    new451 bytes

    Added based on constructor.

    tedbow’s picture

    StatusFileSize
    new2.25 KB
    new62.44 KB

    @Gábor Hojtsy thanks!

    re #162 add the examples.

    Also fixed coding standard drupalci documented for #161. For some reason by phpcs has stopping working to catch all problem in both on the commandline and phpstorm.

    Still to make the screenshots now

    dww’s picture

    Status: Needs review » Needs work

    Good stuff, tons of work already here. Looking fairly solid. Here's the start of a thorough review:

    1. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,208 @@
      +  /**
      +   * The number of minor versions of Drupal core that are supported.
      +   */
      +  const CORE_MINORS_SUPPORTED = 2;
      

      Do we really want this as a constant in core, and not something in the Drupal core project data in the /current release history XML feed? If we ever want to change this value, it sucks to have to make new releases on every supported branch of core and hope that everyone updates (yeah right). Seems it'd be best to let this value come from d.o itself, and all future versions of update.module can handle any changes to this.

    2. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,208 @@
      +  const SUPPORT_END_DATE_8_8 = '2020-12-02';
      +
      +  const SUPPORT_ENDING_WARN_DATE_8_8 = '2020-06-02';
      +
      +  const SUPPORT_END_DATE_8_9 = '2021-11';
      

      Same for all these. Why try to hard-code any of this into core in advance? If the /current feed is too weird for this, and we don't anticipate letting contrib modules define all this stuff for themselves, we could also add a separate end-point (JSON, if we wanted) that contained all this.

    3. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,208 @@
      +   * - version_major (string): The major version of the release.
      +   * - version_minor (string): The minor version of the release.
      +   * - status (string): The status of the release.
      +   * - version_extra (string): The extra string at the end of the version string
      

      Why is status wedged between version_* in these docs? Seems better to put it first (alphabetical), even though I think extra should be after major + minor (even though that's not alphabetical). Or put status last. But between minor and extra seems weird.

    4. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,208 @@
      +   * The existing version of the project.
      ...
      +  protected $existingVersion;
      ...
      +   * @param string $existing_version
      +   *   The existing version of the project.
      ...
      +    $this->existingVersion = $existing_version;
      

      I know I named this in the rest of update.module 10+ years ago like this, but I find "existing" a little weird. It's really "currently installed". I wonder if $installedVersion would be better for this? Or at least "The existing (currently installed) version of the project." as the 1-liner...

    5. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,208 @@
      +   * Because this class only handles the Drupal core project values will be
      

      Why is this only about core? And if so, why is this class called "ProjectSecurityData" when it seems to only be "DrupalCoreSecurityData"?

    6. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,208 @@
      +   * @param string $existing_version
      +   *   The existing version of the project.
      ...
      +  private function __construct($existing_version = NULL, array $releases = []) {
      +    $this->existingVersion = $existing_version;
      

      $installed_version ?

    7. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,208 @@
      +    if (!($project_data['project_type'] === 'core' && $project_data['name'] === 'drupal')) {
      +      // Only Drupal core has an explicit coverage range.
      +      return new static();
      +    }
      +    return new static($project_data['existing_version'], $releases);
      

      Looks like the comment above is somewhat bogus and the class name is legit. The only core-specific part seems to be explicit coverage range. Seems we could let contrib opt-in to providing that info for their own projects, too. Instead of hard-coding this, I'd rather let this functionality be triggered by the existence of the right info in the feed (see earlier points) and then we can control which projects get those attributes in their feed on the d.o side as policy over time, instead of having to re-write any of this code and try to re-release it.

    8. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,208 @@
      +   * Gets the security coverage information for a project.
      +   *
      +   * Currently only Drupal core is supported.
      

      Review has to stop here for tonight. I'll try to resume ASAP.

    NW at least for screen shots and some of these points...

    Thanks/sorry,
    -Derek

    drumm’s picture

    something in the Drupal core project data in the /current release history XML feed?

    That’s #2998285: Add information on later releases to updates.drupal.org, which was effectively blocked when this issue started. That issue could proceed now, if it will help.

    gábor hojtsy’s picture

    I attempted to help create screenshots, but it appears to be a lot more involved than popping up a site with the patch. At least on Drupal 8.8-dev I did not see any changes on the available update screen. How should screenshots be made?

    Also the issue summary looks like it outlines different variants of the screens based on different remote data, I think we settled on what the remote data should be no?

    tedbow’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new786 bytes
    new62.44 KB

    @dww thanks for the review.

    1. There was a lot of discussion about this and 2) and the release managers are ok with hard-coding this because this is 9.0.0 blocker. @drumm mentioned work can start on #2998285: Add information on later releases to updates.drupal.org which would mean we won't have to hard-code this, but it does push back this issue even more. We already have 8.8.0 and 8.8.1 release with no information that there is end for support. I still say we get this and then work on the follow-up to #2998285 which would mean reading those values from the XML feed. only \Drupal\update\ProjectSecurityData would need to be changed.

      If get this issue in now and #2998285 happens very quickly on drupal.org side then maybe won't have the hardcode dates in 8.8.2. But if it is #2998285 delayed then at least 8.8.2 will have something in it. Also I don't think #2998285 is highest priority for what core needs as far as drupal.org changes considering we have solution that was signed off on by the release managers. I think #3100115: The update module should recommend updates based on supported_branches rather than major versions majors is also critical needs d.o changes and would need drupal.org changes. I pretty sure there are other changes too

    2. Same as 1)
    3. Moving status to first
    4. I think it is better to keep it consistent with the rest of the module for now. I also think "installed" is better but I think someone new looking at the code seeing "install" one place and "existing" somewhere else would reasonably assume these are 2 different things.
      if it is important enough we should open issue to rename all to "installed"
    5. I think this class will at some point handle both. Also the consumers of this class don't have to do a check to use it only with core. It send back valid values for any project. It is just that valid values for all projects beside core is no info 😉

      This is just documenting examples values and internally we know it will only be core version numbers.

    6. same as 4
    7. Same as 1 & 2 possible after #2998285: Add information on later releases to updates.drupal.org I don't think we should delay this issue

    @Gábor Hojtsy yep I can do the screenshot. Basically I had to fake the current version number in \Drupal::VERSION to get those shots. It will be more difficult now because the XML from core has changed

    dww’s picture

    Thanks for the responses and quick fixes to a few of the points.

    Yeah, sorry, I haven't had time to read this entire issue and every commenbt. I just know this is critical and something I have a lot of ability to carefully review, so I'm focusing on the code first. Apologies if I'm re-opening old wounds. ;)

    1. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,208 @@
      +   * Currently only Drupal core is supported.
      

      Still a little bummed this is written to only support core.

    2. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,208 @@
      +   *   on support until a specific version the array will have the following
      

      Nit: Could use a comma after "specific version"

    3. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,208 @@
      +   *   - additional_minors_coverage (int): The number of additional minor
      +   *     releases after the latest full release the existing version will be
      +   *     supported.
      

      I don't really understand this comment or what the policy we're aiming to communicate means. Maybe an example with real version numbers would help?

    4. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,208 @@
      +   *   If the support is based on support until a specific date the array will
      

      "the support is based on support" is confusing to parse. Maybe:

      "If the security coverage is based on support..."

      That'd match the comment a few lines up.

    5. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,208 @@
      +    $version_suffix = $existing_release_version->getMajorVersion() . '_' . $this->getCoreMinorVersion($this->existingVersion);
      

      Huh? Why doesn't ModuleVersion::getMinorVerison() exist / work?

      What's core got to do with it? ;)

    6. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,208 @@
      +    if (defined("self::SUPPORT_END_DATE_$version_suffix")) {
      

      Again, sad to see all this hard-coded.

    7. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,208 @@
      +   *   If release information is not available an empty array is returned
      

      Nit: Need either a comma or a period and new sentence after "is returned".

    8. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,208 @@
      +    if (!empty($existing_release_version->getVersionExtra())) {
      +      return [];
      +    }
      

      Maybe add a code comment explaining why releases with extra automatically have no supported until release info?

    9. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,208 @@
      +      'version_minor' => $this->getCoreMinorVersion($this->existingVersion) + static::CORE_MINORS_SUPPORTED,
      

      Again, why this weird private helper instead of having a getMinorVersion() method?

    10. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,208 @@
      +   * @param array $security_supported_release_info
      ...
      +  private function getAdditionalSecuritySupportedMinors(array $security_supported_release_info) {
      

      This whole class is about security, and it's included in the function name. Probably the param could just be called "supported_release_info" to be shorter and easier to read.

    11. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,208 @@
      +   *   The security supported release as returned by
      

      s/release/release info/

    12. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,208 @@
      +   * @return int
      ...
      +      : NULL;
      

      Apparently int|null

    13. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,208 @@
      +  /**
      +   * Gets the minor version for a core version string.
      +   *
      +   * @param string $core_version
      +   *
      +   * @return int
      +   *   The minor version as an integer.
      +   */
      +  private function getCoreMinorVersion($core_version) {
      +    return (int) (explode('.', $core_version)[1]);
      +  }
      

      a) This isn't core-specific, it's semver-specific.
      b) This definitely belongs in the ModuleVersion class, not here.

    14. --- /dev/null
      +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      

      Stopping review here for now. Hope to get through the rest of this patch soon...

    tedbow’s picture

    StatusFileSize
    new5.86 KB
    new62.68 KB
    1. This is an @internal/final class we are free to change it later. if #2998285] is done a way that allows all this info for all projects we can update this class. I don't see any reason to make work contrib now.
    2. fixed
    3. updated and added example. I agree this was confusing.
    4. yep that is better. fixed
    5. In #3074993: Use "current" in update URLs instead of CORE_COMPATIBILITY to retrieve all future updates we didn't need ModuleVersion::getMinorVerison() and that is an final @internal class so shouldn't make public methods that aren't being called. See this comment and interdiff https://www.drupal.org/project/drupal/issues/3074993#comment-13416986

      Basically having getMinorVerison() work with 8.x-1.0 and 1.0.0 formats is much more complicated than getting for the just 1.0.0. We only need to figure out for the format that core uses right now so I don't think adding the complications ModuleVersion makes sense because we would need to handle both formats. See the code we would need in that diff for getMinorVersion() compared to this 1 line if stick to only handling semantic versions.

      If later we need getMinorVerison() outside of this method we can add ModuleVersion::getMinorVerison() and replace this method with it.

      No need to cover more cases now than we need to

    6. 🤷‍♂️
    7. added comma
    8. Added comment
    9. see 5)
    10. fixed
    11. fixed
    12. fixed and added comment for when we would return NULL(this would never happen for core)
    13. a)change to getSemanticMinorVersion()
      b) Not IMHO😜 see 5)
    14. Thanks some good catches so far

    tedbow’s picture

    StatusFileSize
    new1.91 KB
    new62.68 KB

    Small changes based on UX meeting today with me @xjm, @webchick, @Gábor Hojtsy, @AaronMcHale(hope that was everybody) credited those who already credited on this issue. Thanks for the help!

    Changing from

    The installed minor version of Drupal, 8.2...

    to

    The installed minor version of Drupal (8.2)...

    Will make the screenshots again and upload

    The last submitted patch, 170: 2991207-170.patch, failed testing. View results

    xjm’s picture

    Issue tags: +Needs followup

    Here are the notes from the UX meeting @tedbow mentions in #172:

    1. Parenthesis around Drupal version in the first sentence: "The installed version of Drupal (8.2)..." @tedbow Fixed this above.
    2. The date formatting is not localized. Let's open a followup issue for that. Are there places elsewhere in core that we should take into account? E.g. on the upgrade status report, there are dates.
    3. There is no warning in May 2021 for the LTS issue. We are fine with this for now.
    4. Too much text!

      the main thing I am struck by is yoroys constant hammering of “use fewer words”... it feels like there are just 3 things to communicate ... 1) what date am I out of compliance? (“supported until: date”) b) what should I be on instead (download: 9.0.0), c) where do I get more info? (more details link)

      Also, will people know what the word "minor" means?

      This is a third followup issue to file, to further improve the wording.

    5. What about unsupported majors? Will they see these messages? When someone is on 8.9 after 9.0's LTS, or 8.8 after 8.9's LTS. Or D7. A UX review for messaging about the next major should be a critical issue we work on during the Drupal 9 beta. We should file this issue and postpone it on the related beta blockers.
    xjm’s picture

    Status: Needs review » Needs work

    The last submitted patch, 172: 2991207-171.patch, failed testing. View results

    tedbow credited mpdonadio.

    tedbow’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new14.55 KB
    new63.23 KB
    1. #172 failed because I didn't update the test strings.
    2. #170 failed for a much stranger reason. It has nothing to with the patch it has to do with the date the test was run. I am rerunning #168 and it should now fail on this date
      +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      @@ -0,0 +1,275 @@
      +    $date_format = substr_count($this->securityCoverageInfo['support_end_date'], '-') === 2 ? 'Y-m-d' : 'Y-m';
      ...
      +    $end_timestamp = \DateTime::createFromFormat($date_format, $this->securityCoverageInfo['support_end_date'])->getTimestamp();
      

      @mpdonadio figured this out not me. I am crediting him.

      We can't use \DateTime::createFromFormat() with the format 'Y-m'. It will use today's date for the day portion. Today is the 30th but because of timezones Drupal will use 31st. Since there is not November 31st it will use December 1. 😳

      Fixing this and adding a comment.

    dww’s picture

    @tedbow: Thanks for the replies and fixes!

    Re: #170.5:

    I read the linked comment. Well, here's the case where we need it. ;) https://www.drupal.org/files/issues/2020-01-09/interdiff-78-80.txt isn't really a fair comparison, since a lot of that is dealing with the fact you changed your mind for the constructor taking all the parts split up already vs. a single version string. That was a good move. The parts that we'd need to add back to ModuleVersion to support getMinorVersion() are only about 5 lines of code, and maybe 20 lines of test coverage. I totally think that'd be worth doing, even though we have to handle 8.x-1.2 vs. 8.8.1. That's why it's 5 lines, not 1. ;)

    Re: confusion about patch level vs. minor -- that ship has sailed. Contrib versions are definitely API_COMPATIBILITY-MAJOR.MINOR(-EXTRA)?. Patch level is how I intended it in the first place years ago, but that's not how the d.o composer shim interprets it. The fact it's ambiguous means we have to consider it major.minor, not major.patch, since that's more semantically accurate given how contrib maintainers actually use it. We can/should/will cleanup the docs to address all this. Adding ModuleVersion::getMinorVersion() would not add to this confusion. It'd help clear it up.

    Anyway, it's not really up to me, but I'm strongly in favor of adding ModuleVersion::getMinorVersion() for this, not ProjectSecurityData::getSemanticMinorVersion() (although, thanks for renaming it, at least). ;)

    Gotta shift gears for now, but I hope to return to reviewing this later today...

    Thanks,
    -Derek

    The last submitted patch, 168: 2991207-167.patch, failed testing. View results

    dww’s picture

    So as not to derail progress here, split out #3110223: Add ModuleVersion::getMinorVersion() method as a child issue. Reviews / RTBC welcome. I updated the Unit test, and it's all passing locally, so I assume the bot will be happy, too.

    Once that lands, we can update this patch to use it instead of adding ProjectSecurityData::getSemanticMinorVersion()

    Cheers,
    -Derek

    dww’s picture

    Proof-of-concept. Updates 2991207-178.patch (from #179) to use #3110223: Add ModuleVersion::getMinorVersion() method.

    2 versions of the patch:
    2991207-183.WITH-3110223.DO-NOT-COMMIT.patch includes #3110223 so the test bot will work.
    2991207-183.NEEDS-3110223.DO-NOT-TEST-YET.patch does not include #3110223, which would be what we actually want in here once #3110223 lands.
    Interdiff is for the DO-NOT-TEST-YET version, to show the simplifications/improvements from patch 178.

    dww’s picture

    StatusFileSize
    new62.84 KB
    new70.7 KB
    new743 bytes

    Whoops, added an extra space. ;)
    This is better.

    xjm’s picture

    Replied regarding this approach in #3110223-3: Add ModuleVersion::getMinorVersion() method. For the scope of this issue, let's go back to #179.

    mpdonadio’s picture

    Yay, PHP: https://3v4l.org/t0q2RY

    This was also compounded running on 2020/01/30 by the fact that tests run in Australia/Sydney, where it was 2020/01/31 at the time.

    tedbow’s picture

    Issue summary: View changes
    Issue tags: -Needs screenshots, -Needs followup
    StatusFileSize
    new92.71 KB
    new56.28 KB
    new93.48 KB
    new82.52 KB
    new55.01 KB
    new56.84 KB
    new96.16 KB
    new92.78 KB

    Here are the screenshots 📸⎚

    tedbow’s picture

    Issue summary: View changes
    StatusFileSize
    new95.75 KB
    new977 bytes
    new63.23 KB
    +++ b/core/modules/update/src/ProjectSecurityRequirement.php
    @@ -0,0 +1,287 @@
    +        $message .= '<p>' . $this->t('Update to %next_minor or higher soon to continue receiving security updates.', ['%next_minor' => $this->nextVersion])
    

    %next_minor should be @next_minor to match others

    I also updated the screen shot.

    This is ready for review

    The interdiff is from #179 because the patches from @dww will now belong in #3110223: Add ModuleVersion::getMinorVersion() method
    @dww thanks for opening that issue

    benjifisher’s picture

    I am reviewing recent comments, starting with #165. In order to keep track of the constants mentioned in 165.1 and 165.2, I added comments to #2998285: Add information on later releases to updates.drupal.org and #3107378: Deprecate hard-coded Drupal 8 dates from update logic for the status report once this information is provided by the infrastructure.

    xjm’s picture

    Probably we should add all our followups to the remaining tasks in the IS so they're easty to find.

    benjifisher’s picture

    Issue tags: +DrupalCampNJ2020

    There is only one thing (#3 below) that I think really has to be fixed, but as long as we have to have one more revision, I will ask for several changes. I think they will all be easy, and I hope that none will be controversial.

    1. Regarding #165.4 and the reply in #168: I suggest we compromise on leaving the variable names as they are and updating the @param comment and the @var comment for the corresponding class variable as suggested in #165: "The existing (currently installed) version of the project."
    2. Regarding #169.6: we will remove that annoying code in #2998285 or #3107378.
    3. --- /dev/null
      +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,212 @@
      ...
      +   * @return \Drupal\update\ProjectSecurityData
      +   *   The ProjectSecurityData instance.
      +   */
      +  public static function createFormProjectDataAndReleases(array $project_data, array $releases) {
      --- /dev/null
      +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      @@ -0,0 +1,287 @@
      ...
      +   * @return \Drupal\update\ProjectSecurityRequirement
      +   *   The ProjectSecurityRequirement instance.
      ...
      +  public static function createFromProjectDataArray(array $project_data) {
      --- a/core/modules/update/update.compare.inc
      +++ b/core/modules/update/update.compare.inc
      @@ -483,6 +489,10 @@ function update_calculate_project_update_status(&$project_data, $available) {
      ...
      +  $security_data = ProjectSecurityData::createFormProjectDataAndReleases($project_data, $available['releases']);
      --- a/core/modules/update/update.install
      +++ b/core/modules/update/update.install
      @@ -7,6 +7,7 @@
      ...
      +      if ($core_coverage_requirement = ProjectSecurityRequirement::createFromProjectDataArray($data['drupal'])->getRequirement()) {
          

      Naming things is hard. I am sorry for the nit, but please correct the spelling: From, not Form. Less important, but I would prefer createFromProjectData instead of createFromProjectDataArray for consistency.

    4. Another nit, but since I am already asking for small changes, I will ask for this one, too. In the lines quoted above, we should have @return static and we can remove the one-line description according to Indicating data types in documentation in the coding standards. IMO we should remove the one-line description since it does not add any useful information.
    5. In #157, #161, #162 it was decided to remove the property $projectData. I agree that it makes sense to extract the parts we need in the constructor or create methods and not keep the original array. But I do think that, from a documentation point of view, it was better to list all those keys in a class property than in the docblock of the create method. I am not asking you to change it back at this point.
    6. --- /dev/null
      +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,212 @@
      ...
      +   * Because this class only handles the Drupal core project values will be
      +   * semantic version numbers such as 8.8.0, 8.8.0-alpha1 or 9.0.0.
          

      Another nit, with an easy fix. Add a comma after "Drupal core project".

    7. --- /dev/null
      +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,212 @@
      ...
      +  /**
      +   * Constructs a ProjectSecurityData object.
      ...
      +  private function __construct($existing_version = NULL, array $releases = []) {
      ...
      +  /**
      +   * Constructs a ProjectSecurityData object.
      ...
      +  public static function createFormProjectDataAndReleases(array $project_data, array $releases) {
          

      I do not like having identical one-line descriptions for the constructor and the create method, but if you want to leave it as is, that is OK.

    8. --- /dev/null
      +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,212 @@
      ...
      +  /**
      +   * Define constants for versions with support end dates.
      +   *
      +   * Two types of constants are supported:
      +   * - SUPPORT_END_DATE_[VERSION_MAJOR]_[VERSION_MINOR]: A date in 'Y-m-d' or
      +   *   'Y-m' format.
      +   * - SUPPORT_ENDING_WARN_DATE__[VERSION_MAJOR]_[VERSION_MINOR]: A date in
      +   *   'Y-m-d' format.
      +   *
      +   * @see \Drupal\update\ProjectSecurityRequirement::getDateEndRequirement()
      +   */
      +  const SUPPORT_END_DATE_8_8 = '2020-12-02';
      +
      +  const SUPPORT_ENDING_WARN_DATE_8_8 = '2020-06-02';
          

      The code comment for warning dates has a double underscore. It should be consistent with the comment for end dates and the actual constant.

    9. I like the decision to make the constructors private and supply create methods instead. I did not think of that. Is it worth adding a code comment to explain this?
    10. --- /dev/null
      +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,212 @@
      ...
      +  protected $releases;
      ...
      +  protected $existingVersion;
      ...
      +  private function __construct($existing_version = NULL, array $releases = []) {
          

      Another easy-to-fix nit: switch the order of the two properties so that it matches the order in the constructor.

    11. --- /dev/null
      +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      @@ -0,0 +1,287 @@
      ...
      +   * @param array $security_coverage_info
      +   *   Security coverage information as set
      +   * @param string|null $existing_version
      +   *   The next version after the installed version in the format
      +   *   [MAJOR].[MINOR].
      +   * @param string|null $next_version
      +   *   The next version after the installed version in the format
      +   *   [MAJOR].[MINOR].
      +   */
      +  private function __construct($project_title = NULL, array $security_coverage_info = [], $existing_version = NULL, $next_version = NULL) {
          

      The first @param comment got cut off. In the create method that follows, we have

         *   - security_coverage_info (array): The security coverage information as
         *     returned by \Drupal\update\ProjectSecurityData::getCoverageInfo().
          

      Then the next two @param comments have the same description. The first should simply be "The currently installed version in the format [MAJOR].[MINOR]."

    12. --- /dev/null
      +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      @@ -0,0 +1,287 @@
      ...
      +  /**
      +   * Constructs a ProjectSecurityRequirement object from project data.
      +   *
      +   * @param array $project_data
      +   *   Project data form Drupal\update\UpdateManagerInterface::getProjects().
          

      s/form/from/

    benjifisher’s picture

    Issue summary: View changes
    Status: Needs review » Needs work
    Issue tags: -Needs issue summary update

    I meant to set this issue to NW with my previous comment. I will do it now.

    I added the follow-up issues to the summary, so I am removing the "Needs issue summary update" tag. Or do we also need follow-up issues for 174.3 and 174.5?

    We already have several follow-up issues listed under "Completed tasks", so I added them there instead of under "Remaining tasks". My thinking is that the task for now is to create the follow-up issue.

    tedbow’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new7.04 KB
    new63.17 KB

    @benjifisher thanks again for the review!

    1. Taking your suggestion accept for the end "of the project." because the class is just about a project and it keeps it to 1 line for the var
    2. Yep
    3. fixed
    4. fixed
    5. ok. I think point of not having them documenting in the class is the class doesn't have to know that info comes from an array at all. Only the factory method has to know about that
    6. fixed
    7. ok changed both factory functions to "create a ..... object from ....." format
    8. fixed
    9. I don't think we need a comment on this. Hopefully we will use this pattern more often and we shouldn't explain it everytime. I think scope of the constructor and the public factory explains it in itself
    10. switched
    11. fixed
    12. 12
    xjm’s picture

    @benjifisher has 🦅👀!

    tedbow’s picture

    StatusFileSize
    new975 bytes
    new63.21 KB

    Talked to @benjifisher and pointed out a missed couple occurrences for his suggestion in #191.1

    benjifisher’s picture

    Status: Needs review » Reviewed & tested by the community

    Awesome! The patch in #195 fixes all the things I pointed out in #191. Given the tiny change between #193 and #195, I will take a chance and mark this RTBC even though the testbot is still running.

    tedbow’s picture

    Status: Reviewed & tested by the community » Needs review
    StatusFileSize
    new17.55 KB
    new64.03 KB

    @xjm mention that throughout this code we have "supported" when we it should really be "security coverage". This patch fixes comments, variable names and method names. I didn't update the string literals and therefore didn't update test expectations. Will do that next.

    Also found another nit

    +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
    @@ -357,6 +357,224 @@ public function securityUpdateAvailabilityProvider() {
    +   * Tests the Update Manager module when a security update is available.
    

    This was copied from previous function

    benjifisher’s picture

    Status: Needs review » Reviewed & tested by the community

    I will be so happy when we adopt a PR/MR workflow and I can review atomic commits instead of interdiffs or updated patches.

    In the mean time, it will make my reviews easier if you can post multiple patches, each with an interdiff. I guess that has the drawback that other people may be annoyed by the number of comments.

    It seems that we are struggling with the same wording in multiple places. For example:

       *   - additional_minors_coverage (int): The number of additional minor
       *     versions the existing version will receive security coverage. For
       *     example, if this value is 2 and the existing version is 9.0.1, the
       *     9.0.x branch will receive security coverage until the release of
       *     version 9.2.0.
    

    and, later,

       * Gets the release the current minor will receive security coverage until.
       *
       * For example, if two minor core versions receive security updates and the
       * current minor version is 8.6, this method will return 8.8.0.
    

    Maybe we can move this explanation to the doc block on the class. Get it right once and make our code comments more DRY.

    Some of these lines are getting very long. For example,

          $info['security_coverage_ending_warn_date'] = defined("self::SECURITY_COVERAGE_ENDING_WARN_DATE_$version_suffix") ? constant("self::SECURITY_COVERAGE_ENDING_WARN_DATE_$version_suffix") : NULL;
    
    

    There are places in the code where we break up our ternary operators:

        return isset($latest_minor)
          ? $security_covered_release_info['version_minor'] - $latest_minor
          : NULL;
    

    (I often use that style; maybe those lines are the result of one of my previous reviews?) Can we use this style some more (and also break before the "=" if needed to stay under 80 characters)?

    Another place with long lines:

        $security_covered_until_release = [
          'version_major' => (int) $existing_release_version->getMajorVersion(),
          'version_minor' => $this->getSemanticMinorVersion($this->existingVersion) + static::CORE_MINORS_WITH_SECURITY_COVERAGE,
        ];
        $security_covered_until_release['version'] = "{$security_covered_until_release['version_major']}.{$security_covered_until_release['version_minor']}.0";
        return $security_covered_until_release;
    

    That will be easier to read if we change it to

        $version_major = ...
        $version_minor = ...
        return [
          'version_major' => $version_major,
          'version_minor' => $version_minor,
          'version' => "$version_major.$version_minor.0",
        ];
    
    benjifisher’s picture

    Status: Reviewed & tested by the community » Needs work

    BTW, my preference for short lines is not just aesthetic. The last patch updated "support" to "security coverage" or "security_coverage" all over the place. There were some long lines where that change was made in several places. If, from the start, those lines had been broken up, then we might now have a few lines with one change each. That would have made the review much easier.

    Since we seem to be focusing on grammar in code comments at this point, please search for "If" and "Because" and add commas. For example,

          // If the existing version does not have a release we cannot get the
          // security coverage information.
    ...
          // Because the current minor version no longer has security coverage
          // advise the site owner to update.
    

    There should be commas after "release" and "coverage".

    This comment is missing "with":

       * Gets the formatted message for a project no security coverage.
    

    Good news: I am finished reviewing the patch in #197, and that is all for now. The changes made in the patch look good, and I checked that none of the old variable/key/constant names still appear anywhere in the Update module.

    I am setting back to NW based on the comment in #197 that work is still going on as well as the points I brought up in #198 and this comment.

    tedbow’s picture

    1. re #197 my last point

      This was copied from previous function

      Sorry I meant I fixed that in that patch

    2. re my comment

      I didn't update the string literals and therefore didn't update test expectations. Will do that next.

      Actually looking at the messages we give to user I don't think they have to updated. Looking at the expected messages in \Drupal\Tests\update\Functional\UpdateCoreTest::securityCoverageMessageProvider(), they all mention "security" and we have already revised them multiple times and gotten @xjm's, release manager, sign-off.

    3. So I think just 198 needs to be resolved.

      In the mean time, it will make my reviews easier if you can post multiple patches, each with an interdiff. I

      will do

    tedbow’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new4.22 KB
    new64.04 KB

    Somehow when looked at this this morning I missed #198

    So here is patch that just addresses #199, the missing commas and the missing "with".

    tedbow’s picture

    StatusFileSize
    new20.96 KB
    new57.78 KB

    was in the middle of address #198 but I found another problem that must addressed.

    +++ b/core/modules/update/src/ProjectSecurityData.php
    @@ -0,0 +1,216 @@
    +      if ((int) $release_version->getMajorVersion() === $security_covered_release_info['version_major'] && $release['status'] === 'published' && empty($release['version_extra'])) {
    

    We should not be looking at $release['version_extra'] or any version_* values as they were removed in #3074993: Use "current" in update URLs instead of CORE_COMPATIBILITY to retrieve all future updates.

    I thought maybe this was check wasn't needed but I removed it and tests fail. I see the problem is that this is still in our test XML fixtures. I guess I didn't remove them in the last reroll after #3074993.

    This should be checking $release_version->getVersionExtra() instead.

    Fixing this and removing the version_* from the new XML and also #3074993mdhash, and mdhash which were also removed in #3074993

    This pointed another simplification we can make but will make a patch of just this change.

    tedbow’s picture

    StatusFileSize
    new4.63 KB
    new57.4 KB
    +++ b/core/modules/update/src/ProjectSecurityData.php
    @@ -0,0 +1,216 @@
    +   * @return array
    +   *   If release information is not available an empty array is returned,
    +   *   otherwise the release information with the following keys:
    +   *   - version_major (int): The major version of the release.
    +   *   - version_minor (int): The minor version of the release.
    +   *   - version (string): The version number.
    +   */
    +  private function getSecurityCoverageUntilReleaseInfo() {
    ...
    +    $security_covered_until_release = [
    +      'version_major' => (int) $existing_release_version->getMajorVersion(),
    +      'version_minor' => $this->getSemanticMinorVersion($this->existingVersion) + static::CORE_MINORS_WITH_SECURITY_COVERAGE,
    +    ];
    +    $security_covered_until_release['version'] = "{$security_covered_until_release['version_major']}.{$security_covered_until_release['version_minor']}.0";
    

    Originally when I wrote this the idea was to get the info for the release that current version would have security coverage for in a similar format that the xml made release info. So I used the keys version_major, version_minor and version.

    But now the update XML has removed this(as mentioned in the previous comment), so all we need is the actually version number. We can get the major and minor from that in the same we are getting from the version number in the XML.

    So changing this function just return string|null with the version number or NULL if we can't determine it.

    benjifisher’s picture

    Comments #172, #174 refer to last week's Usability (or UX) meeting. The recording is now available: Drupal Usability Meeting - 2020-01-31.

    benjifisher’s picture

    Status: Needs review » Needs work

    @tedbow:

    Thanks for the incremental patches! The first couple have been easy to review.

    1. Re #200.1: yes, that is how I understood the comment.
    2. #200.2: hurray!
    3. #201 addresses the points I raised in #199.
    4. #202: I find it frustrating that I have no easy way to check the XML feed from d.o, and now you tell me that it is changing in the middle of work on this issue. Of course, the tests are only as good as the fixtures. Is ther any way to keep them synchronized? AFAIK, the closest thing we have to documentation for this feed is the comments that I previously asked you to add to this patch:
      --- /dev/null
      +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,216 @@
      ...
      +  /**
      +   * Releases as returned by update_get_available().
      +   *
      +   * @var array
      +   *
      +   * Each release item in the array has metadata about that release. This class
      +   * uses the keys:
      +   * - status (string): The status of the release.
      +   * - version_major (string): The major version of the release.
      +   * - version_minor (string): The minor version of the release.
      +   * - version_extra (string): The extra string at the end of the version string
      +   *   such as '-dev', '-rc', '-alpha1', etc.
      +   *
      +   * @see update_get_available()
      +   */
      +  protected $releases;
      

      Should we remove the line for version_extra? Maybe version_major and version_minor as well? This is really hard to follow because of the existing code in update.compare.inc. In #202 you mention mdhash twice: one of those should be filesize. I checked these changes against the "Proposed resolution" section of #3074993: Use "current" in update URLs instead of CORE_COMPATIBILITY to retrieve all future updates.

    5. I see that #3074993 is marked Postponed, but that is for the port to Drupal 8.8. The issue has already been fixed for 9.0 and 8.9. That is why we need to make those changes as part of this issue.
    6. Is there a follow-up to #3074993 to update the other fixtures in the same directory? I guess there is only one: aaa_update_test.8.x-1.2.xml.

    Other than these points, the patch in #202 looks good.

    benjifisher’s picture

    I reviewed the patch in #203, and it looks good.

    I am leaving the status as NW for the points raised in #198 and #205.

    Let me classify this suggestion from #198 as "nice to have" rather than required:

    Maybe we can move this explanation to the doc block on the class. Get it right once and make our code comments more DRY.

    Of course, I am not the final decider on whether that is needed.

    tedbow’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new831 bytes
    new57.2 KB
    1. re #205.4

      I find it frustrating that I have no easy way to check the XML feed from d.o, and now you tell me that it is changing in the middle of work on this issue.

      Yes it is frustrating but there a lot of concurrent issue with the Update module.

      But you can check the feeds from drupal.org. This is the type of feed core currently uses https://updates.drupal.org/release-history/webform/current (you can swap out the project name)

      Is ther any way to keep them synchronized?

      Not really but I think drupal.org should not change those unless there is existing issue to update our code and tests.

      AFAIK, the closest thing we have to documentation for this feed is the comments that I previously asked you to add to this patch:

      Actually there is a documentation page: https://www.drupal.org/drupalorg/docs/apis/update-status-xml

      All of the ones labeled "Legacy-only" are not in the feed that 8.9.x uses.

      Should we remove the line for version_extra? Maybe version_major and version_minor as well?

      Yes we should remove all those from the doc. Uploading a patch that fixes that.

    2. re #205.6
      I created #3110917: [meta] Fix update XML fixtures bad data
      There are various small problems in our fixtures maybe we could fix them in 1 issue?
    tedbow’s picture

    StatusFileSize
    new4.08 KB
    new57.09 KB

    ok back to addressing #198

    1. Maybe we can move this explanation to the doc block on the class. Get it right once and make our code comments more DRY.

      I added an example to \Drupal\update\ProjectSecurityData::CORE_MINORS_WITH_SECURITY_COVERAGE instead of the class docblock. I think this is the place that needs to be very clear because this is the constant that would be updated if we ever decide to change the number of minors that receive security coverage.

    2. I fixed the long lines in the 2 classes. A couple of the examples no longer applied as they were replaced in #203
    benjifisher’s picture

    @tedbow:

    Thanks for all the answers in #207.

    I am glad to learn that we do have some documentation of the API. It is out of scope for this issue, but I think it should be referenced in the Update module. (I am not sure exactly where in that module.) I did a quick search:

    $ grep -ri updates.drupal.org core/modules/update
    core/modules/update/tests/src/Kernel/Migrate/d6/MigrateUpdateConfigsTest.php:    $this->assertIdentical('http://updates.drupal.org/release-history', $config->get('fetch.url'));
    core/modules/update/src/UpdateManagerInterface.php:   * updates.drupal.org. That information is stored in the
    core/modules/update/src/UpdateFetcher.php:  const UPDATE_DEFAULT_URL = 'http://updates.drupal.org/release-history';
    

    I guess that UpdateFetcher.php would be the place to link to the API docs. Maybe change the default URL to https at the same time.

    I checked that the patch in #207 addresses the point raised in #205.4.

    Thanks also for adding #3110917: [meta] Fix update XML fixtures bad data. That addresses #205.6. The other points in #205 are comments and do not need a response.

    dww’s picture

    @benjifisher Re: #209:

    Maybe change the default URL to https at the same time.

    See #1538118: Update status does not verify the identity or authenticity of the release history URL :/

    benjifisher’s picture

    @dww: Thanks for the reminder that things are often more complicated than they seem!

    @tedbow: Thanks for splitting up those long lines and consolidating the comments. That is good enough for me, although (as I said before) I do not have the last word. I am ready to mark this issue RTBC, but ...

    Are there any further changes that you plan to make?

    If you want to address them, there are a couple of places in ProjectSecurityRequirement.php that still have long lines:

      private function getVersionEndRequirement() {
        $requirement = [];
        if ($security_coverage_message = $this->getVersionEndCoverageMessage()) {
          $requirement['description'] = $security_coverage_message;
          if ($this->securityCoverageInfo['additional_minors_coverage'] > 0) {
            $requirement['value'] = $this->t('Supported minor version');
    	$requirement['severity'] = $this->securityCoverageInfo['additional_minors_coverage'] > 1 ? REQUIREMENT_INFO : REQUIREMENT_WARNING;
          }
    

    The last line could be split up. And

      private function getDateEndRequirement() {
    ...
        $security_coverage_end_timestamp = \DateTime::createFromFormat('Y-m-d', $full_security_coverage_end_date)->getTimestamp();
    

    We could split the line at the = and before the ->.

    My preference is to split before the =, not after. AFAIK either one is allowed under the coding standards, so we can agree to disagree on this point.

    The other long lines are mostly conditionals, strings, and function declarations, which are specifically allowed to exceed 80 characters. Also, despite being long, none of them are complex IMO.

    I fixed the long lines in the 2 classes. A couple of the examples no longer applied as they were replaced in #203

    Yes, I noticed that when reviewing #203. This is one place where the incremental patches make it easier to review, so thanks again for that!

    xjm’s picture

    +++ b/core/modules/update/src/ProjectSecurityRequirement.php
    @@ -0,0 +1,290 @@
    +      if ($this->securityCoverageInfo['additional_minors_coverage'] > 0) {
    +        $requirement['value'] = $this->t('Supported minor version');
    +        $requirement['severity'] = $this->securityCoverageInfo['additional_minors_coverage'] > 1 ? REQUIREMENT_INFO : REQUIREMENT_WARNING;
    +      }
    

    So, logically, with the change we've made throughout the patch:

    Should the $requirement['value'] be "Security coverage only"? when it's a warning and it's not the most recent minor? What do you think?

    (Sorry in advance since this would mean another screenshot to update.)

    Wanted to post that first to get a second opinion on it. I haven't reviewed the entire new patch yet. :)

    benjifisher’s picture

    @xjm: Thanks for bringing that up sooner rather than later.

    The code mentioned in #212 corresponds to the first two screenshots.

    I am pretty sure that we discussed this many comments ago, but there may have been some misunderstanding on this point.

    I think the idea is that this code is about security coverage, so should not distinguish between "security updates and bug fixes" and "security updates only". I do not feel strongly about that decision.

    I would like to keep the UI text consistent. If we do decide to replace "Supported minor version" with "Security coverage only" (when the next minor version has been released) then I would like the other messages to be something like "Security updates and bug fixes" and either "No security coverage" or "Neither security updates nor bug fixes".

    tedbow’s picture

    re #212

    Looking at the screenshot

    We already have a big heading "DRUPAL CORE SECURITY COVERAGE".
    So the heading "Supported Minor Version" and "Unsupported minor version" pertains to "security coverage" only and we are not saying anything in this issue or the message dealing with bug fixes.
    If we were going to add bug fixes text to this issue we would have to also update the main message text to reflect that and then do another round of UX review.

    I think why this issue is "critical" is because we informing the user about "security coverage". So if I think we should only cover that issue and get this issue done as soon as possible. Displaying bug fixes info is not as critical as displaying security coverage issue so I think we should not delay this issue with related but non-critical problems.

    xjm’s picture

    For #214, I can see it being read either way. I'm fine with it as-is since we already have a followup to improve the text in #3110186: Simplify the wording of messages on the status report about security coverage for the site's installed minor version. So fine by me as-is for now.

    For #211, I don't think the lines are long or complex enough to require being split onto multiple lines. It'd be OK if they were, but it's also OK that they aren't.

    Thanks!

    tedbow’s picture

    1. I think the long lines in #211 are not too long are readable
    2. re @benjifisher

      That is good enough for me, although (as I said before) I do not have the last word. I am ready to mark this issue RTBC, but ...

      Are there any further changes that you plan to make?

      Nope I think we are good. We got @xjm's ok too. So RTBC?.....

    benjifisher’s picture

    Status: Needs review » Reviewed & tested by the community

    Yes, all my suggestions have been addressed.

    Just to be thorough, I had another look at the patch in #203. :+1:

    tim.plunkett’s picture

    +1 to RTBC, I believe everything is now addressed. Thanks @benjifisher for the final review!

    dww’s picture

    Assigned: Unassigned » dww

    Huzzah for progress! I'm starting another thorough review now. Hope to not find anything. ;) But wanted to reply here so folks know it's underway...

    dww’s picture

    Assigned: dww » Unassigned
    Status: Reviewed & tested by the community » Needs review

    Mostly looks fantastic, minus the stuff I already said I was uncomfortable with. ;)

    A bunch of tiny nits, and a small number of questions of substance:

    1. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,208 @@
      +    if (empty($this->releases[$this->existingVersion])) {
      +      // If the existing version does not have a release, we cannot get the
      +      // security coverage information.
      +      return [];
      +    }
      ...
      +    if (empty($this->releases[$this->existingVersion])) {
      +      return NULL;
      +    }
      

      I notice we have/need the same check in a few places. Seems like this whole class is fubar if this check fails. Should we add it to the factory method and bail early, then assume we have this everywhere internally?

    2. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,208 @@
      +  /**
      +   * Gets the number of additional minor security covered releases.
      +   *
      +   * @param string $security_covered_version_string
      +   *   The version the existing version will receive security updates until.
      +   *
      +   * @return int|null
      +   *   The number of additional security covered minor releases or NULL if this
      +   *   cannot be determined.
      +   */
      +  private function getAdditionalSecurityCoveredMinors($security_covered_version_string) {
      +    $security_covered_version = ModuleVersion::createFromVersionString($security_covered_version_string);
      +    foreach ($this->releases as $release) {
      +      $release_version = ModuleVersion::createFromVersionString($release['version']);
      +      if ($release_version->getMajorVersion() === $security_covered_version->getMajorVersion() && $release['status'] === 'published' && !$release_version->getVersionExtra()) {
      +        $latest_minor = $this->getSemanticMinorVersion($release['version']);
      +        break;
      +      }
      +    }
      +    return isset($latest_minor)
      +      ? $this->getSemanticMinorVersion($security_covered_version_string) - $latest_minor
      +      : NULL;
      +  }
      

      I've read this function and doc block at least 3 times and I'm still not 100% sure I understand what this is doing and why. It seems like we have an idea about a future release that the current release should be supported until, based on the class constant that expresses the core/sec team policy. We search all available releases of core, looking for the latest release of the same major version that's both published, and "official" (no extra). Given this, we know the "latest_minor" that's been officially released. If we found the latest officially-released minor, we return the difference of the minor version we think we're aiming for, minus the latest official release.

      Assuming all that is true, I'd love to try to improve the docs on this function, both the phpdoc, and perhaps some more inline comments. Is that agreeable? If so, I'll try to upload something ASAP.

    3. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      @@ -0,0 +1,290 @@
      +  /**
      +   * The existing (currently installed) version in the format [MAJOR].[MINOR].
      +   *
      +   * @var string|null
      +   */
      +  private $existingVersion;
      

      In other internal classes, the private $existingVersion is the full version string. Not yet sure why it's only MAJOR.MINOR here, and am slightly worried about the potential for confusion as other people try to understand all this code that "existingVersion" means different things in different classes. Can we call this "existingBranch" or something to more clearly identify what it is, and alert other developers that it's not a full version string?

    4. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      @@ -0,0 +1,290 @@
      +   * @param string|null $existing_version
      +   *   The existing (currently installed) version in the format [MAJOR].[MINOR].
      +   * @param string|null $next_version
      +   *   The next version after the installed version in the format
      +   *   [MAJOR].[MINOR].
      

      Same with these. Can they be "existing_branch" and "next_branch", instead?

    5. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      @@ -0,0 +1,290 @@
      +   * @return static
      

      Dumb question: is this true? Isn't @return \Drupal\update\ProjectSecurityRequirement more accurate?

    6. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      @@ -0,0 +1,290 @@
      +   * Gets the security coverage requirement if any.
      

      Tiny nit: missing comma after "requirement":
      "Gets the security coverage requirement, if any."

    7. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      @@ -0,0 +1,290 @@
      +        $requirement['value'] = $this->t('Supported minor version');
      ...
      +        $requirement['value'] = $this->t('Unsupported minor version');
      

      I guess we have #3110186: Simplify the wording of messages on the status report about security coverage for the site's installed minor version to further refine this text, but I wonder if most users understand semver enough to know what "minor version" means...

    8. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      @@ -0,0 +1,290 @@
      +   * @return string|\Drupal\Component\Render\MarkupInterface
      +   *   The security coverage message, or an empty string if there is none.
      ...
      +    return Markup::create($message);
      

      Looks like it's always a MarkupInterface, never an empty string...

    9. +++ b/core/modules/update/tests/modules/update_test/src/Datetime/TestTime.php
      @@ -0,0 +1,22 @@
      + * Test service to all altering request time.
      

      This doesn't quite parse. Not sure what "to all altering request time" means. s/all/call/? Even then, I'm not really sure. ;)

    10. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
      @@ -357,6 +357,224 @@ public function securityUpdateAvailabilityProvider() {
      +      $this->assertSession()->pageTextNotContains('Drupal core security coverage');
      

      Should we more carefully assert that there's no requirement heading containing this text, instead of searching for it on the entire page? We can probably safely assume that those 4 words won't appear anywhere else on the page for some other reason, but maybe additional caution is worth-while?

    11. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
      @@ -357,6 +357,224 @@ public function securityUpdateAvailabilityProvider() {
      +   * These test cases rely on the following fixtures containing the following
      +   * releases:
      +   * - drupal.sec.2.0_3.0-rc1.xml
      +   *   - 8.2.0
      +   *   - 8.3.0-rc1
      +   * - drupal.sec.2.0.xml
      +   *   - 8.2.0
      +   * - drupal.sec.2.0_9.0.0.xml
      +   *   - 8.2.0
      +   *   - 9.0.0
      +   * - drupal.sec.9.0.xml
      +   *   - 8.9.0
      +   * - drupal.sec.9.9.0.xml
      +   *   - 9.9.0
      

      Love these details, thanks!

    12. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
      @@ -357,6 +357,224 @@ public function securityUpdateAvailabilityProvider() {
      +        'message' => "The installed minor version of Drupal (8.0), is no longer supported and will not receive security updates.$update_asap_message $see_available_message$release_coverage_message",
      ...
      +        'message' => "The installed minor version of Drupal (8.1), will stop receiving official security support after the release of 8.3.0.Update to 8.2 or higher soon to continue receiving security updates. $see_available_message$release_coverage_message",
      

      I don't fully grok why some of these messages have spaces between them and others don't. Does it not matter? If not, it'd be more readable with spaces between everything. If it does matter, I'd love to understand why some need it and others don't...

      This pattern repeats a lot, only flagging the first few...

    13. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
      @@ -357,6 +357,224 @@ public function securityUpdateAvailabilityProvider() {
      +      // Ensure that if the next major version is released  and the supported
      

      Nit: extra space after "released"

    14. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
      @@ -357,6 +357,224 @@ public function securityUpdateAvailabilityProvider() {
      +      // Ensure that if the next major version has been released and
      +      // the supported until version has not been released we show a message.
      ...
      +
      

      Ubernit: needs comma before "we show a message."

    15. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
      @@ -357,6 +357,224 @@ public function securityUpdateAvailabilityProvider() {
      +      '8.2.0, 9 no message' => [
      +        'installed_version' => '8.2.0',
      +        'fixture' => 'sec.2.0_9.0.0',
      +        'requirements_section_heading' => 'Warnings found',
      +        'message' => "The installed minor version of Drupal (8.2), will stop receiving official security support after the release of 8.4.0.Update to 8.3 or higher soon to continue receiving security updates. $see_available_message$release_coverage_message",
      +        'mock_date' => '',
      +      ],
      

      Nit: the key for this test record says "no message", but the test case looks like it's got messages...

    16. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
      @@ -357,6 +357,224 @@ public function securityUpdateAvailabilityProvider() {
      +      // Ensure that if the 8.8 support window is not finished a message is
      +      // displayed.
      

      Again: "... is not finished, a message is displayed."

    17. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
      @@ -357,6 +357,224 @@ public function securityUpdateAvailabilityProvider() {
      +      // Ensure that if the 8.8 support window is not finished but it is within
      +      // 6 months of closing a message is displayed.
      

      "Ensure that if the 8.8 support window is not finished, but it is within 6 months of closing, a message is displayed."

    18. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
      @@ -357,6 +357,224 @@ public function securityUpdateAvailabilityProvider() {
      +    // Ensure that warning message does not change including the last day of
      +    // support.
      

      "... does not change, including ..."

    19. +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
      @@ -357,6 +357,224 @@ public function securityUpdateAvailabilityProvider() {
      +    // Ensure that the LTS support window message does not change including the
      +    // last day of support.
      

      "... change, including ..."

    20. +++ b/core/modules/update/update.compare.inc
      @@ -5,6 +5,7 @@
      @@ -190,6 +191,11 @@ function update_calculate_project_data($available) {
      
      @@ -483,6 +489,10 @@ function update_calculate_project_update_status(&$project_data, $available) {
      +  /** @var \Drupal\update\ProjectSecurityData $security_data */
      +  $security_data = ProjectSecurityData::createFromProjectDataAndReleases($project_data, $available['releases']);
      +  $project_data['security_coverage_info'] = $security_data->getCoverageInfo();
      +
      

      Seems that the coverage info is only used on the status report, not the available updates report. Any reason we're adding it here in update_calcuate_project_data()?

    21. +++ b/core/modules/update/update.install
      @@ -40,6 +41,10 @@ function update_requirements($phase) {
      +      if ($core_coverage_requirement = ProjectSecurityRequirement::createFromProjectData($data['drupal'])->getRequirement()) {
      +        $requirements['coverage_core'] = $core_coverage_requirement;
      +      }
      +
      

      Maybe we could handle the ProjectSecurityData stuff directly right here, instead of bloating the monster project_data array with it and passing all those strings around everywhere else?

    Only NR, not NW. Probably this could be committed as-is and we can fix / improve in the existing follow-ups. But if @tedbow agrees with any of this and wants to re-roll, I'm happy to re-RTBC ASAP.

    xjm’s picture

    Regarding #220:

    I'll leave #220.1, 3, 4, 20, and 21 for @tedbow.

    One grammar fix of my own:

    +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
    @@ -357,6 +357,224 @@ public function securityUpdateAvailabilityProvider() {
    +    // Ensure that if LTS support window is finished a message is displayed.
    
    Ensure an error is displayed if the LTS version's support has ended.

    #220.2

    The main thing that's likely confusing is that the sentence that ends in a preposition:
    + * The version the existing version will receive security updates until.

    I think I gave this feedback once already maybe, but this should be rewritten as:

    The version until which the existing version receives security coverage.

    As has already been stated, calling it the "existing version" is the existing pattern throughout the module and it's scope creep to change that.

    The return value similarly can be fixed grammatically:

    +   *   The number of additional security covered minor releases or NULL if this
    +   *   cannot be determined.

    It can be rewritten as:

    The number of additional minor releases that receive security coverage, or NULL if this cannot be determined.

    Those two changes should make it clearer, I think.

    #220.5

    I think it's correct as-is.

    #220.6

    +++ b/core/modules/update/src/ProjectSecurityRequirement.php
    @@ -0,0 +1,290 @@
    +   * Gets the security coverage requirement if any.

    Yeah, that comma should be added.

    Gets the security coverage requirement, if any.

    #220.7

    Out of scope here as it was one of the pieces we already said in #174 we'd cover in #3110186: Simplify the wording of messages on the status report about security coverage for the site's installed minor version.

    #220.8

    If $message is any false-y value (like NULL), Markup::create() will return an empty string.

    #220.9

    +++ b/core/modules/update/tests/modules/update_test/src/Datetime/TestTime.php
    @@ -0,0 +1,22 @@
    + * Test service to all altering request time.

    Yeah, that needs to be fixed. I don't know what it says either.

    #220.10

    IMO it's better as-is. Else we're further coupling the test to specific markup/theming and we could get a false pass if they're changed. If someone introduces a different instance of this phrase later for whatever reason, the page can be updated.

    #220.12

    These are values being matched to getText(). That's how getText() works.

    #220.13 and .14

    +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
    @@ -357,6 +357,224 @@ public function securityUpdateAvailabilityProvider() {
    +      // Ensure that if the next major version has been released and
    +      // the supported until version has not been released we show a message.
    

    This can be clarified to:

    Ensure a message is still shown if the next major version has been released even if additional minors indicated by CORE_MINORS_WITH_SECURITY_COVERAGE minors have not been released.

    (I think that's what this case is testing, that is.)

    This calls attention to the fact that we're still talking about "support" instead of "security coverage" in a lot of the test fixture comments.

    +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
    @@ -357,6 +357,224 @@ public function securityUpdateAvailabilityProvider() {
    +      // Ensure that if the 8.8 support window is not finished a message is
    +      // displayed.
    

    #220.16

    +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
    @@ -357,6 +357,224 @@ public function securityUpdateAvailabilityProvider() {
    +      // Ensure that if the 8.8 support window is not finished a message is
    +      // displayed.

    Let's rewrite it as:

    Ensure that a message is displayed during 8.8's active support.

    #220.17

    ++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
    @@ -357,6 +357,224 @@ public function securityUpdateAvailabilityProvider() {
    +      // Ensure that if the 8.8 support window is not finished but it is within
    +      // 6 months of closing a message is displayed.
    Ensure a warning is displayed if less than six months remain until the end of 8.8's security coverage.

    #220.18 and .19

    +++ b/core/modules/update/tests/src/Functional/UpdateCoreTest.php
    @@ -357,6 +357,224 @@ public function securityUpdateAvailabilityProvider() {
    +    // Ensure that warning message does not change including the last day of
    +    // support.
    ...
    +    // Ensure that the LTS support window message does not change including the
    +    // last day of support.
    

    These can both be:

    Ensure that the message does not change, including on the last day of security coverage.

    benjifisher’s picture

    Status: Needs review » Needs work

    The status should be NW for #220 and #221.

    tedbow’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new10.46 KB
    new57.25 KB

    re #220

    1. I would prefer not to put more logic in the factor. The logic that is there avoids having to have properties on the class for type and name.

      Since this is final class with 1 public method we can assume it has been checked once \Drupal\update\ProjectSecurityData::getCoverageInfo() has been called. Therefore I am removing it from getSecurityCoverageUntilVersion(),

      Keeping it in getCoverageInfo() means we can see more of the logic for evaluating core security coverage without adding unneeded properties to the class.

    2. I took @xjm 2 suggestions in #221

      As for understandability I have couple ideas with variable changes and inline comment. I will do separate patch for this in a couple comments.

    3. I changed the class level ones to $existingMajorMinorVersion and $nextMajorMinorVersion. I really don't want to use "branch" because we have supported_branch back in the update in the format 8.9.(add period at the end, also this is the issue to discuss that 😜) and our actual git branches for core are in the format 8.9.x. There is no guarantee either 1 of these won't change in the future. So using "branch" I think would just be more confusing
    4. changed to $existing_major_minor_version and $next_major_minor_version
    5. It is currently correct see #2158497: [policy, no patch] Use "$this" and "static" in documentation for @return types and the docs here https://www.drupal.org/docs/develop/standards/api-documentation-and-comm...
    6. fixed
    7. We can make it even better in #3110186: Simplify the wording of messages on the status report about security coverage for the site's installed minor version.
    8. as @xjm mentions in #221 this matches the doc of \Drupal\Component\Render\MarkupTrait::create()
    9. changed to

      Test service for altering the request time.

    10. I agree with @xjm about this in #220. In addition because we are asserting this phrase is not on the page we have no risk of the test passing when it should not if someone introduces a new instance of the this phrase on the page. It seems unlikely this would appear elsewhere on the page but it some tries to introduce it elsewhere this test will fail. Then this test can be updated. I think this is actually a good thing that someone trying use this phrase elsewhere on the page will see this fail and can determine if they really want to duplicate this phrase.
    11. 👍
    12. If there is not actually space in the page output but rather the words are separated by a tag such as <p> getText() will not match if you put a space in.
    13. change the 2 comments for the test cases that deal with the next major version being released to
      // Ensures the message is correct if the next major version has been
      // released and the additional minors indicated by
      // CORE_MINORS_WITH_SECURITY_COVERAGE minors have been released.
      

      and

      // Ensures the message is correct if the next major version has been
      // released and the additional minors indicated by
      // CORE_MINORS_WITH_SECURITY_COVERAGE minors have not been released.
      

      The next major version being released has no effect on the logic but put these test cases in just to be sure that doesn't change.

    14. ☝️
    15. fixed changed to '8.2.0, 9 warning'
    16. Took @xjm suggestion in #221
    17. Took @xjm suggestion in #221
    18. Took @xjm suggestion in #221
    19. Took @xjm suggestion in #221
    20. + 21 Good question and suggestion. I will address this in the next patch
    tedbow’s picture

    StatusFileSize
    new5.17 KB
    new55.87 KB

    re #220.20 & 21

    @dww very good catch. I think I was probably the person who originally put it here and at the time I thought it was the only place we had everything we needed. But now I see you are correct we can just put it in update_requirements()

    instead of bloating the monster project_data array with it and passing all those strings around everywhere else?

    Yes I think not setting in 'security_coverage_info' in project data will be a big win. If this in the project data we can expect some contrib or custom to code to inspect it and use the value 💥 we just created an API out of an array key/value. Calling it directly in update_requirements() we never have to set it in the array.

    Because both the classes introduced here are internal we trying to discourage developers from calling there public methods directly. But if they happen see $project_data['security_coverage_info'] there is nothing telling them they can't use this value.

    Here is patch that address that.

    tedbow’s picture

    StatusFileSize
    new2.56 KB
    new56.44 KB

    This patch going back to #220.2 and the understandability of getAdditionalSecurityCoveredMinors()

    1. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,204 @@
      +  private function getAdditionalSecurityCoveredMinors($security_covered_version_string) {
      +    $security_covered_version = ModuleVersion::createFromVersionString($security_covered_version_string);
      

      I think having $security_covered_version_string and then $security_covered_version which is an object is not great.

      We only need the major version from the object so let's just assign that to $security_covered_version_major and use $security_covered_version for the parameter.

      After that let's immediately set $security_covered_version_minor.

    2. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,204 @@
      +        $latest_minor = $this->getSemanticMinorVersion($release['version']);
      

      I added a comment here to explain we just need the first version that matches our criteria.

    3. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,204 @@
      +    return isset($latest_minor)
      +      ? $this->getSemanticMinorVersion($security_covered_version_string) - $latest_minor
      

      Added a comment here about we can just subtract.

      I didn't change any of the existing comments because they have been nit picked over a bunch and surely someone won't like the changes for comments we have already gone over.

    The last submitted patch, 224: 2991207-224.patch, failed testing. View results

    Status: Needs review » Needs work

    The last submitted patch, 225: 2991207-225.patch, failed testing. View results

    dww’s picture

    @xjm re: #221: Thanks for the replies and further improvements.

    @tedbow re: #223:
    1. Fair enough re: not wanting to add more logic to the factory. I guess if the factory blows up and returns NULL, then anywhere we instantiate one of these has to care, too. I suppose silently failing to provide any info is better than making every caller care about these details.
    2. See below.
    3. 👍
    4. 👍
    5. Thanks for the links to the docs. I don't think I'll ever fully understand PHP and PHPDoc, but whatever. Off topic. ;)
    6. 🙏
    7. 👍
    8. 👍
    9. 🙏Yay, that makes sense now. ;)
    10. Both your reply and @xjm's in #220 make total sense. Thanks to you both for the thoughtful response to this!
    12. Ahh, right. Some of these messages are wrapped in <p>. Kind of a PITA that's how getText() works, but so be it. Thanks for the explanation.
    13-19: 👍
    Interdiff from #223 looks great!

    Re: #224
    🙏Fantastic! Very glad you agree with this. Since all of this code only works for core (*sniff*), and is only used for the status report, way better to only instantiate and use it there, both for reducing "API" surface and for memory / resource consumption. Interdiff seems fine, although something about this is now causing test failures. :( Haven't dug into why, but it seems to be something is confused about the structure of the available releases array we're passing around. Fun with array-as-API! 🤦‍♂️I wish I had more courage last decade to question this practice throughout core and not add to the mess like I did with this module. ;) Glad we're finally coming to our senses about it.

    Re: #225:
    Thanks for working on this, too. @xjm's suggestions do indeed help, as do the inline comments you added and other changes. Interdiff seems fine.

    I still think the 1-liner could be improved, and that the whole doc block would benefit from more detail about what's happening, and probably providing some specific examples. I don't agree with this logic:

    I didn't change any of the existing comments because they have been nit picked over a bunch and surely someone won't like the changes for comments we have already gone over.

    That basically implies further reviews of anything aren't valuable once they've been reviewed once, which is clearly not the case. ;) Everyone has different eyes for different things, different perspectives.

    That said, none of this particular point is worthy of blocking a critical from going in. Following the pattern from #3101547: Clean up code documentation for display of core compatibility ranges for available module updates maybe we should just spin off another follow-up to really fix these code comments and make it really easy for other people to understand.

    tedbow’s picture

    Status: Needs work » Needs review
    StatusFileSize
    new1.34 KB
    new56.51 KB
    1. That basically implies further reviews of anything aren't valuable once they've been reviewed once, which is clearly not the case. ;) Everyone has different eyes for different things, different perspectives.

      Sorry that wasn't my intention, this issue is wearing me down.

      I would be in favor of a spin-off issue. I personally think it is understandable but I sure it can always been improved.

    2. this patch fixes the test failure
    dww’s picture

    Issue summary: View changes

    @tedbow re: #229:

    this issue is wearing me down.

    I totally relate. Apologies if I've added to that!

    I would be in favor of a spin-off issue.

    Done, and added to summary: #3111463: Improve code documentation for \Drupal\update\ProjectSecurityData

    this patch fixes the test failure

    Oh, interesting! So it wasn't array structure weirdness, just the fact that some tests hit this code such that we don't have any available update data at all. Good to be defensive here and not try to do this requirement check if we have no data, which can happen for all sorts of reasons in the real world.

    All of my (and @xjm's) feedback is addressed. RTBC as soon as the bot is green.

    Thanks!!
    -Derek

    dww’s picture

    Status: Needs review » Reviewed & tested by the community

    Tests are passing.👍
    No CS problems.
    All feedback (and it's been a lot) is addressed. 🙏
    All follow-ups are filed.
    RTBC! 🎉

    Thanks!
    -Derek

    dww’s picture

    Issue summary: View changes
    StatusFileSize
    new58.08 KB
    new4.22 KB

    At risk of confusing things, here's a copy of #229 with #3111463-2: Improve code documentation for \Drupal\update\ProjectSecurityData applied on top. This would totally solve all my concerns about the documentation for ProjectSecurityData::getAdditionalSecurityCoveredMinors(). Interdiff here is identical to 3111463-2.patch.

    If we agree this is an improvement, we can close #3111463 and reduce the number of distinct commits that core maintainers have to cherry pick all over the place for this issue. ;)

    #229 is RTBC, not this (yet).

    I'm hiding this patch from the file table (along with a bunch of stale patches + interdiffs), and added a note at the very top of the issue pointing committers to #229.

    Hope this helps more than it causes trouble...

    Thanks,
    -Derek

    dww’s picture

    Hiding interdiff, too.

    • Gábor Hojtsy committed 87df6a1 on 9.0.x
      Issue #2991207 by tedbow, dww, samuel.mortenson, robpowell, Spokje,...

    • Gábor Hojtsy committed 1f9fb6a on 8.9.x
      Issue #2991207 by tedbow, dww, samuel.mortenson, robpowell, Spokje,...
    gábor hojtsy’s picture

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

    Thanks all for your epic work and deep reviews! I committed #229 to 9.0.x and 8.9.x. It did not cleanly merge into 8.8.x. It also helps to test against that too, so I queued a test for that as well.

    @dww let's discuss followups in their respective issues!

    benjifisher’s picture

    Status: Reviewed & tested by the community » Patch (to be ported)
    Issue tags: +Needs reroll

    The last time I checked (several patches ago) this issue needed an easy reroll to apply to 8.8.x. I think we still want this feature for the 8.8.x branch, so I am setting the status to "Patch to be ported" and adding the tag for a reroll.

    I also un-postponed one of the child issues.

    tedbow’s picture

    🎉🏅🎉🏅🎉🏅🎉🏅🎉🏅🎉🏅🎉🏅🎉🏅
    @Gábor Hojtsy thanks for committing this!

    Thanks everyone for working on this for so long!!!! Especially @benjifisher @dww and @xjm! 🏅🏅🏅🏅🏅🏅🙏🙏🙏🙏🙏🙏🙏🙏

    So this is blocked on backport by #3074993: Use "current" in update URLs instead of CORE_COMPATIBILITY to retrieve all future updates which is block on #3096078: Display core compatibility ranges for available module updates which is blocked on #3102724: Improve usability of core compatibility ranges on available updates report
    It's like we have our Drupal core block⛓ 😜

    dww’s picture

    Yay, very happy to see this in! Huge thanks to @tedbow for putting up with all of us. ;)

    #238 got me worried that we have a really complicated set of issues / patches / commits that need to be backported to 8.8.x in the right order for all this to work. :/ We discussed in Slack, and agreed that the best place to document everything for 8.8.x backporting is at #3076183: [Meta] Determine how available updates for modules should be handled if they are not compatible with the current version of Drupal core. There's now a list in the Remaining tasks of that summary to try to track everything. We'll try to flesh that list out in detail and attempt to keep it accurate as the web of interdependent patches grows. ;)

    dww’s picture

    Status: Patch (to be ported) » Needs review
    Issue tags: -Needs reroll
    StatusFileSize
    new56.42 KB
    new1.36 KB
    new415 bytes

    Meanwhile, here's a reroll for 8.8.x. I suspect this will blow up horribly until the other backports are in, but I figured I'd give it a go.

    Interdiff not available since #229 doesn't apply, so here's a raw diff of the 2 patch files. Also attaching the update.install.rej from patch -p1, which is the only part of #229 that doesn't apply cleanly to the 8.8.x branch right now.

    Status: Needs review » Needs work

    The last submitted patch, 240: 2991207-240.8_8_x.patch, failed testing. View results
    - codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

    dww’s picture

    Title: Drupal core should inform the user of the security coverage for the site's installed minor version including final 8.x LTS releases » [PP-3] Drupal core should inform the user of the security coverage for the site's installed minor version including final 8.x LTS releases
    Issue summary: View changes
    Status: Needs work » Postponed

    Indeed. ;) So yeah, this backport is postponed on at least 3 issues:

    #3074993: Use "current" in update URLs instead of CORE_COMPATIBILITY to retrieve all future updates
    #3096078: Display core compatibility ranges for available module updates
    #3102724: Improve usability of core compatibility ranges on available updates report

    Setting title + status accordingly.
    Added waiting for those as remaining tasks here.
    A few other minor updates to the summary.

    Cheers,
    -Derek

    tedbow’s picture

    Status: Postponed » Needs review
    StatusFileSize
    new27.38 KB
    new73.87 KB

    Although this is blocked on 2 other issues as I mentioned in #238 that is only because

    1. we need \Drupal\update\ModuleVersion that was committed in #3074993: Use "current" in update URLs instead of CORE_COMPATIBILITY to retrieve all future updates. This is used in \Drupal\update\ProjectSecurityData in this patch.
    2. All of the test XML fixtures still need the version_* elements because update_calculate_project_update_status() still uses them. This was changed in 8.9.x in #3074993: Use "current" in update URLs instead of CORE_COMPATIBILITY to retrieve all future updates changes

    Here is reroll plus

    1. git checkout 8.9.x -- core/modules/update/src/ModuleVersion.php
      git checkout 8.9.x -- core/modules/update/tests/src/Unit/ModuleVersionTest.php
      
    2. Adds the version_major etc back to all the test XML

    I would say this issue is more critical to get backported to 8.8.x than #3074993: Use "current" in update URLs instead of CORE_COMPATIBILITY to retrieve all future updates.
    If this issue doesn't get committed before 8.8.3 then we will have another release where users will not be informed about the date at which security coverage ends for 8.8(the minor they are on).
    If #3074993 doesn't get committed before 8.8.3 it will mean they are not informed of contrib new major version updates that use semantic versioning, for example 2.0.0, instead of 8.x-2.0. This seems much less critical for 8.8.x users.

    Both this issue and #3074993 are critical issues but I would say the current issue is the only one that is critical for 8.8.3, maybe for 8.8.x in general. In either case it is more critical than #3074993 as fars backporting to 8.8.x.

    Because we mark releases "insecure" even if #3074993 is not backported a user will not be told they are on secure contrib module version when they are not. If this issue is not backported before 8.8.3 users who stay on 8.8.3 will not be told about security coverage ending for 8.8.3. Though they would be told if 8.8.3 becomes insecure.

    #3074993 is ultimately blocked on #3102724: Improve usability of core compatibility ranges on available updates report which is important to get right but not important enough to stop this issue from getting into 8.8.3 if we can get it in.

    dww’s picture

    Title: [PP-3] Drupal core should inform the user of the security coverage for the site's installed minor version including final 8.x LTS releases » [PP-1] Drupal core should inform the user of the security coverage for the site's installed minor version including final 8.x LTS releases
    Issue summary: View changes
    Status: Needs review » Needs work

    Blockers have nearly all landed in 8.8.x, so this can have a proper / clean re-roll now.

    tedbow’s picture

    Assigned: Unassigned » tedbow

    @dww thanks for keeping track of this. Assigning to myself to do the re-roll

    tedbow’s picture

    Title: [PP-1] Drupal core should inform the user of the security coverage for the site's installed minor version including final 8.x LTS releases » Drupal core should inform the user of the security coverage for the site's installed minor version including final 8.x LTS releases
    Assigned: tedbow » Unassigned
    Status: Needs work » Needs review
    StatusFileSize
    new56.46 KB

    well that was easy. only the use statements in update.install didn't apply cleanly

    rerolled from #229 which is the one @Gábor Hojtsy committed to the other branches in #236

    🤞(though I did run update tests locally 😜)

    tedbow’s picture

    Status: Needs review » Reviewed & tested by the community

    246 was just a reroll

    benjifisher’s picture

    StatusFileSize
    new469 bytes

    Just to be on the safe side, I did several sanity checks:

    1. The patch from #246 applies cleanly to 8.8.x. (OK, the testbot already told us that.)
    2. The only differences between the patches in #229 and #246 are context lines. Diff (not interdiff) attached.
    3. I compared the files changed/added in #246 to the differences between my patched 8.8.x and the HEAD of 8.9.x (which already has the patch from #229). Only two files appear in both lists: tests/src/Functional/UpdateCoreTest.php and update.install. I "manually" compared those files:
    4. I did a quick manual test (hacking Drupal.php to set const VERSION = '8.7.10';). The warning on the status report looks the same (except for the version numbers) as the screenshot in this issue for "Minor 8.1 is supported, warning. Next minor 8.2 has come out".

    +1 for RTBC.

    I also checked that the latest patch (RTBC) on #3110186: Simplify the wording of messages on the status report about security coverage for the site's installed minor version applies cleanly on top of this one.

    gábor hojtsy’s picture

    Status: Reviewed & tested by the community » Needs work

    Thanks for working this issue out so thoroughly. Reviewing the patch I only noticed a few smaller problems.

    1. +++ b/core/modules/update/src/ProjectSecuri11tyData.php
      @@ -0,0 +1,211 @@
      +final class ProjectSecurityData {
      ...
      +   *    what the final minor release of a particular major version will be. This
      
      +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      @@ -0,0 +1,291 @@
      +final class ProjectSecurityRequirement {
      

      Other than surrounding code comments, there is nothing indicating these are core specific. Ie. nothing in the class namespace or hierarchy or the name of the class. It would be better IMHO to make it explicit in the class naming.

      Unless there is an intention to change the scope of the classes in the future.

    2. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,211 @@
      +  /**
      +   * Define constants for versions with security coverage end dates.
      +   *
      +   * Two types of constants are supported:
      +   * - SECURITY_COVERAGE_END_DATE_[VERSION_MAJOR]_[VERSION_MINOR]: A date in
      +   *   'Y-m-d' or 'Y-m' format.
      +   * - SECURITY_COVERAGE_ENDING_WARN_DATE_[VERSION_MAJOR]_[VERSION_MINOR]: A
      +   *   date in 'Y-m-d' format.
      +   *
      +   * @see \Drupal\update\ProjectSecurityRequirement::getDateEndRequirement()
      +   */
      +  const SECURITY_COVERAGE_END_DATE_8_8 = '2020-12-02';
      +
      +  const SECURITY_COVERAGE_ENDING_WARN_DATE_8_8 = '2020-06-02';
      +
      +  const SECURITY_COVERAGE_END_DATE_8_9 = '2021-11';
      

      It would be standard to document the constants one by one instead of one block that only applies to one constant but logically documents the other two. I understand the nuances of this pattern being explained rather than the specific constant, and also this being a final class, I can live with this.

    3. +++ b/core/modules/update/src/ProjectSecurityData.php
      @@ -0,0 +1,211 @@
      +   * @todo In https://www.drupal.org/node/2608062 determine how we will know
      

      *waves with hand* This is not the issue you are looking for. (This is the Drupal 9 alpha1 requirements issue, you did not mean that right?)

    4. +++ b/core/modules/update/src/ProjectSecurityRequirement.php
      @@ -0,0 +1,291 @@
      +      if ($this->securityCoverageInfo['additional_minors_coverage'] === 1) {
      +        // If the installed minor version will only receive security coverage
      +        // for 1 newer minor core version, encourage the site owner to update
      +        // soon.
      +        $message .= '<p>' . $this->t('Update to @next_minor or higher soon to continue receiving security updates.', ['@next_minor' => $this->nextMajorMinorVersion])
      +          . ' ' . static::getAvailableUpdatesMessage() . '</p>';
      +      }
      

      If there is only one newer why do we say "or higher"? We know there is not a higher one than the next minor, no?

    benjifisher’s picture

    If we do make any changes here, then we will have to make the corresponding changes on the 8.9.x and 9.0.x branches as well. In my opinion, only the third point needs to be addressed.

    1. Unless there is an intention to change the scope of the classes in the future.

      Yes, that is the intention.

    2. I can live with this.

      Maybe I should just leave it at that. If we were to document the variables separately, then we would need substantially the same comment for SECURITY_COVERAGE_END_DATE_8_8 and SECURITY_COVERAGE_END_DATE_8_9. Also, the intention is to remove these constants after #2998285: Add information on later releases to updates.drupal.org and #3107378: Deprecate hard-coded Drupal 8 dates from update logic for the status report once this information is provided by the infrastructure.

    3.   +   * @todo In https://www.drupal.org/node/2608062 determine how we will know
        +   *    what the final minor release of a particular major version will be. This
        +   *    method should not return a version beyond that minor.

      Good point. This is not the issue we are looking for. Maybe this should be #2998285: Add information on later releases to updates.drupal.org.

    4. I think that "or higher" could include the next major release. For example, in a few months sites running on 8.8.x will get the message "Upgrade to 8.9 or higher …" meaning 8.9 or 9.0 (or 9.1). Do you think that "@next_minor or @next_major.x" or something would be clearer?

    (edited)

    dww’s picture

    Status: Needs work » Reviewed & tested by the community

    @Gábor Hojtsy: I'm really confused by #249. At 234 and 235, you committed exactly all this code to 9.0.x and 8.9.x branches. Now you're blocking a backport to 8.8.x branch. Seems really weird scope creep to only fix these in 8.8.x. As you said in #236:

    @dww let's discuss followups in their respective issues!

    If you want to further tweak this API or the code comments, let's do it in a follow-up. ;)

    249.1: It doesn't have to be core specific. Contrib projects could have something similar. See #165.5 and 7, and reply in #168.

    249.2: We can all live with it. ;)

    249.3: Well, #2608062: [META] Requirements for tagging Drupal 9.0.0-alpha1 had a discussion about release dates and such, which is I think why the comment pointed there originally. But yeah, that's probably not the best place to point. #NeedsFollowup, right? Then we can fix it in all the branches with a single commit that's easily cherry-picked.

    249.4: @benjifisher in #250 answers this well. This text was extensively debated and refined via UX team meetings, Slack, and here. Let's not change it in the middle of the 8.8.x backport.

    dww’s picture

    Opened #3117188: Change @todo comment in core/modules/update/src/ProjectSecurityData.php to point to a better issue for #249.3

    Please, let's get this into 8.8.x as it is in the other branches.

    Thanks!
    -Derek

    • Gábor Hojtsy committed 9f825f2 on 8.8.x
      Issue #2991207 by tedbow, dww, samuel.mortenson, robpowell, Spokje,...
    gábor hojtsy’s picture

    Status: Reviewed & tested by the community » Fixed

    Uhoh. The more I look at a patch the more problems I'll find ;) You may know the feeling. Did not intend to derail this and none of my feedback was earth shattering. Thanks for opening the followup that we can commit and merge back all the way :)

    xjm’s picture

    Issue tags: +8.8.3 release notes

    Since this is a more disruptive change than we would normally backport (new status report message) we should mention it in the release notes.

    xjm’s picture

    Issue summary: View changes

    Adding the release note.

    dww’s picture

    Issue summary: View changes

    @Gábor Hojtsy Re: #254: Yes, I definitely relate. ;) Thanks for committing this as-is and doing the additional cleanups elsewhere.

    @xjm re: #256: Thanks for the release note. Minor fix:

    s/December 2rd/December 2/

    a) If we wanted an English-specific suffix, it should be "2nd", not "2rd".
    b) These suffixes only make sense in English, and it's probably better to leave them off entirely.

    Status: Fixed » Closed (fixed)

    Automatically closed - issue fixed for 2 weeks with no activity.