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