Skip to content

Instantly share code, notes, and snippets.

@zacscott
Created June 25, 2018 00:05
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zacscott/1b1f38da4764706a03ce3df31c1a3eaf to your computer and use it in GitHub Desktop.
Save zacscott/1b1f38da4764706a03ce3df31c1a3eaf to your computer and use it in GitHub Desktop.
PHPCS w/ Bitbucket Pipelines helper script
import os
import re
import subprocess
import sys
import tempfile
def log(message):
"""Print a log message to console, will be a darker colour than normal print()"""
formatted = "%s%s%s" % (
'\u001b[30;1m', # dark grey colour
message,
'\u001b[0m' # reset colour
)
print(formatted)
def hr():
"""Print a horizontal line to console"""
log("================================================================")
def cmd(command):
"""
Execute the given command.
:param command: The command to be executed, passed to os.system()
"""
exit_code = 0
lines = []
command_str = ' '.join(command)
log(command_str)
hr()
# run the command and capture the output
try:
output = subprocess.check_output(
command,
stderr=subprocess.STDOUT,
universal_newlines=True
)
except subprocess.CalledProcessError as ex:
output = ex.output
exit_code = ex.returncode
# parse lines
output = output.decode('ascii') if not isinstance(output, str) else output
lines = output.split("\n")
# output command output
for line in lines:
print(line)
hr()
return (exit_code, lines)
_tempdir = None
def tempdir():
"""Returns the temp working directory, where composer etc. will be installed"""
global _tempdir
if _tempdir is None:
_tempdir = tempfile.mkdtemp()
return _tempdir
def git_fetch():
cmd(["git", "remote", "set-branches", "origin", "*"])
cmd(["git", "fetch"])
def git_checkout(branch):
"""Checkout the given branch in Git"""
# NOTE we have to do it in this round about way because Bitbucket only does
# a shallow clone, so we dont have all the branches
cmd([
"git",
"checkout",
branch
])
cmd([
"git", "pull", "origin", branch
])
def git_diff_files(branch):
"""
Return a list of all of the files which have changed between the current
branch and the given branch in Git
"""
(exit_code, changed_files) = cmd([
"git", "diff", branch, "--name-only"
])
return changed_files
def phpcs_build():
"""Download, install and configure PHPCS"""
owd = os.getcwd()
os.chdir(tempdir())
cmd([
"composer",
"require",
"squizlabs/php_codesniffer",
"--ignore-platform-reqs"
])
os.chdir(owd)
# include WP coding standards
cmd([
"git", "clone",
"https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards.git",
"%s/vendor/wpcs" % tempdir(),
"--depth", "1"
])
cmd([
"%s/vendor/bin/phpcs" % tempdir(),
"--config-set",
"installed_paths",
"%s/vendor/wpcs" % tempdir()
])
def phpcs_analyse(files):
"""Run the PHPCS analyser on the given list of files"""
command = [
"%s/vendor/bin/phpcs" % tempdir(),
"--colors"
]
(exit_code, changed_files) = cmd(command + files)
return exit_code
################################################################################################
def run_phpcs(branch_from, branch_to):
hr()
log("COMPARING GIT %s => %s" % (branch_from, branch_to))
log("TEMPDIR = %s" % tempdir())
hr()
git_fetch()
# determine the files which have changed between the two branches
git_checkout(branch_from)
changed_files = git_diff_files(branch_to)
# select the PHP files only for analysis
changed_php_files = []
for file_path in changed_files:
print("'%s'" % file_path)
if file_path.endswith("php"):
changed_php_files.append(file_path)
if len(changed_php_files):
# run PHPCS if there are files to update
# include PHPCS and analyse the changed files
phpcs_build()
exit_code = phpcs_analyse(changed_files)
# exit with same code as PHPCS, so pipeline fails if there are errors
exit(exit_code)
else:
log("NO PHP FILES TO ANALYSE")
if len(sys.argv) >= 2:
run_phpcs(sys.argv[1], sys.argv[2])
else:
print("USAGE: %s <from branch> <to branch>" % sys.argv[0])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment