Problem/Motivation

Git deploy has 2 roles with upgrade status:

1. It supplies crucial data to categorize projects as contrib and custom.
2. It supplies crucial data to identify versions of contributed projects and thus suggest available updates.

Other than these Upgrade Status does not need or rely on Git Deploy. So one could run upgrade status if we remove the requirement and maybe (some of) their contributed projects would show up as custom but no other harm would be done.

Unfortunately git deploy is causing various problems to users, see #3123286: Fix endless loop when multiple remote branches share base with HEAD where various people reported multiple types of problems.

Proposed resolution

Explore the option to remove this requirement and make it a suggestion instead.

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Gábor Hojtsy created an issue. See original summary.

Gábor Hojtsy’s picture

Title: Consider removing git deploy as a requirement » Consider removing git deploy as a requirement from upgrade status
FileSize
4.13 KB

Status: Needs review » Needs work

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

Gábor Hojtsy’s picture

Status: Needs work » Needs review
FileSize
4.81 KB

We can (probably should) put more heuristics into upgrade_status, eg. about “modules/contrib” and “modules/custom” to soften the negative effects of not having git_deploy anymore for categorization. This was raised in #3122298: Incorrect category for modules too.

Fixing the fail for now.

Gábor Hojtsy’s picture

Title: Consider removing git deploy as a requirement from upgrade status » Remove git deploy as a requirement from upgrade status
FileSize
8.6 KB

@fgm made some good points on slack, and pointed me to https://www.drupal.org/project/composer_deploy which would actually be a better fit for composer sites. So adding that as a primary recommendation to the readme and to the help text. I am even more convinced that this should be done.

