{"id":3402,"date":"2023-09-22T21:09:00","date_gmt":"2023-09-22T19:09:00","guid":{"rendered":"https:\/\/www.h-hennes.fr\/blog\/?p=3402"},"modified":"2023-09-22T21:09:03","modified_gmt":"2023-09-22T19:09:03","slug":"prestashop-deploiement-continu-verifier-la-qualite-du-code","status":"publish","type":"post","link":"https:\/\/www.h-hennes.fr\/blog\/2023\/09\/22\/prestashop-deploiement-continu-verifier-la-qualite-du-code\/","title":{"rendered":"Prestashop : D\u00e9ploiement continu, v\u00e9rifier la qualit\u00e9 du code"},"content":{"rendered":"\n<p>Cet article est le 3\u00e8me de la s\u00e9rie sur le d\u00e9ploiement et l\u2019int\u00e9gration continu dans Prestashop.<br \/>Les autres articles de cette s\u00e9rie sont les suivants :<\/p>\n\n\n\n<ul>\n<li><a title=\"Prestashop : Aller plus loin dans le d\u00e9ploiement continu\" href=\"https:\/\/www.h-hennes.fr\/blog\/2023\/09\/11\/prestashop-aller-plus-loin-dans-le-deploiement-continu\/\">Introduction<\/a><\/li>\n<li><a href=\"https:\/\/www.h-hennes.fr\/blog\/2023\/09\/16\/prestashop-deploiement-continu-initialisation-du-projet\/\">Initialisation du projet<\/a><\/li>\n<li><a title=\"Prestashop : D\u00e9ploiement continu, qui peut livrer du code et ou\" href=\"https:\/\/www.h-hennes.fr\/blog\/2023\/09\/18\/prestashop-deploiement-continu-qui-peut-livrer-du-code-et-ou\/\">Qui peut livrer du code et ou<\/a><\/li>\n<li><a title=\"Prestashop : D\u00e9ploiement continu, v\u00e9rifier la qualit\u00e9 du code\" href=\"https:\/\/www.h-hennes.fr\/blog\/2023\/09\/22\/prestashop-deploiement-continu-verifier-la-qualite-du-code\/\">Est-ce que la qualit\u00e9 du code livr\u00e9e est correcte<\/a><\/li>\n<li><a title=\"Prestashop : Comment limiter les interactions manuelles avec le d\u00e9ploiement continu\" href=\"https:\/\/www.h-hennes.fr\/blog\/2023\/11\/06\/prestashop-comment-limiter-les-interactions-manuelles-avec-le-deploiement-continu\/\">Comment limiter les interactions manuelles<\/a><\/li>\n<li><a title=\"Prestashop : Est-ce que mon site fonctionne toujours apr\u00e8s ma livraison de code.\" href=\"https:\/\/www.h-hennes.fr\/blog\/2023\/11\/08\/prestashop-est-ce-que-mon-site-fonctionne-toujours-apres-ma-livraison-de-code\/\">Est-ce que mon site fonctionne toujours apr\u00e8s ma livraison de code.<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">\u00c9tat des lieux<\/h2>\n\n\n\n<p>En pr\u00e9alable de cette \u00e9tape nous allons ajouter un nouveau module prestashop de mauvaise qualit\u00e9 et avec une erreur de syntaxe php.<br \/>C&rsquo;est volontairement ce qu&rsquo;il ne faut pas faire \ud83d\ude42<br \/><br \/>Pour faire \u00e7a simplement vous pouvez utiliser l&rsquo;outil prestashopConsole qui est disponible ici : <a href=\"https:\/\/github.com\/nenes25\/prestashop_console\" target=\"_blank\" rel=\"noopener\">https:\/\/github.com\/nenes25\/prestashop_console<\/a><br \/>Et cr\u00e9er un module basique de test <em>hhtestci\u00a0<\/em> via la commande suivante : <br \/>php prestashopConsole.phar module:generate:module hhtestci<\/p>\n<p>Dans ce module rajouter n&rsquo;importe quelle erreur php, commiter et envoyer la modification dans git, puis faire une merge request comme nous l&rsquo;avons vu dans l&rsquo;\u00e9tape pr\u00e9c\u00e9dente.<br \/>Dans le code de la merge request, rien ne nous indique qu&rsquo;il y&rsquo;a une erreur.<br \/><br \/>L&rsquo;erreur n&rsquo;est pas forc\u00e9ment tr\u00e8s visible et il est donc\u00a0 tout \u00e0 fait possible de passer \u00e0 c\u00f4t\u00e9 et d&rsquo;envoyer une erreur en production.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-8.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"494\" src=\"https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-8-1024x494.png\" alt=\"\" class=\"wp-image-3429\" srcset=\"https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-8-1024x494.png 1024w, https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-8-300x145.png 300w, https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-8-768x371.png 768w, https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-8.png 1113w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>On voit bien qu&rsquo;il n&rsquo;y a aucun contr\u00f4le, et cela veut dire que m\u00eame si on s\u00e9curise qui peut livrer le code, nous ne sommes pas \u00e0 l&rsquo;abri d&rsquo;envoyer du code non fonctionnel.<br>Il est donc temps de simplifier le travail de celui qui est charg\u00e9 de valider le code \ud83d\ude42<br><br><br>Le code prestashop, est majoritairement constitu\u00e9 de fichiers php ( mais aussi :&nbsp; javascript, css ,tpl&nbsp; &#8230;)<br>Lors de chaque livraison de code ces fichiers sont chang\u00e9s.<br><br>En fonction des intervenants, la qualit\u00e9 du d\u00e9veloppement pourra \u00eatre plus ou moins bonne et g\u00e9n\u00e9rer des erreurs.<\/p>\n<p>Afin de limiter ces erreurs on va donc mettre en place des outils d&rsquo;analyse de la qualit\u00e9 de code.<br>Ces outils vont se charger pour nous de v\u00e9rifier le code qu&rsquo;on va envoy\u00e9 ne comporte pas d&rsquo;erreurs.<br>Pour la v\u00e9rification des fichiers php dans un premier temps nous allons utliser <strong>Phpstan<br><\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/phpstan.png\" alt=\"\" class=\"wp-image-3435\" style=\"width:124px;height:124px\" width=\"124\" height=\"124\" srcset=\"https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/phpstan.png 600w, https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/phpstan-300x300.png 300w, https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/phpstan-150x150.png 150w\" sizes=\"auto, (max-width: 124px) 100vw, 124px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Configuration locale de phpstan<\/h2>\n\n\n\n<p>Pour ceux qui ne connaissent pas phpstan : <br \/>C&rsquo;est un outil d&rsquo;analyse statique pour PHP qui aide les d\u00e9veloppeurs \u00e0 d\u00e9tecter les erreurs de type, les probl\u00e8mes de coh\u00e9rence, et les violations des bonnes pratiques dans leur code PHP. <br \/>Il am\u00e9liore la qualit\u00e9 du code, favorise la maintenance et permet de gagner du temps lors du processus de d\u00e9veloppement en fournissant des informations sur les erreurs potentielles, les types de donn\u00e9es et les performances du code.<br \/>L&rsquo;avantage des outils d&rsquo;analyses statiques est donn\u00e9e dans leur nom, ils n&rsquo;ont pas besoin d&rsquo;ex\u00e9cuter le projet pour d\u00e9tecter les probl\u00e8mes potentiels.<br \/>Vous pouvez trouver plus d&rsquo;information ( en anglais ) sur le site officiel : <a href=\"https:\/\/phpstan.org\" target=\"_blank\" rel=\"noopener\">https:\/\/phpstan.org\/<\/a><br \/><br \/>Pour commencer il va falloir faire fonctionner phpstan en local.<br \/><br \/>Cr\u00e9er une nouvelle branche depuis master<br \/>En fonction de la structuration du projet , cr\u00e9er un dossier <strong>tests<\/strong> soit \u00e0 la racine, au m\u00eame niveau que le dossier <strong>www<br \/><\/strong><br \/>Dans ce dossier, lancer la commande suivante pour r\u00e9cup\u00e9rer phpstan :<\/p>\n\n\n\n<pre lang=\"bash\">\ncomposer require phpstan\/phpstan\n<\/pre>\n\n\n\n<p>Pour ne pas versionner le dossier vendor ajouter \u00e9galement un fichier <em>.gitignore<\/em> dans ce dossier avec le contenu suivant :<br>vendor<strong><br><br><\/strong>Ensuite vous pouvez cr\u00e9er le dossier suivant <em>php\/phpstan<\/em> et mettre le contenu suivant dans le fichier <strong>phpstan.neon<\/strong><br>Ce fichier permets de configurer phpstan, je mets volontairement tous les commentaires dans le fichiers pour ce que ce soit plus clair<\/p>\n\n\n\n<pre lang=\"yaml\">\nparameters:\n  scanFiles:\n    - class_stub.php\n  scanDirectories: #Listes des fichiers syst\u00e8mes de Prestashop auxquels votre module peut \u00eatre li\u00e9\n    # Tous les chemins sont relatifs \u00e0 l'emplacement du fichier de ce fichier configuration phpstan.neon\n    - ..\/..\/..\/www\/classes\n    - ..\/..\/..\/www\/config\/\n    - ..\/..\/..\/www\/controllers\n    - ..\/..\/..\/www\/override\n    - ..\/..\/..\/www\/src\n    - ..\/..\/..\/www\/vendor\n  level: 4 # Niveau de qualit\u00e9 du code, commencer (cf. https:\/\/phpstan.org\/user-guide\/rule-levels )\n  paths: # Liste des modules sp\u00e9cifiques \u00e0 tester\n    - ..\/..\/..\/www\/modules\/hhtestci #Notre module de d\u00e9mo\n  excludePaths:\n    - ..\/..\/..\/www\/modules\/*\/vendor\/* #On ne veut pas analyser les fichiers vendor des modules\n  ignoreErrors: #Liste des erreurs \u00e0 ignorer\n  #Pour les autres \u00e9l\u00e9ments je vous renvoie vers la documentation de phpstan\n  reportUnmatchedIgnoredErrors: false\n  checkMissingIterableValueType: false\n  treatPhpDocTypesAsCertain: false\n  parallel:\n    maximumNumberOfProcesses: 1\n<\/pre>\n\n\n\n<p>Pour aider Phpstan \u00e0 conna\u00eetre les classes de Prestashop rajoutez \u00e9galement le fichier <strong>class_stub.php<\/strong> , dans ce m\u00eame dossier<\/p>\n\n\n\n<pre lang=\"php\">\n<?php\n\nclass SmartyDevTemplate extends SmartyDevTemplateCore {};\nclass SmartyResourceParent extends SmartyResourceParentCore {};\nclass SmartyCustom extends SmartyCustomCore {};\nclass TemplateFinder extends TemplateFinderCore {};\nclass SmartyCustomTemplate extends SmartyCustomTemplateCore {};\nclass SmartyResourceModule extends SmartyResourceModuleCore {};\nclass Search extends SearchCore {};\nclass WarehouseAddress extends WarehouseAddressCore {};\nclass LocalizationPack extends LocalizationPackCore {};\nclass CartRule extends CartRuleCore {};\nclass FeatureValue extends FeatureValueCore {};\nclass AddressFormat extends AddressFormatCore {};\nclass Currency extends CurrencyCore {};\nclass CategoryLang extends CategoryLangCore {};\nclass DataLang extends DataLangCore {};\nclass ConfigurationLang extends ConfigurationLangCore {};\nclass AttributeGroupLang extends AttributeGroupLangCore {};\nclass CarrierLang extends CarrierLangCore {};\nclass TabLang extends TabLangCore {};\nclass StockMvtReasonLang extends StockMvtReasonLangCore {};\nclass MetaLang extends MetaLangCore {};\nclass GroupLang extends GroupLangCore {};\nclass AttributeLang extends AttributeLangCore {};\nclass GenderLang extends GenderLangCore {};\nclass QuickAccessLang extends QuickAccessLangCore {};\nclass FeatureValueLang extends FeatureValueLangCore {};\nclass SupplyOrderStateLang extends SupplyOrderStateLangCore {};\nclass ThemeLang extends ThemeLangCore {};\nclass ContactLang extends ContactLangCore {};\nclass OrderStateLang extends OrderStateLangCore {};\nclass OrderMessageLang extends OrderMessageLangCore {};\nclass ProfileLang extends ProfileLangCore {};\nclass RiskLang extends RiskLangCore {};\nclass FeatureLang extends FeatureLangCore {};\nclass CmsCategoryLang extends CmsCategoryLangCore {};\nclass OrderReturnStateLang extends OrderReturnStateLangCore {};\nclass ProductDownload extends ProductDownloadCore {};\nclass QuickAccess extends QuickAccessCore {};\nclass ImageType extends ImageTypeCore {};\nabstract class Db extends DbCore {};\nclass DbPDO extends DbPDOCore {};\nclass DbQuery extends DbQueryCore {};\nclass DbMySQLi extends DbMySQLiCore {};\nclass Tools extends ToolsCore {};\nclass DateRange extends DateRangeCore {};\nclass Employee extends EmployeeCore {};\nabstract class PaymentModule extends PaymentModuleCore {};\nclass Page extends PageCore {};\nclass Carrier extends CarrierCore {};\nabstract class Controller extends ControllerCore {};\nclass AdminController extends AdminControllerCore {};\nclass FrontController extends FrontControllerCore {};\nclass ModuleFrontController extends ModuleFrontControllerCore {};\nabstract class ProductPresentingFrontController extends ProductPresentingFrontControllerCore {};\nabstract class ProductListingFrontController extends ProductListingFrontControllerCore {};\nabstract class ModuleAdminController extends ModuleAdminControllerCore {};\nclass PrestaShopDatabaseException extends PrestaShopDatabaseExceptionCore {};\nclass PrestaShopPaymentException extends PrestaShopPaymentExceptionCore {};\nclass PrestaShopObjectNotFoundException extends PrestaShopObjectNotFoundExceptionCore {};\nclass PrestaShopModuleException extends PrestaShopModuleExceptionCore {};\nclass PrestaShopException extends PrestaShopExceptionCore {};\nclass Tree extends TreeCore {};\nclass TreeToolbarLink extends TreeToolbarLinkCore {};\nclass TreeToolbarSearch extends TreeToolbarSearchCore {};\nclass TreeToolbarSearchCategories extends TreeToolbarSearchCategoriesCore {};\nabstract class TreeToolbarButton extends TreeToolbarButtonCore {};\nclass TreeToolbar extends TreeToolbarCore {};\nclass Attribute extends AttributeCore {};\nclass Country extends CountryCore {};\nclass WebserviceException extends WebserviceExceptionCore {};\nclass WebserviceSpecificManagementImages extends WebserviceSpecificManagementImagesCore {};\nclass WebserviceOutputBuilder extends WebserviceOutputBuilderCore {};\nclass WebserviceSpecificManagementAttachments extends WebserviceSpecificManagementAttachmentsCore {};\nclass WebserviceOutputJSON extends WebserviceOutputJSONCore {};\nclass WebserviceRequest extends WebserviceRequestCore {};\nclass WebserviceKey extends WebserviceKeyCore {};\nclass WebserviceOutputXML extends WebserviceOutputXMLCore {};\nclass WebserviceSpecificManagementSearch extends WebserviceSpecificManagementSearchCore {};\nclass LinkProxy extends LinkProxyCore {};\nclass SearchEngine extends SearchEngineCore {};\nclass CustomerAddress extends CustomerAddressCore {};\nclass AttributeGroup extends AttributeGroupCore {};\nclass Link extends LinkCore {};\nclass ProductSupplier extends ProductSupplierCore {};\nclass Media extends MediaCore {};\nclass ShopGroup extends ShopGroupCore {};\nclass ShopUrl extends ShopUrlCore {};\nclass Shop extends ShopCore {};\nclass Supplier extends SupplierCore {};\nclass ImageManager extends ImageManagerCore {};\nabstract class AbstractCheckoutStep extends AbstractCheckoutStepCore {};\nclass PaymentOptionsFinder extends PaymentOptionsFinderCore {};\nclass DeliveryOptionsFinder extends DeliveryOptionsFinderCore {};\nclass CheckoutDeliveryStep extends CheckoutDeliveryStepCore {};\nclass CheckoutPaymentStep extends CheckoutPaymentStepCore {};\nclass AddressValidator extends AddressValidatorCore {};\nclass CheckoutSession extends CheckoutSessionCore {};\nclass CheckoutProcess extends CheckoutProcessCore {};\nclass CartChecksum extends CartChecksumCore {};\nclass CheckoutAddressesStep extends CheckoutAddressesStepCore {};\nclass ConditionsToApproveFinder extends ConditionsToApproveFinderCore {};\nclass CheckoutPersonalInformationStep extends CheckoutPersonalInformationStepCore {};\nclass CustomerThread extends CustomerThreadCore {};\nclass PhpEncryptionLegacyEngine extends PhpEncryptionLegacyEngineCore {};\nclass CacheXcache extends CacheXcacheCore {};\nabstract class Cache extends CacheCore {};\nclass CacheMemcache extends CacheMemcacheCore {};\nclass CacheApc extends CacheApcCore {};\nclass CacheMemcached extends CacheMemcachedCore {};\nclass PhpEncryption extends PhpEncryptionCore {};\nclass Delivery extends DeliveryCore {};\nclass Gender extends GenderCore {};\nclass Translate extends TranslateCore {};\nclass HelperOptions extends HelperOptionsCore {};\nclass HelperCalendar extends HelperCalendarCore {};\nclass HelperImageUploader extends HelperImageUploaderCore {};\nclass HelperForm extends HelperFormCore {};\nclass HelperTreeShops extends HelperTreeShopsCore {};\nclass HelperKpiRow extends HelperKpiRowCore {};\nclass HelperTreeCategories extends HelperTreeCategoriesCore {};\nclass HelperUploader extends HelperUploaderCore {};\nclass HelperList extends HelperListCore {};\nclass HelperKpi extends HelperKpiCore {};\nclass HelperView extends HelperViewCore {};\nclass HelperShop extends HelperShopCore {};\nclass Helper extends HelperCore {};\nclass Tag extends TagCore {};\nclass CMS extends CMSCore {};\nclass Customization extends CustomizationCore {};\nclass Cookie extends CookieCore {};\nclass SupplyOrderReceiptHistory extends SupplyOrderReceiptHistoryCore {};\nclass StockAvailable extends StockAvailableCore {};\nclass StockManager extends StockManagerCore {};\nclass StockMvt extends StockMvtCore {};\nclass Warehouse extends WarehouseCore {};\nclass WarehouseProductLocation extends WarehouseProductLocationCore {};\nclass Stock extends StockCore {};\nclass SupplyOrderDetail extends SupplyOrderDetailCore {};\nclass StockManagerFactory extends StockManagerFactoryCore {};\nabstract class StockManagerModule extends StockManagerModuleCore {};\nclass StockMvtReason extends StockMvtReasonCore {};\nclass SupplyOrderState extends SupplyOrderStateCore {};\nclass StockMvtWS extends StockMvtWSCore {};\nclass SupplyOrder extends SupplyOrderCore {};\nclass SupplyOrderHistory extends SupplyOrderHistoryCore {};\nclass Customer extends CustomerCore {};\nclass Hook extends HookCore {};\nclass CustomerAddressPersister extends CustomerAddressPersisterCore {};\nclass FormField extends FormFieldCore {};\nclass CustomerLoginFormatter extends CustomerLoginFormatterCore {};\nclass CustomerAddressFormatter extends CustomerAddressFormatterCore {};\nclass CustomerPersister extends CustomerPersisterCore {};\nclass CustomerForm extends CustomerFormCore {};\nclass CustomerFormatter extends CustomerFormatterCore {};\nclass CustomerAddressForm extends CustomerAddressFormCore {};\nclass CustomerLoginForm extends CustomerLoginFormCore {};\nabstract class AbstractForm extends AbstractFormCore {};\nclass Context extends ContextCore {};\nclass Connection extends ConnectionCore {};\nclass QqUploadedFileForm extends QqUploadedFileFormCore {};\nclass ProductSale extends ProductSaleCore {};\nclass Group extends GroupCore {};\nclass PrestaShopCollection extends PrestaShopCollectionCore {};\nclass ValidateConstraintTranslator extends ValidateConstraintTranslatorCore {};\nabstract class ModuleGridEngine extends ModuleGridEngineCore {};\nabstract class Module extends ModuleCore {};\nabstract class CarrierModule extends CarrierModuleCore {};\nabstract class ModuleGraph extends ModuleGraphCore {};\nabstract class ModuleGrid extends ModuleGridCore {};\nabstract class ModuleGraphEngine extends ModuleGraphEngineCore {};\nclass SupplierAddress extends SupplierAddressCore {};\nclass Store extends StoreCore {};\nclass QqUploadedFileXhr extends QqUploadedFileXhrCore {};\nclass CMSCategory extends CMSCategoryCore {};\nclass Profile extends ProfileCore {};\nclass Upgrader extends UpgraderCore {};\nclass Category extends CategoryCore {};\nclass Meta extends MetaCore {};\nclass ProductPresenterFactory extends ProductPresenterFactoryCore {};\nclass Address extends AddressCore {};\nclass Windows extends WindowsCore {};\nclass HTMLTemplateSupplyOrderForm extends HTMLTemplateSupplyOrderFormCore {};\nclass HTMLTemplateOrderReturn extends HTMLTemplateOrderReturnCore {};\nclass HTMLTemplateDeliverySlip extends HTMLTemplateDeliverySlipCore {};\nclass PDF extends PDFCore {};\nabstract class HTMLTemplate extends HTMLTemplateCore {};\nclass HTMLTemplateInvoice extends HTMLTemplateInvoiceCore {};\nclass HTMLTemplateOrderSlip extends HTMLTemplateOrderSlipCore {};\nclass PDFGenerator extends PDFGeneratorCore {};\nclass OrderReturn extends OrderReturnCore {};\nclass OrderDiscount extends OrderDiscountCore {};\nclass OrderHistory extends OrderHistoryCore {};\nclass OrderMessage extends OrderMessageCore {};\nclass Order extends OrderCore {};\nclass OrderState extends OrderStateCore {};\nclass OrderCarrier extends OrderCarrierCore {};\nclass OrderCartRule extends OrderCartRuleCore {};\nclass OrderInvoice extends OrderInvoiceCore {};\nclass OrderPayment extends OrderPaymentCore {};\nclass OrderReturnState extends OrderReturnStateCore {};\nclass OrderDetail extends OrderDetailCore {};\nclass OrderSlip extends OrderSlipCore {};\nclass RangeWeight extends RangeWeightCore {};\nclass RangePrice extends RangePriceCore {};\nabstract class AbstractLogger extends AbstractLoggerCore {};\nclass FileLogger extends FileLoggerCore {};\nclass Uploader extends UploaderCore {};\nclass Guest extends GuestCore {};\nclass SpecificPriceRule extends SpecificPriceRuleCore {};\nclass CustomerSession extends CustomerSessionCore {};\nclass PrestaShopBackup extends PrestaShopBackupCore {};\nclass Alias extends AliasCore {};\nclass Configuration extends ConfigurationCore {};\nclass Manufacturer extends ManufacturerCore {};\nclass ConfigurationTest extends ConfigurationTestCore {};\nclass RequestSql extends RequestSqlCore {};\nclass JsMinifier extends JsMinifierCore {};\nclass JavascriptManager extends JavascriptManagerCore {};\nabstract class AbstractAssetManager extends AbstractAssetManagerCore {};\nclass CssMinifier extends CssMinifierCore {};\nclass CccReducer extends CccReducerCore {};\nclass StylesheetManager extends StylesheetManagerCore {};\nclass Tab extends TabCore {};\nabstract class ObjectModel extends ObjectModelCore {};\nclass ProductAssembler extends ProductAssemblerCore {};\nclass SpecificPrice extends SpecificPriceCore {};\nclass CustomerMessage extends CustomerMessageCore {};\nclass EmployeeSession extends EmployeeSessionCore {};\nclass ManufacturerAddress extends ManufacturerAddressCore {};\nclass CustomizationField extends CustomizationFieldCore {};\nclass State extends StateCore {};\nclass Combination extends CombinationCore {};\nclass Access extends AccessCore {};\nclass TranslatedConfiguration extends TranslatedConfigurationCore {};\nclass AddressChecksum extends AddressChecksumCore {};\nclass CSV extends CSVCore {};\nclass GroupReduction extends GroupReductionCore {};\nclass Language extends LanguageCore {};\nclass Image extends ImageCore {};\nclass Risk extends RiskCore {};\nclass SpecificPriceFormatter extends SpecificPriceFormatterCore {};\nclass Pack extends PackCore {};\nclass FileUploader extends FileUploaderCore {};\nclass CMSRole extends CMSRoleCore {};\nclass PhpEncryptionEngine extends PhpEncryptionEngineCore {};\nclass Referrer extends ReferrerCore {};\nclass Contact extends ContactCore {};\nclass Feature extends FeatureCore {};\nclass Mail extends MailCore {};\nclass Notification extends NotificationCore {};\nclass PrestaShopLogger extends PrestaShopLoggerCore {};\nclass Curve extends CurveCore {};\nabstract class TaxManagerModule extends TaxManagerModuleCore {};\nclass TaxManagerFactory extends TaxManagerFactoryCore {};\nclass Tax extends TaxCore {};\nclass TaxRulesTaxManager extends TaxRulesTaxManagerCore {};\nclass TaxConfiguration extends TaxConfigurationCore {};\nclass TaxRule extends TaxRuleCore {};\nclass TaxCalculator extends TaxCalculatorCore {};\nclass TaxRulesGroup extends TaxRulesGroupCore {};\nclass Dispatcher extends DispatcherCore {};\nclass Validate extends ValidateCore {};\nclass ConfigurationKPI extends ConfigurationKPICore {};\nclass Attachment extends AttachmentCore {};\nclass ConnectionsSource extends ConnectionsSourceCore {};\nclass Chart extends ChartCore {};\nclass Product extends ProductCore {};\nclass Message extends MessageCore {};\nclass Zone extends ZoneCore {};\nclass Cart extends CartCore {};\n<\/pre>\n\n\n\n<p>La structure du projet devrait \u00e0 pr\u00e9sent \u00eatre la  suivante :  <\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-12.png\"><img loading=\"lazy\" decoding=\"async\" width=\"216\" height=\"335\" src=\"https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-12.png\" alt=\"\" class=\"wp-image-3438\" srcset=\"https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-12.png 216w, https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-12-193x300.png 193w\" sizes=\"auto, (max-width: 216px) 100vw, 216px\" \/><\/a><\/figure>\n\n\n\n<p>Et&nbsp; on devrait maintenant \u00eatre bon pour lancer phpstan en local et v\u00e9rifier si tout fonctionne comme pr\u00e9vu<br>Via la commande suivante<\/p>\n\n\n\n<pre lang=\"bash\">\nphp vendor\/bin\/phpstan analyze -c php\/phpstan\/phpstan.neon \n<\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-9.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1007\" height=\"319\" src=\"https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-9.png\" alt=\"\" class=\"wp-image-3431\" srcset=\"https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-9.png 1007w, https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-9-300x95.png 300w, https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-9-768x243.png 768w\" sizes=\"auto, (max-width: 1007px) 100vw, 1007px\" \/><\/a><\/figure>\n\n\n\n<p>Parfait la v\u00e9rification locale est bien fonctionnelle !<br>Place maintenant \u00e0 la configuration dans la CI<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Configuration de phpstan dans la CI<\/h2>\n\n\n\n<p>Reste donc maintenant \u00e0 ajouter cette v\u00e9rification dans l'int\u00e9gration continue.<br>Pour cela il va donc falloir rajouter les informations suivantes dans le fichier .gitlab-ci.yml<\/p>\n\n\n\n<pre lang=\"yaml\">\n#V\u00e9rification de la qualit\u00e9 du code\ntest:code_quality:\n  stage: test\n  image: php:7.4\n  rules:\n    - if: $CI_PIPELINE_SOURCE == \"merge_request_event\"\n  before_script:\n    - mv \"$PHP_INI_DIR\/php.ini-development\" \"$PHP_INI_DIR\/php.ini\"\n    - apt-get update -yqq\n    - apt install zip unzip\n    - \"curl -sSLf -o \/usr\/local\/bin\/install-php-extensions https:\/\/github.com\/mlocati\/docker-php-extension-installer\/releases\/latest\/download\/install-php-extensions &&\n        chmod +x \/usr\/local\/bin\/install-php-extensions &&\n        install-php-extensions zip \"\n    # Install and run Composer\n    - cd tests\n    - curl -sS https:\/\/getcomposer.org\/installer | php\n    - php composer.phar install\n  script:\n    #SCRIPTS DE TESTS ICI\n    - php -d memory_limit=512M vendor\/bin\/phpstan analyze -c php\/phpstan\/phpstan.neon\n<\/pre>\n\n\n\n<p>La ligne importante est celle apr\u00e8s <strong>#SCRIPTS DE TESTS ICI<\/strong> <br>qui va lancer le test phpstan dans la CI \ud83d\ude42<br><br>Le&nbsp; reste du code permets de mettre en place une image docker et de pr\u00e9parer l'ex\u00e9cution des scripts.<br>Il ne nous reste plus qu'\u00e0 tester que tout fonctionne comme attendu.<br>Commitez et poussez votre code, puis cr\u00e9er une merge request dans gitlab.<br><br>Et le code de la merge request devrait maintenant g\u00e9n\u00e9rer une erreur.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-10.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"598\" src=\"https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-10-1024x598.png\" alt=\"\" class=\"wp-image-3432\" srcset=\"https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-10-1024x598.png 1024w, https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-10-300x175.png 300w, https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-10-768x449.png 768w, https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-10.png 1066w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>Et si on regarde les d\u00e9tails de l'erreur on peut voir que c'est bien la m\u00eame que lors de nos tests locaux.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-11.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"550\" src=\"https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-11-1024x550.png\" alt=\"\" class=\"wp-image-3433\" srcset=\"https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-11-1024x550.png 1024w, https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-11-300x161.png 300w, https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-11-768x412.png 768w, https:\/\/www.h-hennes.fr\/blog\/wp-content\/uploads\/2023\/09\/image-11.png 1291w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>Notre v\u00e9rification de la qualit\u00e9 du code php est maintenant en place, et nous sommes \u00e0 pr\u00e9sents en mesure de v\u00e9rifier de mani\u00e8re simple et automatis\u00e9 que notre code php ne comporte pas d'erreurs manifestes.<br \/>Corriger l'erreur et pousser le code et tout devrait \u00eatre ok ensuite.<br \/><br \/>Il est possible d'aller plus loin dans cette partie \u00e0 la fois en augmentant le niveau des r\u00e8gles de phpstan, mais \u00e9galement en rajoutant d'autres outils tels que :<\/p>\n<ul>\n<li>Php Mess Detector ( PhpMd) qui permets de v\u00e9rifier la complexit\u00e9 du votre code<\/li>\n<li>Php Cs Fixer (\u00a0 Qui permets de v\u00e9rifier le formatage du code )<\/li>\n<\/ul>\n<p>En tant que d\u00e9veloppeur front il doit \u00e9galement \u00eatre possible de mettre en place le m\u00eame genre de linting sur les fichiers javascript ou css.<br \/>Cependant je n'en fais pas assez de mon c\u00f4t\u00e9 pour \u00eatre pertinent sur cette partie, n'h\u00e9sitez pas \u00e0 partager vos actuces sur le sujet.<br \/><br \/>Dans la prochaine \u00e9tape nous r\u00e9pondrons \u00e0 la probl\u00e9matique de<strong> Comment r\u00e9duire les interactions manuelles dans notre proc\u00e9dure de livraison de code.<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Cet article est le 3\u00e8me de la s\u00e9rie sur le d\u00e9ploiement et l\u2019int\u00e9gration continu dans Prestashop.Les autres articles de cette s\u00e9rie sont les suivants : \u00c9tat des lieux En pr\u00e9alable de cette \u00e9tape nous allons ajouter un nouveau module prestashop de mauvaise qualit\u00e9 et avec une erreur de syntaxe php.C&rsquo;est volontairement ce qu&rsquo;il ne faut [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"set","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[245],"tags":[597,484,599,104],"class_list":["post-3402","post","type-post","status-publish","format-standard","hentry","category-prestashop-2","tag-ci-cd","tag-gitlab","tag-phpstan","tag-prestashop"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.h-hennes.fr\/blog\/wp-json\/wp\/v2\/posts\/3402","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.h-hennes.fr\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.h-hennes.fr\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.h-hennes.fr\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.h-hennes.fr\/blog\/wp-json\/wp\/v2\/comments?post=3402"}],"version-history":[{"count":11,"href":"https:\/\/www.h-hennes.fr\/blog\/wp-json\/wp\/v2\/posts\/3402\/revisions"}],"predecessor-version":[{"id":3453,"href":"https:\/\/www.h-hennes.fr\/blog\/wp-json\/wp\/v2\/posts\/3402\/revisions\/3453"}],"wp:attachment":[{"href":"https:\/\/www.h-hennes.fr\/blog\/wp-json\/wp\/v2\/media?parent=3402"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.h-hennes.fr\/blog\/wp-json\/wp\/v2\/categories?post=3402"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.h-hennes.fr\/blog\/wp-json\/wp\/v2\/tags?post=3402"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}