Display Git informations in the Symfony WebProfiler ↗️

26 / 08 / 2018

Today we’ll manipulate the Symfony webprofiler, and add some information from Git. Be aware that this feature sould be avaible only in dev environment.

Here is the source code but follow me it’s an easy task !

1- Create a Symfony Project

$ composer create-project symfony/website-skeleton project

2- Inside the project, create a simple Controller

<?php

namespace AppController;

use SensioBundleFrameworkExtraBundleConfigurationRoute;
use SymfonyBundleFrameworkBundleControllerController;

class DefaultController extends Controller
{
    /**
     * @Route("/")
     */
    public function profiler()
    {
        return $this->render('base.html.twig');
    }
}

3- Create a Service for retrieve the information from Git

In src, create a directory BranchLoader. Inside this folder, create a class GitLoader that will contains the logic to retrieve the Git informations The idea comes from stackoverflow, feel free to improve the code but keep in mind that it’s not our first goal here 😁

<?php
//src/BranchLoader/GitLoader.php

namespace AppBranchLoader;

class GitLoader
{
    private $projectDir;

    public function __construct($projectDir)
    {
        $this->projectDir = $projectDir;
    }

    public function getBranchName()
    {
        $gitHeadFile = $this->projectDir.'/.git/HEAD';
        $branchname = 'no branch name';

        $stringFromFile = file_exists($gitHeadFile) ? file($gitHeadFile, FILE_USE_INCLUDE_PATH) : "";

        if(isset($stringFromFile) && is_array($stringFromFile)) {
            //get the string from the array
            $firstLine =  $stringFromFile[0];
            //seperate out by the "/" in the string
            $explodedString = explode("/", $firstLine, 3);

            $branchname = trim($explodedString[2]);
        }

        return $branchname;
    }

    public function getLastCommitMessage()
    {
        $gitCommitMessageFile =  $this->projectDir.'/.git/COMMIT_EDITMSG';
        $commitMessage = file_exists($gitCommitMessageFile) ? file($gitCommitMessageFile, FILE_USE_INCLUDE_PATH) : "";

        return is_array($commitMessage) ? trim($commitMessage[0]) : "";
    }

    public function getLastCommitDetail()
    {
        $logs = [];
        $gitLogFile =  $this->projectDir.'/.git/logs/HEAD';
        $gitLogs = file_exists($gitLogFile) ? file($gitLogFile, FILE_USE_INCLUDE_PATH) : "";

        $logExploded = explode(' ', end($gitLogs));
        $logs['author'] =  $logExploded[2] ?? 'not defined';
        $logs['date'] = isset($logExploded[4]) ? date('Y/m/d H:i', $logExploded[4]) : "not defined";

        return $logs;
    }
}

4- Declare this class in services.yaml to get the kernel.project_dir parameter

# config/services.yaml
AppBranchLoaderGitLoader:
    arguments:
        ['%kernel.project_dir%']

5- Create our custom data collector : GitDataCollector the name is arbitrary

Now we have access to the Git informations, we just have to add them to the DataCollector. Our custom class will extends DataCollector see documentation for more details.

<?php

//src/DataCollector/GitDataCollector.php
namespace AppDataCollector;

use AppBranchLoaderGitLoader;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpFoundationResponse;
use SymfonyComponentHttpKernelDataCollectorDataCollector;

class GitDataCollector extends DataCollector
{
    private $gitLoader;

    public function __construct(GitLoader $gitLoader)
    {
       $this->gitLoader =  $gitLoader;
    }

    public function collect(Request $request, Response $response, Exception $exception = null)
    {
       // We add the git informations in $data[]
       $this->data = [
            'git_branch' => $this->gitLoader->getBranchName(),
            'last_commit_message' => $this->gitLoader->getLastCommitMessage(),
            'logs' => $this->gitLoader->getLastCommitDetail(),
        ];
    }

    // we will use this name in the config later
    public function getName()
    {
        return 'app.git_data_collector';
    }

    public function reset()
    {
        $this->data = array();
    }
    //Some helpers to access more easily to infos in the template
    public function getGitBranch()
    {
        return $this->data['git_branch'];
    }

    public function getLastCommitMessage()
    {
        return $this->data['last_commit_message'];
    }

    public function getLastCommitAuthor()
    {
        return $this->data['logs']['author'];
    }

    public function getLastCommitDate()
    {
        return $this->data['logs']['date'];
    }
}

6- Create the template git_data.html.twig

{# templates/data_collector/git_data.html.twig #}
{% extends '@WebProfiler/Profiler/layout.html.twig' %}

{% block toolbar %}
    {% set icon %}
        {# this is the content displayed as a panel in the toolbar #}
{# this big svg is just the Git icon #}
        <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
             width="97px" height="97px" viewBox="0 0 97 97" enable-background="new 0 0 97 97" xml:space="preserve">
<g>
    <path fill="#F05133" d="M92.71,44.408L52.591,4.291c-2.31-2.311-6.057-2.311-8.369,0l-8.33,8.332L46.459,23.19
      c2.456-0.83,5.272-0.273,7.229,1.685c1.969,1.97,2.521,4.81,1.67,7.275l10.186,10.185c2.465-0.85,5.307-0.3,7.275,1.671
      c2.75,2.75,2.75,7.206,0,9.958c-2.752,2.751-7.208,2.751-9.961,0c-2.068-2.07-2.58-5.11-1.531-7.658l-9.5-9.499v24.997
      c0.67,0.332,1.303,0.774,1.861,1.332c2.75,2.75,2.75,7.206,0,9.959c-2.75,2.749-7.209,2.749-9.957,0c-2.75-2.754-2.75-7.21,0-9.959
      c0.68-0.679,1.467-1.193,2.307-1.537V36.369c-0.84-0.344-1.625-0.853-2.307-1.537c-2.083-2.082-2.584-5.14-1.516-7.698
      L31.798,16.715L4.288,44.222c-2.311,2.313-2.311,6.06,0,8.371l40.121,40.118c2.31,2.311,6.056,2.311,8.369,0L92.71,52.779
      C95.021,50.468,95.021,46.719,92.71,44.408z"/>
</g>
</svg>
        <span class="sf-toolbar-value">{{ collector.gitBranch }}</span>
    {% endset %}

    {% set text %}
        {# this is the content displayed when hovering the mouse over
        the toolbar panel #}
        <div class="sf-toolbar-info-piece">

                <b>Last commit : </b>
            <span>{{ collector.lastCommitDate }} </span>

        </div>
        <div class="sf-toolbar-info-piece">
                <b>Author : </b>
                <span>{{ collector.lastCommitAuthor }} </span>
        </div>
        <div class="sf-toolbar-info-piece">
                <b>Message : </b>
                <span>{{ collector.lastCommitMessage }} </span>
        </div>

    {% endset %}

    {# the 'link' value set to 'false' means that this panel doesn't
    show a section in the web profiler #}
    {{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: false }) }}
{% endblock %}

7- Enable the template

To enable the data collector template, override the service configuration to specify a tag that contains the template.

# config/services.yaml
# ...

AppDataCollectorGitDataCollector:
    tags:
        -
            name:     data_collector
            template: 'data_collector/git_data.html.twig'
            # must match the value returned by the getName() method
            id: 'app.git_data_collector'
    public: false

8- Result ! 🎉

Did you see the Git logo with the current branch name ? Victory !!

Result

Bonus : The last commit details are displayed when hovering the zone.

Bonus

Thanks for reading, I hope you liked it, don't forget to share it !
LinkedIn Twitter