Přechod na DressCode

Stará jména pravidel i potlačovací komentáře fungují dál, konfiguraci převede jeden příkaz a vypíše, co se nepodařilo přenést. Společný postup pro přechod z jakéhokoli nástroje a poctivý seznam toho, co bude jinak.

Proč to nebolí

Vím, jak to vypadá: máte konfiguraci, ve které jsou roky ladění, v kódu stovky komentářů phpcs:ignore, možná pár vlastních sniffů a k tomu CI, které to celé spouští. Nástroj se nemění proto, že je nový hezčí. Mění se, když přechod nebolí, a přesně tak je DressCode postavený.

Klíčová věc: DressCode zná svá pravidla nejen pod vlastním jménem, ale i pod tím, jak se jmenují v PHP CS Fixeru, PHP_CodeSniffer a Slevomatu. Když napíšete dresscode rules, uvidíte u každého pravidla cizí jména, která pokrývá. Z toho plyne všechno ostatní: komentáře v kódu fungují beze změny a konfigurace se dá převést strojově.

Postup má tři kroky a každý z nich se dá vrátit.

1. Kód nechte, jak je

Komentáře // phpcs:ignore, phpcs:disable, phpcs:enable, phpcs:ignoreFile i anotace @phpcsSuppress dělají dál to, co dělaly. DressCode je přečte, cizí jméno pravidla si přeloží na své, a potlačení platí. Do kódu tedy zatím vůbec nemusíte sahat a první kontrolu můžete pustit hned:

dresscode check src tests

Bez konfigurace platí preset dresscode/per, tedy PER Coding Style 3.1. Kdo dosud používal @PER-CS nebo PSR12, uvidí zhruba to, co čekal. Kdo měl doladěno nad rámec standardu, uvidí rozdíly, které vyřeší další krok.

2. Přeložte konfiguraci

Příkaz import přečte cizí konfiguraci a vypíše její ekvivalent pro DressCode (kdo přichází z nástroje bez konfigurace, nebo žádnou nemá, si ji nechá změřit z kódu příkazem dresscode init):

dresscode import phpcs.xml > dresscode.php
dresscode import .php-cs-fixer.dist.php > dresscode.php

phpcs.xml je XML, takže se přečte bez čehokoli dalšího. Naproti tomu .php-cs-fixer.dist.php je PHP, které se musí spustit a které vrací objekt cizí knihovny; import na něm funguje jen v projektu, kde je ta knihovna ještě nainstalovaná. Proto konfiguraci překládejte dřív, než starý nástroj odeberete.

Na standardní výstup jde hotová konfigurace, na chybový výstup to, co se přenést nepodařilo:

<?php declare(strict_types=1);

use DressCode\Config;

return new Config(
	presets: ['dresscode/psr12'],
	rules: [
		'dresscode/line-length' => true,
		'dresscode/unused-imports' => ['searchAnnotations' => false],
	],
	lineLength: 100,
);

Read 4 rules, enabled 2 and 1 preset.
  No DressCode rule covers Squiz.Commenting.FunctionComment.

Druhý seznam je stejně cenný jako první: říká, kde se musíte rozhodnout. Pravidlo bez protějšku buď nepotřebujete, nebo si ho napíšete. Sady jako @PSR12 nebo PSR12 se překládají na presety; u sad, které protějšek nemají (třeba @PhpCsFixer), to import ohlásí a doporučí začít od dresscode/per.

Přeložené volby s sebou nesou i hodnoty (absoluteLineLimit se stane klíčem lineLength), ale ne každá cizí volba protějšek má; i to import vypíše. Pravidlo, které cizí konfigurace vypnula, import vypne také (=> false) a shrnutí ho počítá jako turned off. Když ale totéž pravidlo DressCode pokrývá i jiné pravidlo téhož nástroje, nechá ho zapnuté a vypíše varování, protože nemůže vědět, jestli z nich některé pořád platí. Výsledný soubor si projděte, je krátký.

3. Přepište komentáře

Komentáře v kódu fungují i se starými jmény, nové jsou ale kratší a čitelnější. Přepis udělá jeden příkaz:

dresscode migrate-suppressions src tests

Z phpcs:ignore SlevomatCodingStandard.Namespaces.UnusedUses se stane dresscode:ignore dresscode/unused-imports, z phpcs:disable a phpcs:enable se stanou dresscode:disable a dresscode:enable, z phpcs:ignoreFile pak dresscode:ignore-file. Jméno, které žádné pravidlo nepokrývá, zůstane, jak bylo, a příkaz ho vypíše. Z toho výpisu máte seznam potlačení, která už nic nepotlačují.

První oprava

Až konfigurace sedí, pusťte dresscode fix a výsledek commitněte samostatně, bez jiných změn. I u pravidla, které je „stejné“, může oprava vyjít o mezeru jinak než u starého nástroje, a procházet to řádek po řádku nemá smysl. Smysl má vědět, že v tom commitu není nic jiného. U velkého projektu, kde by byl jeden commit nepřehledný, opravujte po pravidlech, dresscode fix --only <pravidlo>, a každé z nich commitněte zvlášť; příští úplný fix pak změní zbytek, viz –only. Co fix opravit neumí, zůstane ve výpisu, a když je toho víc, než chcete řešit hned, zapíše to baseline a hlásit se budou jen nová porušení.

Co bude jinak

Návod, který slibuje bezešvý přechod, ztratí důvěru u prvního rozdílu, tak raději rovnou:

  • Priority neexistují. Kdo si výsledek stavěl na pořadí fixerů, dostane u některých souborů jiný tvar kódu. Pravidla tu běží opakovaně, dokud se výsledek neustálí; proč.
  • Pravidla bez protějšku vypíše import i migrate-suppressions. Není jich málo, hlavně mezi sniffy o dokumentaci a mezi pravidly, kterými se nástroje navzájem překrývají.
  • Rizikové (risky) pravidlo tu rizikové být nemusí. Co PHP CS Fixer zapínal jen na výslovnou žádost, protože nad tokeny nerozeznal bezpečný případ od nebezpečného, rozhoduje tady strom, a pravidlo opraví jen ty bezpečné. Oprava, která chování měnit může, se ohlásí jako riziková a udělá se až u pravidla uvedeného v seznamu fixRisky v konfiguraci, nebo s --fix-risky. A pravidlo, které mění chování programu ze své podstaty (strict-comparison dělá z == ===), zůstává vaším rozhodnutím, ať ho zapnete kdekoli.
  • Exit kódy jsou jiné: 0 čisto, 1 porušení, 2 selhání nástroje. PHP_CodeSniffer i PHP CS Fixer mají vlastní stupnice, takže skript, který je vyhodnocuje, potřebuje jednu úpravu.
  • Jeden nástroj místo dvou. Kdo kombinoval CodeSniffer a Fixer, měl dvě konfigurace a dva kroky v CI. Teď je jedna a jeden.
  • Místo výčtu pravidel se ptáte na záměr. Konfigurace stojí na dvou otázkách: standard řekne, jak má kód vypadat, a skupina pravidel to, co po něm chcete kromě vzhledu. Skupin je šest a jejich jména jsou uzavřený výčet, takže se z řádku groups: [cleanup] nemá jak stát dvacet řádků se jmény pravidel, ani když katalog povyroste.
  • Aktualizace kódu je v témže nástroji. DressCode přepíše kód i na novější PHP a na nové API knihoven a v témž běhu ho zformátuje podle standardu, který jste právě převedli. Na přechod na novou verzi tedy nepotřebujete další nástroj s vlastní konfigurací, viz Přechod na novější PHP a Aktualizace knihoven.

Podrobnosti pro konkrétní nástroj: PHP CS Fixer, PHP_CodeSniffer a Slevomat, Nette Coding Standard.