PHPCS on Codeship as CI test
Use Codeship to test the changed files in your pull request against PHPCS. Find working code, and explanation on why it works.
Yesterday I wrote about setting up PHPCS on changed files on CircleCI. Today’s article is about doing the same thing on Codeship Basic.
tldr;
Code is on the same repository, in the .codeship
folder. You’ll need these two snippets for Setup commands and a Test pipeline:
Setup commands
phpenv local 7.2
# Prepare cache directory and install dependencies
mkdir -p ./bootstrap/cache
composer install --no-interaction
bash $HOME/clone/.codeship/setup.sh
Test pipeline
bash $HOME/clone/.codeship/test.sh
Explanation
The same logic is used on Codeship as on CircleCI: check out code, get changed files between target branch and PR branch, and run phpcs on those.
The Setup Commands bit sets php to be 7.2 (you can use whatever the latest phpcs supports), creates a bootstrap/cache directory which we don't use, installs composer packages, which is needed to get phpcs in there, and runs our setup.sh
file that’s in the repository.
setup.sh
if [ -d "$HOME/cache/wpcs" ];
then
git -C $HOME/cache/wpcs fetch origin && git -C $HOME/cache/wpcs pull origin master
else
git clone -q -b master https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards.git $HOME/cache/wpcs
fi
./vendor/bin/phpcs --config-set installed_paths $HOME/cache/wpcs
./vendor/bin/phpcs -i
The $HOME/cache
directory is special. It’s retained between builds. If the wpcs
folder is already there, let’s pull down latest master, if it’s not there, let’s check out the coding standards repo at master
branch.
Then tell phpcs
(installed via composer) about our new rules, and list them so we can double check.
test.sh
url="https://api.github.com/repos/$CI_REPO_NAME/pulls/$CI_PR_NUMBER"
target_branch=$(curl -s -X GET -G \
$url \
-d access_token=$GITHUB_TOKEN | jq '.base.ref' | tr -d '"')
git remote set-branches --add origin $target_branch
git fetch origin $target_branch:$target_branch
git checkout $target_branch
git checkout $CI_BRANCH
changed_files=$(git diff --name-only $target_branch..$CI_BRANCH -- '*.php')
if [[ -z $changed_files ]]
then
echo "There are no files to check."
exit 0
fi
if [ ! -f phpcs.xml ]
then
echo "No phpcs.xml file found. Nothing to do."
exit 0
fi
echo "Running phpcs..."
./vendor/bin/phpcs $changed_files
This is mostly the same as the one in CircleCI, adjusted for available environment variables.
Fixing shallow clone
Codeship also does a shallow clone, which implies the use of the --single-branch
flag, which means the remote will only know about that one branch, so a git fetch
will only get info about that one singular branch.
To fix that, we need to tell our local git that we might want to fetch another branch as well. The below achieves this:
git remote set-branches --add origin $target_branch
git fetch origin $target_branch:$target_branch
If you look into your .git/config
file, on a normal git clone
you will see this part of the file:
[remote "origin"]
url = git@github.com:javorszky/circleci-calibration.git
fetch = +refs/heads/*:refs/remotes/origin/*
In a --single-branch
setting, the fetch
will look like this:
fetch = +refs/heads/branch_name:refs/remotes/origin/branch_name
Using set-branches --add
will add a new fetch
entry, so you’ll have this:
fetch = +refs/heads/branch_name:refs/remotes/origin/branch_name
fetch = +refs/heads/other_branch_name:refs/remotes/origin/other_branch_name
Once these two lines are there, a git fetch
will get all info on both branches, but only those two branches. Any other branches on the remote will be ignored.
See https://git-scm.com/docs/git-remote.html#Documentation/git-remote.txt-emset-branchesem for official git documentation.
Grabbing the difference
Now that we have both the feature and target branch in our fetch config, git can pull info from both, which means we can check out both, and the git diff
will return a meaningful list of files.
Don’t forget to check out the feature branch again after checking out the target branch. git diff
will definitely get you the list of files changed in the PR, but if you’re still on the target branch, it will run phpcs on those files as they were before you began work. Which means the files might not even exist.
Other than that, this is all that should be needed.
Photo by Vidar Nordli-Mathisen on Unsplash