wunderio / code-quality

List of tools that aims to help with static code quality inspection.
GNU General Public License v3.0
2 stars 5 forks source link

#62 Add Psalm support. #66

Closed hkirsman closed 2 years ago

hkirsman commented 3 years ago

You can try this out on Drupal 9 project:

composer require wunderio/code-quality:dev-feature/62-add-psalm-task --dev

or in Lando prefix with lando. Psalm requires PHP's mbstring and in my experience I was missing it locally but Lando had it.

lando composer require wunderio/code-quality:dev-feature/62-add-psalm-task --dev

Lock files can be tricky and every project is different. On my 9.2.6 installation I did this:

lando composer require wunderio/code-quality:dev-feature/62-add-psalm-task composer/xdebug-handler:1.4.6 composer/composer:2.0.2  --dev
  1. Check that first line in grumphp.yml is grumphp: and not parameters:

image

  1. In Grumphp add psalm task and extension lines ("psalm: ~" under "tasks:" and "- Wunderio\GrumPHP\Task\Psalm\PsalmExtensionLoader" under "extensions:")

image

  1. Copy the psalm.xml config to project root

    cp vendor/wunderio/code-quality/config/psalm.xml ./psalm.xml

  2. You might see issues with tests not finding dependencies. ERROR: MissingDependency - web/modules/custom/redirect_old_tua/tests/src/HomePageTest.php:13:28 - Drupal\Tests\BrowserTestBase depends on class or interface phpunit\framework\testcase that does not exist (see https://psalm.dev/157) class HomePageTest extends BrowserTestBase {

For that install testing Drupals testing support:

composer require drupal/core-dev:X.X.X --dev
  1. As I don't have php locally I'm also using Landos php with this grumphp config:

    grumphp: git_hook_variables: EXEC_GRUMPHP_COMMAND: 'lando php'

and re-init grumphp

lando grumphp git:init

Where X.X.X is your current core version.

hkirsman commented 3 years ago

Seems as if we also need https://github.com/fenetikm/autoload-drupal because otherwise it complains missing classes although they are there (and dev-master because it supports Composer 2). I've added this with last commit.

image

In composer.json under extras add

    "autoload-drupal": {
        "modules": [
            "web/modules/custom/",
            "web/modules/contrib/",
            "web/core/modules/"
        ],
        "classmap": [
            "web/core/tests/Drupal/Tests"
        ]
    }

Run

lando composer dump-autoload 

And finally try to commit code or run

lando grumphp run
hkirsman commented 3 years ago

Could also be we need to test https://github.com/mortenson/psalm-plugin-drupal

hkirsman commented 3 years ago

https://github.com/fenetikm/autoload-drupal seems to be quite good but doesn't seem to load .module files so I'm seeing undefined constant error with my code.

This one says it solves the .module and .theme loading https://github.com/mortenson/psalm-plugin-drupal

hkirsman commented 3 years ago

For temporary fix it seems I'd need to create file something like autoload-extras-for-psalm.php

<?php

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
$projectRoot = realpath($baseDir . '/..');

// @todo: find all .module and .theme files and require here.
require_once $projectRoot . '/web/modules/contrib/adobe_captivate/adobe_captivate.module';

In psalm.xml add autoloader parameter:

<psalm
    errorLevel="6"
    resolveFromConfigFile="true"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="https://getpsalm.org/schema/config"
    xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
    autoloader="vendor/wunderio/code-quality/autoload-extras-for-psalm.php"
>
hkirsman commented 3 years ago

Hm, can't get this to work.

One more thing. We already have mglaman/phpstan-drupal installed and this seems promising: https://github.com/mglaman/phpstan-drupal/blob/main/drupal-autoloader.php

hkirsman commented 3 years ago

I've taken the https://github.com/mglaman/phpstan-drupal/blob/main/drupal-autoloader.php and refactored it a bit. To me it seems to work nicely.

hkirsman commented 3 years ago

Should be ok now for testing. See initial comment.

hkirsman commented 2 years ago

I'm getting

ERROR: UndefinedInterfaceMethod - web/modules/custom/tekla_apireference/src/Form/APIReferenceDocumentRevisionRevertTranslationForm.php:101:54 - Method Drupal\Core\Entity\EntityInterface::getTranslation does not exist (see https://psalm.dev/181)
    $latest_revision_translation = $latest_revision->getTranslation($this->langcode);

This is the code:

    $latest_revision = $this->apiReferenceDocumentStorage->load($revision->id());
    $latest_revision_translation = $latest_revision->getTranslation($this->langcode);

I don't see it's actually a valid error. PhpStorm find the interface and if I try to add it then PhpStorm also yells that I can't add it again.

So I'll disable this error:

    <issueHandlers>
      <UndefinedInterfaceMethod errorLevel="suppress" />
    </issueHandlers>
hkirsman commented 2 years ago

Another one:

ERROR: ImplicitToStringCast - web/modules/custom/tekla_apireference/src/Form/APIReferenceDocumentImportForm.php:137:58 - Argument 2 of Drupal\Core\Form\FormStateInterface::setErrorByName expects string, Drupal\Core\StringTranslation\TranslatableMarkup provided with a __toString method (see https://psalm.dev/060)
      $form_state->setErrorByName('source_package_file', t('Import could not continue because directory %directory could not be created for extraction.', [
        '%directory' => $extract_path,
      ]));

But we're not going to do something like t('Foobar')->____toString(). That would output string but with the placeholders. I'll create ignore for that specific error.

All in all I'm adding these ignores to config:

    <issueHandlers>
      <UndefinedInterfaceMethod errorLevel="suppress" />
      <ImplicitToStringCast errorLevel="suppress" />
    </issueHandlers>