Wednesday, February 13, 2019

Code Analysis with Exakat on Docker

One of the neatest things I learned about last week at SunshinePHP, was how Exakat can be used to perform static analysis of a codebase to help formalize your code review processes.  It's a great tool for determining how consistent you and your team are being with your code, and has indicators to show you how closely your code base aligns to each of the major PHP versions -- an excellent way to check backward compatibility and/or whether you're ready for a PHP upgrade or not. 

With Docker, it's extremely easy to get things running!


To get started, pull the exakat/exakat:latest docker image.

docker image pull exakat/exakat:latest

You can confirm that it works by running the version command:
docker container run --rm exakat/exakat version

Now, that you know the image is downloaded properly and working, you can save your project analysis to your local project root by mounting the project storage folder to the /usr/src/exakat/projects/ folder of the container using the docker volume toggle when you execute your container
-v $(pwd):/usr/src/exakat/projects
Alternately, you can set up a named volume for that projects folder:
docker volume create exakat_projects --opt type=none  \
   --opt device=/my/path/to/projects --opt o=bind

# Then in all the following examples, use this volume 
# toggle instead of the local map
-v exakat_projects:/usr/src/exakat/projects

To start our analysis, we need to initialize the project. You can point it to your repo with the -R command, if your repo is public and you want it to pull sources automatically, or you can use the -R toggle to point it to a local folder where your code is stored.

Since I don't want to mess with ssh keys in the container, or have extra copies of my repo locally, I'm just going to create multiple volume mappings into the exakat container and tell it where to store the project data and the src code, running the container from the folder where I have my git repository checked out locally and specifying that mount location as a symlink for the exakat /code/ folder for the project.

I'm also specifying a parent folder specifically set aside to hold my exakat project data (../exakat). If you're going to use this same technique, please make sure you create that ../exakat folder before attempting to run the container.
docker container run --rm -it \
   -v $(PWD)/../exakat:/usr/src/exakat/projects \
   -v $(PWD):/usr/src/exakat/projects/volume_src \
   exakat/exakat init \
   -p MyProject -v \
   -R /usr/src/exakat/projects/volume_src/ -symlink
- or (if using the named volume) -
docker container run --rm -it \
   -v exakat_projects:/usr/src/exakat/projects \
   -v $(PWD):/usr/src/exakat/projects/volume_src \
   exakat/exakat init \
   -p MyProject -v \
   -R /usr/src/exakat/projects/volume_src/ -symlink
Note that the -v before the image name and command is a volume mapping for the container, while the -v after the command is a toggle passed to the command (in this case, the verbose toggle)

Then run the project command, using the same volume mount points specified previously and sit back and watch while it runs it's magic! (Remember, if you're using a remote git repository instead of local source, you do not need to use the second volume mount for volume_src)
docker container run --rm -it \
   -v $(PWD)/../exakat:/usr/src/exakat/projects \
   -v $(PWD):/usr/src/exakat/projects/volume_src \
   exakat/exakat project -v -p MyProject
- or (if using the named volume) -
docker container run --rm -it \
   -v exakat_projects:/usr/src/exakat/projects \
   -v $(PWD):/usr/src/exakat/projects/volume_src \
   exakat/exakat project -v -p MyProject


When the report generation is complete, it will have populated the folder for your project (in this case ../exakat/MyProject) with a report subfolder that contains an index.html file. Opening that file should show you a page like this (I recommend using Firefox, not Chrome for this as the genrated javascript plays more nicely with that browser):


And if you go down to the "Compatibility" menu, and look at PHP Versions, you'll see something that looks like this:


As expected, since this is a legacy application that I'm testing with right now, it's showing that 5.6 is my lowest fully compatible php version for this application. It clearly hasn't been refactored with any of the newest PHP 7 specific capabilities, or it would no longer be backward compatible to 5.6.

Finally, since I've mapped the volumes to persist, I can customize my exakat.ini settings by going to my /exakat/MyProject/config.ini file and making any necessary adjustments.

This just scratches the surface of what you're able to do with this amazing tool. I highly suggest that you read the docs for the full range of capabilities, now that you know how easy it is to get started.

Happy Analyzing!

Update: If you want to have the code linked in the report output, use -copy instead of -symlink for the local source file.

2 comments:

  1. Just a quick update - if you're using the most recent images, you need to pass the exakat command, not just the command parameter. So it becomes ```exakat/exakat exakat project``` etc.

    ReplyDelete
  2. Another note: If you want to be able to view the reports with the full source code, you need to do so via a web server. You can easily do this by navigating to your exakat project report folder and using ```php -S localhost:8080``` to launch a standalone php web server to serve the files. Choose whatever port works for you.

    ReplyDelete