[PHP] Issues with Composer cache, PHPUnit coverage & logs

Hello everyone, I can’t make my phpunit coverage & logs available in my artifacts, and can’t even send my coverage to CodeCov.io

Here’s my circle.yml file: https://gist.github.com/Pierstoval/51c1c81c35b95d3d32aa2584737c0eda

First, even if I have set up the cache for composer, I can’t make it work and composer packages are always downloaded, whatever the cache I try to configure…

The tests/ci/ci.bash is just a bash script that uses environment vars as parameters. It also runs lots of stuff before using phpunit (composer install, check environment configuration, etc.).

The final PHPUnit command looks like this when resolved:

./vendor/bin/phpunit \
    --log-junit "/home/ubuntu/my_project/build/phpunit/junit.xml" \
    --coverage-clover "/home/ubuntu/my_project/build/phpunit/clover.xml" \
    --coverage-html "/home/ubuntu/my_project/build/phpunit/html/

The problem is that none of these files exist in the end.

I tried adding test -f "${PROJECT_DIR}/build/phpunit/clover.xml" in the circle.yml file and I have these results:

$ test -f "${PROJECT_DIR}/build/phpunit/clover.xml"
test -f "${PROJECT_DIR}/build/phpunit/clover.xml" returned exit code 1

BUT, in the PHPUnit’s output I see this:

Generating code coverage report in Clover XML format ... done
Generating code coverage report in HTML format ... done

Any idea on why PHPUnit does not generate coverage or logs?

May I have done something wrong?


I relaunched the build with SSH enabled, and when I log with ssh, go to the project’s directory and run the exact same phpunit command, the coverage is dumped to the directories.
Whereas it is not when running the build “normally”…

What’s the problem? :sob:

Is it possible the variable expansion isn’t working for PHPUNIT_PARAMETERS ? Try echoing out the command you end up running and see what it looks like?


I know you put a resolved command in the issue summary but not sure if you actually echo’d that from your script? FWIW, I ran that exact command locally and it works exactly as you’d expect.

I know you put a resolved command in the issue summary but not sure if you actually echo’d that from your script? FWIW, I ran that exact command locally and it works exactly as you’d expect.

@benjy Exactly, the outputted command is precisely the one executed by the ci.bash script. Actually, I wrap all commands with a bash function to retrieve all errors and show them only at the end of the script execution.

The problem does not seem to come from the command itself because all arguments are correct…

I can try using phpunit directly in the circle.yml file configuration, but as I’m using different CIs (I also have a local docker image that can run these tests), I really don’t want to get rid of this ci.bash file :confused:

Hello @Pierstoval,

Could you provide a link to a build? I will take a look.

Best, Zak

The project is from a private Github repo, and it seems CircleCI builds are also private (even though I don’t mind them to be public as long as the repo stays private) :confused:

But still, in https://circleci.com/gh/Pierstoval/corahn_rin/86 , if you can look at it, you can check for the [Command] ./vendor/bin/phpunit ... line in build logs, as well as the full circle.yml file with the env vars.

The build succeeds, PHPUnit tells that the coverage was generated (clover & html formats), but in the post section in circle.yml, I’m running CodeCov.io script and it says file not found at /tmp/circle-artifacts.kwiWs5M/phpunit/clover.xml.

Also, at the end of the build, the Collect artifacts tells that nothing was retrieved.

Edit: And the problem doesn’t seem to come from the /tmp dir because I also have tried to log the files in the local app’s build directory and copy them afterwards, but they are not present.

Are the tests executions isolated from the filesystem or something?

That is really weird, have you tried logging in via SSH an executing the command directly?

Such as,

./vendor/bin/phpunit --log-junit "${CIRCLE_TEST_REPORTS}/phpunit/junit.xml" --coverage-clover "${CIRCLE_ARTIFACTS}/phpunit/clover.xml" --coverage-html "${CIRCLE_ARTIFACTS}/phpunit/html"

Yes @zzak, that’s what I say in the first post, I tried both this command AND another command where the log files are outputted to local ./build/ directory instead:

./vendor/bin/phpunit --log-junit "build/phpunit/junit.xml" --coverage-clover "build/phpunit/clover.xml" --coverage-html "build/phpunit/html"

And when running this command in SSH, logs are correctly generated in the specified directories :disappointed:

Sorry for double answer, but I tested without using the ci.bash script, and files are created in the correct directories.

Maybe the script doesn’t have the rights to create a file?

The circle.yml file looks like this when removing the ci.bash script:

        # ... Other scripts
        - './vendor/bin/phpunit --log-junit "${CIRCLE_TEST_REPORTS}/phpunit/junit.xml" --coverage-clover "${CIRCLE_ARTIFACTS}/phpunit/clover.xml" --coverage-html "${CIRCLE_ARTIFACTS}/phpunit/html"'

For now I’m falling back to this solution, but as I might use different CIs (appveyor for windows, for example) I’d like to have the same “test execution” for every CI, even if the configuration behind is different… :confused:

1 Like

Hello @Pierstoval,

I’m glad you found a workaround to get your builds running.

I wonder if you could modify the script to accept the output directories as command-line argument, then you can have both a functional script on CircleCI, and one that you can share on other CI services as well.

Best, Zak

I don’t understand exactly what you mean, what should I do exactly?

If you run your script using BASH, any arguments you pass to it, including the script itself, will get assigned as positional parameters that you can access within the script.

For example:

# from the command-line
$ ./path/to/script.sh foo bar baz

# script.sh
echo $0
echo $1
echo $2
echo $3

# The output will be:
#    path/to/script.sh
#    foo
#    bar
#    baz

So you could pass any variables you want, including the path to these output directories you need, so that your script can use them. For example, in circle.yml you could call this script with the $CIRCLE_ARTIFACTS/phpunit as one of the arguments, or in some other CI service config file pass something completely different.

Hope that makes sense, and I have given you enough motivation to learn on your own :slight_smile:

Oh, I see what you’re talking about, but actually I’m using environment variables configured in the circle.yml file, an argument named PHPUNIT_PARAMETERS which is retrieved automatically by my bash script.

And to re-explain, the complete phpunit ... command does correspond to what should be used, when I dump the different CircleCI env vars (artifacts & test logs) they do correspond to what I have in my PHPUnit command.

The problem is that it works on another CI (Shippable, to mention it), and on my local VM (where I output logs to a shared directory), but not in CircleCI :confused:

I could also prepend the command in the circle.yml file with these environment vars, maybe. I’m gonna try in the next days, once my build works again (lots of updates and build is red for now :wink: )

Thanks for help anyway :thumbsup:

1 Like

Sounds like are heading in the right direction!

Let us know if you get stuck or have any more questions.

Now that I have switched to Circle2.0, I don’t know if coverage will work, but still, there is no CIRCLE_TEST_REPORTS nor CIRCLE_ARTIFACTS env vars so I ended up pushing my coverage to an external service :confused: