squizlabs / PHP_CodeSniffer

PHP_CodeSniffer tokenizes PHP files and detects violations of a defined set of coding standards.
BSD 3-Clause "New" or "Revised" License
10.63k stars 1.48k forks source link

Allow CodeSniffer.conf to be stored in a user's home directory #2062

Open digitalsounds opened 6 years ago

digitalsounds commented 6 years ago

When running composer global update, if there is even a minor version update, e.g. from 3.2.3 to 3.3.0 then the CodeSniffer.conf gets removed (for me its here: ~/.composer/vendor/squizlabs/php_codesniffer/CodeSniffer.conf) I have it installed globally. This file as you know stores the global config settings for default_standard and installed_paths, etc; which means i lose these settings after every time code sniffer updates and i have to set them again, any way we can avoid this?

gsherwood commented 6 years ago

I'm not sure why the file is being removed. I guess it must be specific to how composer updates packages because I don't track CodeSniffer.conf in the repo and so composer would see it as a local file only. I don't know any way around that.

It seems like you'd need to either stop using that file and move to a phpcs.xml file instead (per-project defaults) or I'd need to add an option to allow you to specify a path to a config file on the command line. But given I can't store this path anywhere, you'd have to specify it every time you run PHPCS.

Or any ideas you have?

digitalsounds commented 6 years ago

So after looking into it a bit further, using composer's -vvv cli option when updating:

composer global require "squizlabs/php_codesniffer=3.3.0" -vvv

It looks like composer uses zip archives to install the packages, which means the entire package directory is being completely overwritten when an update happens, this led me to think i could use the --prefer-source cli option when installing (this actually clones the repository into the vendor directory instead of using zip files)":

composer global require "squizlabs/php_codesniffer=3.3.0" -vvv --prefer-source

This in fact resolves the issue when updating (so the config file remains using this option), but I think you'd agree that this is not a very practical or long term solution, and the clone actually took quite a long time.

I think a better solution would be to just change where this config file is stored in the first place; is this possible? i.e. so when we run:

phpcs --config-set default_standard PSR2

instead of generating the file here:

~/.composer/vendor/squizlabs/php_codesniffer/CodeSniffer.conf

create it here instead:

~/.CodeSniffer.conf

Obviously you could play with the name a little.

gsherwood commented 6 years ago

Using the user's home directory is probably a good option, although that does mean that shared configs are basically gone.

So maybe the way to do this is to look in the standard config file location first, then look in the user's home directory if nothing is found there.

The tricky bit is setting configs. PHPCS wouldn't know if you want to set a global config or a user config, so it would need a CLI switch (sort of like git uses) to switch between those two locations I guess.

What I really would like is a place to store a config file in composer that isn't destroyed during upgrades, like the PEAR installer has always had. But I can't find a place to put anything like that. The suggestion is to include the config file inside your project itself, which is what the phpcs.xml (or xml.dist) file is for.

I suggest changing to the phpcs.xml file format and committing it to your projects directly, if possible, as it means that you can have different settings per project if necessary, and any other developers who ever work on that project already have the PHPCS settings required for it. Or if you happen to clone the repo on another machine, the settings are there already.

digitalsounds commented 6 years ago

@gsherwood Thanks for this, I will place the config in the xml file for now, its a shame we can't use the main config, I have dug through the composer documentation myself and like you said there is nowhere you can put this file, perhaps a feature request is in order, but i shall leave that decision up to you.

I was wondering however, with the xml option, can I put a phpcs.xml file in the root of my home directory and set the installed_paths in it, and then set other xml files in child directories without having to set the installed_paths in each each one of those child directories, i.e. they will inherit the installed_paths from the one in my home directory creating a combined config of sorts, or will they completely overwrite the one in my home directory?

jrfnl commented 6 years ago

@digitalsounds You can include the ruleset from your project root in the rulesets in child directories. That will "import" all rules and config from the root ruleset.

<rule ref="/path/to/project/root/phpcs.xml.dist"/>

or

<rule ref="./../phpcs.xml.dist"/>
digitalsounds commented 5 years ago

I have actually found a solution to global phpcs config file overwriting itself, although some may feel it lacks in elegance, but I have taken a somewhat pragmatic approcach with this.

To your global composer.json file, usually located in $HOME/.composer or $HOME/.config/composer, add the following to the scripts key:

"post-install-cmd": [
    "phpcs --config-set installed_paths <installed_paths>",
    "phpcs --config-set default_standard <coding_standard>"
],
"post-update-cmd": [
    "phpcs --config-set installed_paths <installed_paths>",
    "phpcs --config-set default_standard <coding_standard>"
]

so the complete composer.json file would look something like this:

{
    "require": {
        "squizlabs/php_codesniffer": "3.*",
        "friendsofphp/php-cs-fixer": "^2.12"
    },
    "scripts": {
        "post-install-cmd": [
            "phpcs --config-set installed_paths <installed_paths>",
            "phpcs --config-set default_standard <coding_standard>"
        ],
        "post-update-cmd": [
            "phpcs --config-set installed_paths <installed_paths>",
            "phpcs --config-set default_standard <coding_standard>"
        ]
    }
}

Here we are just setting the global installed_paths and default_standard, but obviously you could set any config you liked. In this example, you would obviously change out and for whatever you wanted to set them to, but this means whenever there is a composer update/install these scripts will run, which means even if there is an update to phpcs and the global config gets overwritten, these commands will run and re-populate the global config with whatever these commands set.

minterior commented 5 years ago

Hi there! Thank you for your previous comments. I have some thoughts:

Yes please!! I always miss that (optional) option. We then could specify any location. If the file doesn't exist or is bad formatted just raise an error. If the option is not used then look up for the config file in the same way you're doing it now.

Thank you for your time ;)

b-hayes commented 4 years ago

phpcs.xml I ahve been trying to share code sniffer settings and Ive seen this mentioned in a few places and also appears that phpstorm can detect this file but I cant see any explanation on how to use the xml file to setup a few settings.

The code sniffer doesnt appear to use the local php version or the compsoer.json php version when issuing waning for certain standards and I need it to remember what version of php to run as. (this migth be another issue)

Just seems very difficult to get the information I need.

Can you point me to some clear documentation on how to write this phpcs.xml file?

jrfnl commented 4 years ago

Can you point me to some clear documentation on how to write this phpcs.xml file?

@b-hayes https://github.com/squizlabs/PHP_CodeSniffer/wiki/Annotated-Ruleset

Note: if you save a ruleset file in the project root and name it [.]phpcs.xml[.dist], it will be picked up automatically by PHPCS and you don't need to pass --standard=... on the command-line.

tfrommen commented 3 years ago

Sorry for reviving this from the dead, but since the issue is still open and since my question is closely related, I thought I'd start by leaving a comment here. If this should be a separate issue, I can do that no problem.

I would like to use phive for managing my local PHP tooling. So far, it's working pretty good, also with PHP_CodeSniffer, in general. However, what is not working is making the (sym-linked) phpcs binary pick up changes in the CodeSniffer.conf file, either done by calling phpcs or by some Composer plugin. Of course, this is because it is (or would be) stored in vendor.

My exact use case I'm having issues with is that I am using phpcodesniffer-composer-installer to set the installed_paths option to include all PHP_CodeSniffer standards pulled in via Composer. This is done by writing to (or creating) the vendor/squizlabs/php_codesniffer/CodeSniffer.conf file.

What I would look to be able to do is tell the sym-linked phpcs binary, that is actually physically stored in my user directory, /home/tfrommen/.phive/phars/phpcs-3.5.8.phar, to pick up the installed_paths, in some way.

If the config file path could be user-defined, as currently being worked on in #3191 👏, I would create a PR for the phpcodesniffer-composer-installer repository.

What could work as well is making PHP_CodeSniffer look for the configuration file in the current directory, pretty much in line with how/where it looks for a ruleset file...? 🤔

Does this make sense, or is there anything worth clarifying?

dossy commented 5 months ago

For Mac users using Homebrew, every time we upgrade php-code-sniffer, it creates a new /usr/local/Cellar/php-code-sniffer/$VERSION directory, leaving the CodeSniffer.conf behind in the previous version's bin directory. In other words, the path to the CodeSniffer.conf looks like this:

/usr/local/Cellar/php-code-sniffer/3.8.1/bin/CodeSniffer.conf

Having PHPCS have a "search path" for CodeSniffer.conf which looks in the user's home directory first would be incredibly helpful. I always forget to copy over the conf file from the previous version's bin directory when PHPCS "breaks" after each upgrade ...

fredden commented 5 months ago

@dossy that sounds like something that could be added to https://github.com/Homebrew/homebrew-core/blob/master/Formula/p/php-code-sniffer.rb. I recommend you open an issue over there to see if your particular case can be solved within the Brew toolset.

dossy commented 5 months ago

@fredden Unfortunately, Homebrew formulas do not have a method of executing code on upgrade, and by default Homebrew uninstalls the old version before installing the new version during an upgrade, so even trying to add code to the install hook to try and copy forward the CodeSniffer.conf from the previous/old version requires the user to either set HOMEBREW_NO_INSTALL_CLEANUP=1 or HOMEBREW_NO_CLEANUP_FORMULAE=php-code-sniffer which is not obvious and has other undesirable side-effects.