Adding a bit of code to identify contrib projects in */contrib/* as contrib. While this is not a mandatory structure, many sites use it, so it works as a best effort fallback. We don't really have other indication as to whether something is contrib or core. Given this modification, we also need collation happen for contributed extensions, and assume a project name for them if they did not have one.

I *think* this is functionally complete.

Gábor Hojtsy credited fgm.

Gábor Hojtsy’s picture

Status: Needs review » Needs work

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

Gábor Hojtsy’s picture

Status: Needs work » Needs review
FileSize
8.65 KB

One case forgotten :D

Status: Needs review » Needs work

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

Gábor Hojtsy’s picture

Status: Needs work » Needs review
FileSize
10.01 KB

Ok understandbly the module now categorizes all test modules under the main project. That is a case of "why/how did it not work like that before".

So skipping "upgrade_status_test_*" modules from our category magic. (Since the category magic depends on path info outside of the control of the test). Also specifying unique projects for the test "projects" under the module.

Status: Needs review » Needs work

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

Gábor Hojtsy’s picture

Status: Needs work » Needs review
FileSize
10.23 KB

We should also skip the collation.

Status: Needs review » Needs work

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

Gábor Hojtsy’s picture

Status: Needs work » Needs review
FileSize
10.49 KB

Ok got my haystacks and needles wrong with strpos() and also matched the shorter module names instead of longer ones in the collate method. Fixing those two seems to work fine at least for the test scenarios without git_deploy.

Gábor Hojtsy’s picture

Status: Needs review » Reviewed & tested by the community

As far as I see that is good. Unless I get complaints will commit tomorrow :)

fgm’s picture

Status: Reviewed & tested by the community » Needs work
FileSize
39.37 KB

Upgrade status now works, and recognizes mongodb as a contrib, but four small things:

  • There's a git whitespace warning when applying the patch
  • Running the check displays a warning as attached
  • Not sure if it's expected or not but, although the version is above 8.x-2.0 for both git_deploy and mongodb, it suggests an update to the older 8.x-2.0 version
  • After analyzing (not on initial display), it discovers project submodules and lists them as projects too

Patch:

LANG=C git apply 3129903-15.patch
3129903-15.patch:32: trailing whitespace.
Composer Deploy (https://www.drupal.org/project/composer_deploy) or
3129903-15.patch:70: trailing whitespace.
      // and theoretically this could lead to false positives, but if
warning: 2 lines add whitespace errors.
fgm’s picture

Status: Needs work » Needs review
FileSize
17.13 KB

Rerolled to fix this issue and a few related others, plus DCS warnings on the modified file.

Note that, although this is likely unrelated, the drush commands fail like:

../vendor/bin/drush us-a upgrade_status
 [notice] Processing /Users/fgm/src/Drupal/d8/project/web/modules/contrib/upgrade_status.
PHP Warning:  include(/Users/fgm/src/Drupal/d8/project/web/vendor/autoload.php): failed to open stream: No such file or directory in /Users/fgm/src/Drupal/d8/project/vendor/mglaman/phpstan-drupal/src/Drupal/DrupalAutoloader.php on line 78
Warning: include(/Users/fgm/src/Drupal/d8/project/web/vendor/autoload.php): failed to open stream: No such file or directory in /Users/fgm/src/Drupal/d8/project/vendor/mglaman/phpstan-drupal/src/Drupal/DrupalAutoloader.php on line 78
PHP Warning:  include(): Failed opening '/Users/fgm/src/Drupal/d8/project/web/vendor/autoload.php' for inclusion (include_path='/Users/fgm/src/Drupal/d8/project/vendor/pear/archive_tar:/Users/fgm/src/Drupal/d8/project/vendor/pear/console_getopt:/Users/fgm/src/Drupal/d8/project/vendor/pear/pear-core-minimal/src:/Users/fgm/src/Drupal/d8/project/vendor/pear/pear_exception:/Users/fgm/src/Drupal/d8/project/vendor/pear/archive_tar:/Users/fgm/src/Drupal/d8/project/vendor/pear/console_getopt:/Users/fgm/src/Drupal/d8/project/vendor/pear/pear-core-minimal/src:/Users/fgm/src/Drupal/d8/project/vendor/pear/pear_exception:.:/usr/local/Cellar/php@7.3/7.3.17/share/php@7.3/pear') in /Users/fgm/src/Drupal/d8/project/vendor/mglaman/phpstan-drupal/src/Drupal/DrupalAutoloader.php on line 78
Warning: include(): Failed opening '/Users/fgm/src/Drupal/d8/project/web/vendor/autoload.php' for inclusion (include_path='/Users/fgm/src/Drupal/d8/project/vendor/pear/archive_tar:/Users/fgm/src/Drupal/d8/project/vendor/pear/console_getopt:/Users/fgm/src/Drupal/d8/project/vendor/pear/pear-core-minimal/src:/Users/fgm/src/Drupal/d8/project/vendor/pear/pear_exception:/Users/fgm/src/Drupal/d8/project/vendor/pear/archive_tar:/Users/fgm/src/Drupal/d8/project/vendor/pear/console_getopt:/Users/fgm/src/Drupal/d8/project/vendor/pear/pear-core-minimal/src:/Users/fgm/src/Drupal/d8/project/vendor/pear/pear_exception:.:/usr/local/Cellar/php@7.3/7.3.17/share/php@7.3/pear') in /Users/fgm/src/Drupal/d8/project/vendor/mglaman/phpstan-drupal/src/Drupal/DrupalAutoloader.php on line 78
PHP Fatal error:  Uncaught Error: Call to a member function addPsr4() on bool in /Users/fgm/src/Drupal/d8/project/vendor/mglaman/phpstan-drupal/src/Drupal/DrupalAutoloader.php:280
Stack trace:
#0 /Users/fgm/src/Drupal/d8/project/vendor/mglaman/phpstan-drupal/src/Drupal/DrupalAutoloader.php(101): PHPStan\Drupal\DrupalAutoloader->registerPs4Namespaces(Array)
#1 /Users/fgm/src/Drupal/d8/project/vendor/mglaman/phpstan-drupal/drupal-autoloader.php(16): PHPStan\Drupal\DrupalAutoloader->register(Object(PHPStan\DependencyInjection\MemoizingContainer))
#2 phar:///Users/fgm/src/Drupal/d8/project/vendor/phpstan/phpstan/phpstan/src/Command/CommandHelper.php(238): require_once('/Users/fgm/src/...')
#3 phar:///Users/fgm/src/Drupal/d8/project/vendor/phpstan/phpstan/phpstan/src/Command/CommandHelper.php(239): PHPStan\Command\CommandHelper::PHPStan\Command\{closure}('/Users/fgm/src/...')
#4 phar:///Users/fgm/src/Drupal/d8/project/vendor/phpstan/phpstan/phpstan/src/Command/AnalyseCommand.php(77): PHPStan\Command\CommandHelper::begin(Object(_Hum in /Users/fgm/src/Drupal/d8/project/vendor/mglaman/phpstan-drupal/src/Drupal/DrupalAutoloader.php on line 280
Fatal error: Uncaught Error: Call to a member function addPsr4() on bool in /Users/fgm/src/Drupal/d8/project/vendor/mglaman/phpstan-drupal/src/Drupal/DrupalAutoloader.php:280
Stack trace:
#0 /Users/fgm/src/Drupal/d8/project/vendor/mglaman/phpstan-drupal/src/Drupal/DrupalAutoloader.php(101): PHPStan\Drupal\DrupalAutoloader->registerPs4Namespaces(Array)
#1 /Users/fgm/src/Drupal/d8/project/vendor/mglaman/phpstan-drupal/drupal-autoloader.php(16): PHPStan\Drupal\DrupalAutoloader->register(Object(PHPStan\DependencyInjection\MemoizingContainer))
#2 phar:///Users/fgm/src/Drupal/d8/project/vendor/phpstan/phpstan/phpstan/src/Command/CommandHelper.php(238): require_once('/Users/fgm/src/...')
#3 phar:///Users/fgm/src/Drupal/d8/project/vendor/phpstan/phpstan/phpstan/src/Command/CommandHelper.php(239): PHPStan\Command\CommandHelper::PHPStan\Command\{closure}('/Users/fgm/src/...')
#4 phar:///Users/fgm/src/Drupal/d8/project/vendor/phpstan/phpstan/phpstan/src/Command/AnalyseCommand.php(77): PHPStan\Command\CommandHelper::begin(Object(_Hum in /Users/fgm/src/Drupal/d8/project/vendor/mglaman/phpstan-drupal/src/Drupal/DrupalAutoloader.php on line 280
 [warning] The following theme is missing from the file system: upgrade_status_test_library bootstrap.inc:295
 [warning] The following theme is missing from the file system: upgrade_status_test_twig bootstrap.inc:295

But in spite of that, the results still display, showing that upgrade_status is not D9-ready at this point:

================================================================================
Upgrade Status, --
Scanned on Thu, 04/23/2020 - 08:49

FILE:
web/modules/contrib/upgrade_status/tests/modules/upgrade_status_test_twig/templa
tes/test.html.twig

STATUS         LINE                           MESSAGE
--------------------------------------------------------------------------------
Check manually 3    Twig Tag "raw" is deprecated since version 1.21. Use
                    "verbatim" instead. See https://drupal.org/node/3071078.
--------------------------------------------------------------------------------

FILE:
web/modules/contrib/upgrade_status/tests/themes/upgrade_status_test_theme/templa
tes/test.html.twig

STATUS         LINE                           MESSAGE
--------------------------------------------------------------------------------
Check manually 1    Twig Tag "raw" is deprecated since version 1.21. Use
                    "verbatim" instead. See https://drupal.org/node/3071078.
--------------------------------------------------------------------------------

FILE: web/modules/contrib/upgrade_status/upgrade_status.info.yml

STATUS         LINE                           MESSAGE
--------------------------------------------------------------------------------
Check manually 0    Add <code>core_version_requirement: ^8 || ^9</code> to
                    upgrade_status.info.yml to designate that the module is
                    compatible with Drupal 9. See
                    https://drupal.org/node/3070687.
--------------------------------------------------------------------------------

FILE: web/modules/contrib/upgrade_status/composer.json

STATUS         LINE                           MESSAGE
--------------------------------------------------------------------------------
Check manually 0    The drupal/core requirement is not Drupal 9 compatible.
                    Either remove it or update it to be compatible with Drupal
                    9. See
                    https://drupal.org/node/2514612#s-drupal-9-compatibility.
--------------------------------------------------------------------------------
Gábor Hojtsy’s picture

Status: Needs review » Needs work
  1. +++ b/src/DeprecationAnalyzer.php
    @@ -3,6 +3,7 @@
    +use Drupal\Component\Datetime\TimeInterface;
    
    @@ -91,6 +95,13 @@ final class DeprecationAnalyzer {
    +  /**
    +   * The time service.
    +   *
    +   * @var \Drupal\Component\Datetime\TimeInterface
    +   */
    +  protected $time;
    +
    
    @@ -104,10 +115,12 @@ final class DeprecationAnalyzer {
    -   * @param \Drupal\upgrade_status\LibraryDeprecationAnalyzer
    +   * @param \Drupal\upgrade_status\LibraryDeprecationAnalyzer $library_deprecation_analyzer
        *   The library deprecation analyzer.
    -   * @param \Drupal\upgrade_status\ThemeFunctionDeprecationAnalyzer
    +   * @param \Drupal\upgrade_status\ThemeFunctionDeprecationAnalyzer $theme_function_deprecation_analyzer
        *   The theme function deprecation analyzer.
    +   * @param \Drupal\Component\Datetime\TimeInterface $time
    +   *   The time service.
    
    @@ -116,7 +129,8 @@ final class DeprecationAnalyzer {
    -    ThemeFunctionDeprecationAnalyzer $theme_function_deprecation_analyzer
    +    ThemeFunctionDeprecationAnalyzer $theme_function_deprecation_analyzer,
    +    TimeInterface $time
    
    @@ -126,7 +140,7 @@ final class DeprecationAnalyzer {
    -
    +    $this->time = $time;
    
    @@ -160,11 +174,12 @@ final class DeprecationAnalyzer {
    +   * Errors are logged to the logger, data is stored to keyvalue storage.
    +   *
    ...
    -   * @return null
    -   *   Errors are logged to the logger, data is stored to keyvalue storage.
    +   * @throws \Exception
    
    @@ -172,8 +187,11 @@ final class DeprecationAnalyzer {
    -    $json = json_decode(join('', $output), TRUE);
    -    $result = ['date' => REQUEST_TIME, 'data' => $json];
    +    $json = json_decode(implode('', $output), TRUE);
    +    $result = [
    +      'date' => $this->time->getRequestTime(),
    +      'data' => $json ?? ['files' => [], 'totals' => ['file_errors' => 0]],
    +    ];
    
    @@ -231,7 +249,8 @@ final class DeprecationAnalyzer {
    -    } catch (InvalidDataTypeException $e) {
    +    }
    +    catch (InvalidDataTypeException $e) {
           $result['data']['files'][$extension->getPathname()]['messages'][] = [
             'message' => 'Parse error. ' . $e->getMessage(),
             'line' => 0,
    @@ -261,9 +280,9 @@ final class DeprecationAnalyzer {
    
    @@ -261,9 +280,9 @@ final class DeprecationAnalyzer {
           }
         }
     
    -    foreach($result['data']['files'] as $path => &$errors) {
    +    foreach ($result['data']['files'] as &$errors) {
           if (!empty($errors['messages'])) {
    -        foreach($errors['messages'] as &$error) {
    +        foreach ($errors['messages'] as &$error) {
     
               // Overwrite message with processed text. Save category.
               [$message, $category] = $this->categorizeMessage($error['message'], $extension);
    @@ -307,13 +326,15 @@ final class DeprecationAnalyzer {
    
    @@ -307,13 +326,15 @@ final class DeprecationAnalyzer {
       /**
        * Analyzes twig templates for calls of deprecated code.
        *
    -   * @param $directory
    +   * @param string $directory
        *   The directory which Twig templates should be analyzed.
        *
        * @return array
    +   *   An array of deprecations.
        */
       protected function analyzeTwigTemplates($directory) {
    -    return (new \Twig_Util_DeprecationCollector($this->twigEnvironment))->collectDir($directory, '.html.twig');
    +    return (new \Twig_Util_DeprecationCollector($this->twigEnvironment))
    +      ->collectDir($directory, '.html.twig');
    
    +++ b/upgrade_status.services.yml
    @@ -1,7 +1,16 @@
    -    arguments: ['@keyvalue', '@logger.channel.upgrade_status', '@http_client', '@file_system', '@twig', '@upgrade_status.library_deprecation_analyzer', '@upgrade_status.theme_function_deprecation_analyzer']
    +    arguments:
    +      - '@keyvalue'
    +      - '@logger.channel.upgrade_status'
    +      - '@http_client'
    +      - '@file_system'
    +      - '@twig'
    +      - '@upgrade_status.library_deprecation_analyzer'
    +      - '@upgrade_status.theme_function_deprecation_analyzer'
    +      - '@datetime.time'
    +
    

    Can we try to not couple everything all at once to one patch? This makes problems much harder to individually track down :/ Almost half the patch is now unrelated things. I would much rather deal with your concern about After analyzing (not on initial display), it discovers project submodules and lists them as projects too which IS a problem that this patch may be introducing and we need to fix.

  2. +++ b/src/ProjectCollector.php
    @@ -106,41 +106,69 @@ class ProjectCollector {
    +      // structure it is in. Extension placement is not a mandatory requirement
    +      // and theoretically this could lead to false positives, but if ¶
    +      // composer_deploy or git_deploy is not available (and/or did not
    

    The end of line whitespace here remained somehow :D

Gábor Hojtsy’s picture

REQUEST_TIME is not even deprecated for Drupal 9, it is deprecated for Drupal 10 currently: https://api.drupal.org/api/drupal/core%21includes%21bootstrap.inc/consta...

fgm’s picture

Not sure about the implications of your last comment: REQUEST_TIME is deprecated since Drupal 8.3 (but removed in Drupal 10), so I figured it would be better to remove it in all code since 8.3 : that's what I did elsewhere. Is this wrong ?

Beyond that deprecation and the PHPCS issues the only actual change I added to your patch is to address the warning about unchecked access to nonexistent data. I did not touch the discovery itself. Do you want me to only include the unchecked access, without the request time and phpcs fixes ?

Gábor Hojtsy’s picture

I am happy to commit the request time and the phpcs fixes in a different patch but not here. We still need to resolve the bug you found here and we should not complicate it with a bunch of unrelated things. Who knows who else will be involved in fixing it, let's keep it streamlined to that IMHO. Thanks!

Gábor Hojtsy’s picture

I reviewed your patch once again and I assume the "unchecked access to nonexistent data". I think this is it:

-    $json = json_decode(join('', $output), TRUE);
-    $result = ['date' => REQUEST_TIME, 'data' => $json];
+    $json = json_decode(implode('', $output), TRUE);
+    $result = [
+      'date' => $this->time->getRequestTime(),
+      'data' => $json ?? ['files' => [], 'totals' => ['file_errors' => 0]],
+    ];

Would that not be in the realms of #3129430: When phpstan is not found, the error is too subtle, does not support custom binary path? We would need to report the error itself because in this case apparently the output from phpstan was not parse-able. Also this does not seem to be related to removing git_deploy either.

The one thing you reported that I am concerned about is this:

After analyzing (not on initial display), it discovers project submodules and lists them as projects too

fgm’s picture

Yes, this is the bit I was referring to. But - without debugging it - I don't think it is related to not finding phpstan because errors were reported when there still were some, so I assume it was found.

Regarding the submodules, what is the expected behavior ? Should they be listed from the first GET to the page ? Or not be listed separately even after the scan ?

Gábor Hojtsy’s picture

For both contrib and custom projects, submodules should be grouped under the topmost extension, see

    // Collate custom extensions to projects, removing sub-extensions.
    $projects['custom'] = $this->collateExtensionsIntoProjects($projects['custom']);

    // Also collate contrib extensions. This is only needed if there were
    // contrib extensions with projects not identified, and they had
    // sub-extensions. After the collation is done, assign project names
    // based on the topmost extension. While this is not always right for
    // drupal.org projects, this is the best guess we have.
    $projects['contrib'] = $this->collateExtensionsIntoProjects($projects['contrib']);
    foreach ($projects['contrib'] as $name => $extension) {
      if (!isset($extension->info['project'])) {
        $projects['contrib'][$name]->info['project'] = $name;
      }
    }

in the patched code. I think we only ever use our own ProjectCollector to list projects, so I am very surprised they would be different before/after scan. Scanning should not change their project metadata which is the only thing outside ProjectCollector that would change how they are categorized.

fgm’s picture

Status: Needs work » Needs review
FileSize
11.28 KB
738 bytes

Probably good news: I did a reinstall with the latest 8.9.x, phpstan, upgrade_status and mongodb modules, and could not reproduce the issue. And I didn't even get the error. So I guess you don't need to dig further on that part.

However, the errors on the Drush command are still there:

  • without a web/vendor symlink (only vendor/, no web/vendor), drush fails opening web/vendor/autoload.php
  • with the web/vendor symlink added, I get "too many open files" preventing including autoload.php
  • the working combination is to:
    1. mkdir web/vendor
    2. cd web/vendor
    3. ln -s ../../vendor/autoload
    4. cd ../..
    5. drush us-a (modules to check)

Since other Drush commands not related to phpstan/upgrade_status/drupal-check work normally, this does not seem to be related to the git_deploy removal, but to be the same problem already discovered with drupal-check, so I think it does not belong in this issue.

Now, regarding the json part of my suggested patch, I would still apply it because I like to cover my bases, but that's really your choice. I've attached is the reduced version only containing that bit.

In the web UI (but not with drush us-a or drush us-cs), I still get spurious detection bugs due to the scan not being able to access the class in the mongodb library (a dependency installed in vendor/), but these were already present with git_deploy, so it is an other issue.

I also checked these non-autoloaded classes in the popin with the scan results in ScanResultFormatter::formatResult() and here they can be found normally, so it's really unrelated and will need to be addressed in a lower layer, during the scan phase.

  • Gábor Hojtsy committed 539c78a on 8.x-2.x
    Issue #3129903 by Gábor Hojtsy, fgm: Remove git deploy as a requirement...
Gábor Hojtsy’s picture

Status: Needs review » Fixed

Great, thank you! I fixed the two one line whitespace problems on commit.

I did not commit the json hardening, but suggested @ndeet that it be taken forward in #3129430: When phpstan is not found, the error is too subtle, does not support custom binary path. I'll try to make sure it is included there. (If you are interested you can join there and help but no obligations :)

Thanks for all your help here!

Gábor Hojtsy’s picture

Extracted the REQUEST_TIME related parts to #3131176: Remove use of deprecated REQUEST_TIME and added one more use of it to fix there.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.