Use git reflog to split two squashed commits

published on February 08, 2019.

Today I was using interactive git rebase to squash some commits together to clean up the commit history of a git branch. At one point I went a bit overboard with it and squashed together two commits by mistake.

I’ve heard somewhere from someone that in git you pretty much can’t lose code because everything is in the git reflog. Today I decided to put that to the test.

Spoiler alert: git reflog saved the day.

The setup

We start with two separate commits, “Commit 1” and “Commit 2”:

> git hist
* c3fa1d6 -  (HEAD -> reflog-undo-squash) Commit 2 [Robert Basic 4 seconds ago]
* db73960 -  Commit 1 [Robert Basic 56 seconds ago]

Using git rebase -i HEAD~2 we start the interactive rebase for the last two commits:

pick db73960 Commit 1
f c3fa1d6 Commit 2

We choose to fixup “Commit 2” with “Commit 1”, which means that the second commit will be squashed with the first commit, discarding the commit message of the second commit.

Uh oh, that was a mistake, and our commit history now looks like this:

> git hist
* 786865f -  (HEAD -> reflog-undo-squash) Commit 1 [Robert Basic 5 minutes ago]

Our nice little “Commit 2” is now gone and before we start panicking and making more damage, let’s take a look at the git reflog to see what we have there.

Looking at the reflog

The git reflog right after the bad rebase shows us the following:

> git reflog
786865f (HEAD -> reflog-undo-squash) HEAD@{0}: rebase -i (finish): returning to refs/heads/reflog-undo-squash
786865f (HEAD -> reflog-undo-squash) HEAD@{1}: rebase -i (fixup): Commit 1
0a8f291 HEAD@{2}: rebase -i (pick): Commit 1
684d689 HEAD@{3}: rebase -i (pick): Commit 1
5761a21 HEAD@{4}: rebase -i (start): checkout 5761a21b0c0a1f12ab1c60bfef1f1d111ba699c0
c3fa1d6 HEAD@{5}: commit: Commit 2
db73960 HEAD@{6}: commit (initial): Commit 1

The thing at HEAD@{6} was the first thing that happened and the thing at HEAD@{0} is whatever is going on right now.

What we want the current state to be is the state before we started the rebase process, that is the state at HEAD@{5}. To do that we “reset” our state to that point in time:

> git reset HEAD@{5}

And now our git history is back to it’s pre-rebase state:

> git hist
* c3fa1d6 -  (HEAD -> reflog-undo-squash) Commit 2 [Robert Basic 15 minutes ago]
* db73960 -  Commit 1 [Robert Basic 16 minutes ago]

Note that even the commit shas are back to their pre-rebase values, db73960 and c3fa1d6.

The Atlassian git reflog tutorial goes into more detail, so make sure to read that as well.

Happy hackin’!

Tags: git, reflog, squash, rebase.
Categories: Development, Software.

Vue.js reusable components

published on February 04, 2019.

A while ago I started learning bits and pieces about Vue.js by creating a single page application for one of my pet projects that I use to explore Domain-Driven Design. In general I know my way around a Javascript file, but wouldn’t call myself an expert with it. In the past I mostly used jquery, some mootools, and even Dojo. Ah, good old Zend Framework 1 times.

While reading up on Vue.js I came across the part of their documentation that talks about components and how to make them reusable. At the time I just glanced over it, thought “Neat.” to myself and went on with my day. Yesterday when I was done with creating a page that holds a list of tasks, I remembered that section about reusable components and wondered could I use that to clean up a bit of the code I wrote. Turns out, I can!

A simplified version of my initial Vue.js page was something like this:

./assets/vue/components/Journal.vue

<template>
    <div>
        <template v-if="journal.tasks.length !== 0">
            <div v-for="task in journal.tasks">
                <template v-if="task.status === 'todo'">
                    <button @click="markTaskAsDone(task.id)">
                        Mark as done
                    </button>
                    <span>{{ task.description }}</span>
                </template>
                <template v-if="task.status === 'done'">
                    <strong>{{ task.description }}</strong>
                </template>
            </div>
        </template>
    </div>
</template>

<script>
    export default {
        name: 'journal',
        data: function () {
            return {
                journal: {
                    tasks: [
                        {
                            'id': 1,
                            'description': "Task 1",
                            'status': "todo"
                        },
                        {
                            'id': 2,
                            'description': "Task 2",
                            'status': "done"
                        },
                    ],
                }
            }
        },
        methods: function () {
            markTaskAsDone: function(taskId) {
                alert("Marking task as done, ID: " + taskId);
            }
        }
    }
</script>

We check if there are any tasks in the journal and if so, iterate over them. For todo tasks show a button that we can use to mark that task as done and show the description of the task. For done tasks display the task description bolded.

Now, for the case when the journal has no tasks, I decided I want to show the organizer (an organizer is a person who organizes their tasks in that app) an example list of tasks instead of a blank page with a boring “No tasks” message. I’m also learning to make my designs a tiny bit better, courtesy of the Refactoring UI book.

How did I do that? By copy/pasting a bunch of times the HTML for the todo and done tasks.

./assets/vue/components/Journal.vue

<template>
    <div>
        <template v-if="journal.tasks.length !== 0">
            <div v-for="task in journal.tasks">
                <template v-if="task.status === 'todo'">
                    <button @click="markTaskAsDone(task.id)">
                        Mark as done
                    </button>
                    <span>{{ task.description }}</span>
                </template>
                <template v-if="task.status === 'done'">
                    <strong>{{ task.description }}</strong>
                </template>
            </div>
        </template>
        <template v-else>
            <div>
                <button @click="alert('Marking the task as done')">
                    Mark as done
                </button>
                <span>An example of a todo task</span>
            </div>
            <div>
                <strong>An example of a done task</strong>
            </div>
        </template>
    </div>
</template>

Remember, this is a simplified version of the code. Add to that a bunch of more divs, a bunch of CSS classes as I’m using TailwindCSS and what I had before me was a real nightmare. Almost a hundred lines of HTML.

Enter stage left… Reusable components.

What I did was I created two reusable components, one for a todo task, and one for a done task.

The component for the todo task looks something like this:

./assets/vue/components/Tasks/Todo.vue

<template>
    <div>
        <button @click="">
            Mark as done
        </button>
        <span><slot>An empty task</slot></span>
    </div>
</template>
<script>
    export default {
        name: 'todoTask',
    }
</script>

The <slot> element acts like a kind of a placeholder where Vue.js will insert whatever text we pass on later to that component. There are other ways to pass in data from parent to child components, but in this case, this was simple and enough for me. Note that the @click event handler for the button is empty, as at this time I had no idea what to do with it. The export part in the script tag is how we expose the component to be available for use in other components. I think?

The component for the done task is similar:

./assets/vue/components/Tasks/Done.vue

<template>
    <div>
        <strong><slot>An empty task</slot></strong>
    </div>
</template>
<script>
    export default {
        name: 'doneTask',
    }
</script>

To use these components we need to import them and list them under components within our component where we want to use them:

./assets/vue/components/Journal.vue

<script>
    import TodoTask from "./Tasks/Todo";
    import DoneTask from "./Tasks/Done";
    export default {
        name: 'journal',
        components: {
            TodoTask,
            DoneTask,
        },
        // Shortened the rest of it as nothing changed
    }
</script>

We take the name of the components we imported, turn them kebab-case, and use them as HTML tags. What we put between the opening and closing tags of our component will be inserted into the <slot> tag inside:

./assets/vue/components/Journal.vue

<template>
    <div>
        <template v-if="journal.tasks.length !== 0">
            <div v-for="task in journal.tasks">
                <todo-task v-if="task.status === 'todo'">{{ task.description }}</todo-task>

                <done-task v-if="task.status === 'done'">{{ task.description }}</done-task>
            </div>
        </template>
        <template v-else>
            <todo-task>An example of a todo task</todo-task>

            <done-task>An example of a done task</done-task>
        </template>
    </div>
</template>

Vue.js will make sure that we get the proper HTML rendered in the browser.

Events to the rescue

For a while I didn’t know what to do with the Mark as done button. The original implementation of the markTaskAsDone(taskId) method uses other methods local to the Journal component, so if I’d move that to the TodoTask child component, there’d be a mess on my hand real quick. I’ve tried passing in to the TodoTask a function from the parent component and a couple of other things…

Turns out the solution is quite elegant. On the button within the TodoTask we listen for the click event and trigger our own custom clickedToMarkTaskAsDone event:

./assets/vue/components/Tasks/Todo.vue

<template>
    <div>
        <button @click="clickedToMarkTaskAsDone">
            Mark as done
        </button>
        <span><slot>An empty task</slot></span>
    </div>
</template>
<script>
    export default {
        name: 'todoTask',
        methods: {
            clickedToMarkTaskAsDone: function () {
                this.$emit('clickedToMarkTaskAsDone');
            }
        }
    }
</script>

In the parent component where we use this TodoTask component, we create a handler for our custom event using the existing code we have:

./assets/vue/components/Journal.vue

<todo-task v-if="task.status === 'todo'" @clickedToMarkTaskAsDone="markTaskAsDone(task.id)">
    {{ task.description }}
</todo-task>

Nothing within the markTaskAsDone method changed.

The end result is much more nicer and the line count went down from a hundred to 25 lines. Isn’t that great? I think it’s great.

Happy hackin’!

Versions used for examples: Vue 2.5.
Tags: vue.js, reusable, components, javascript.
Categories: Programming, Development.

Accessing Symfony private services in Behat

published on February 01, 2019.

Since Symfony 3.4 the services in the service container are private by default. While this decision made us write better production code by making us use Dependency Injection more and rely on the service container less, using these services in a test environment proved to be a challenge.

Since Symfony 4.1 there’s a special service container in the test environment which allows fetching private services in tests.

In a Behat test this test service container is not available through the static::$container property as it is in a WebTestCase or a KernelTestCase, but it is available under the test.service_container name in the service container.

We need Symfony, Behat, and Behat Symfony2 extension with the Behat Symfony2 extension configured to bootstrap an instance of the App\Kernel for us:

./behat.yml

default:
    extensions:
        Behat\Symfony2Extension:
          kernel:
            bootstrap: features/bootstrap/bootstrap.php
            class: App\Kernel

    suites:
      system:
        paths:
          - '%paths.base%/features/system.feature'
        contexts:
          - SystemContext:
              kernel: '@kernel'

If the behat.yml example looks weird, I’m reusing it from my previous blog post on testing Symfony commands with Behat.

Now that we have injected the kernel into our Context file, we can get the service container from the kernel, and from that service container access the test.service_container:

./features/bootstrap/SystemContext.php

<?php

use App\Kernel;
use Behat\Behat\Context\Context;

class SystemContext implements Context
{
    public function __construct(Kernel $kernel)
    {
        $testContainer = $kernel->getContainer()->get('test.service_container');
        $someService = $testContainer->get(App\Some\Service\We\Need::class);
    }

The test service container has all the services public and we can access them without worrying if they are private or public.

If you’re project is still on Symfony 3.4 or Symfony 4.0, Tomas Votruba has a blog post explaining how to achieve something similar using a compiler pass.

Happy hackin’!

Versions used for examples: Symfony 4.1, Behat 3.4, Behat Symfony2 Extension 2.1.
Tags: symfony, behat, private services, testing, php.
Categories: Programming, Development.

Testing Symfony commands with Behat

published on January 18, 2019.

The other day I was creating a Symfony command that will be periodically executed by a cronjob. I decided to write a Behat test for it, to see what a test like that would look like. Plus, just because it is executed by the system from a command line, doesn’t mean we can skimp on the business requirements.

We need Symfony, Behat, and Behat Symfony2 extension. In the behat.yml file we configure the Behat extension to boot up the Kernel for us and pass it in is a constructor argument to our Behat Context:

./behat.yml

default:
    extensions:
        Behat\Symfony2Extension:
          kernel:
            bootstrap: features/bootstrap/bootstrap.php
            class: App\Kernel

    suites:
      system:
        paths:
          - '%paths.base%/features/system.feature'
        contexts:
          - SystemContext:
              kernel: '@kernel'

We enable and configure the Behat Symfony2 extension, and tell Behat that the system suite will use the system.feature feature file and the SystemContext context which takes one constructor argument, the kernel. I don’t like to put everything into the default FeatureContext for Behat, but rather split different contexts into, well, different contexts. That’s why I created the separate SystemContext.

The boostrap.php file is created when installing the extension (at least, it was created for me as I installed it using Symfony Flex):

./features/bootstrap/bootstrap.php

<?php
putenv('APP_ENV='.$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = 'test');
require dirname(__DIR__, 2).'/config/bootstrap.php';

The system.feature file doesn’t have much, just an example scenario:

./features/system.feature

Feature: System executed commands

  Scenario: Behat testing a Symfony command
    Given I am the system
    When I greet the world
    Then I should say "Hello World"

The SystemContext

The SystemContext file is where it gets interesting:

./features/bootstrap/SystemContext.php

<?php

use App\Kernel;
use Behat\Behat\Context\Context;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Output\BufferedOutput;
use Webmozart\Assert\Assert;

class SystemContext implements Context
{
    /**
     * @var Application
     */
    private $application;

    /**
     * @var BufferedOutput
     */
    private $output;

    public function __construct(Kernel $kernel)
    {
        $this->application = new Application($kernel);
        $this->output = new BufferedOutput();
    }

It implements the Behat Context interface so that Behat recognizes it as a context.

In the constructor we create a new console Application with the Kernel that the Behat Symfony2 extension created for us. We will use this application instance to run the command that we are testing. For all intents and purposes, this application instance acts the same as the application instance that gets created in the bin/console script that we usually use to run Symfony commands.

We also create a BufferedOutput in the constructor, that will hold the output that the command produces, which we can later on use to assert did the command produce the desired output.

Behat step definitions

The steps are defined like so (it’s in the same SystemContext.php file as the previous example):

./features/bootstrap/SystemContext.php

<?php

class SystemContext implements Context
{
    /**
     * @Given I am the system
     */
    public function iAmTheSystem()
    {
        Assert::same('cli', php_sapi_name());
    }

    /**
     * @When I greet the world
     */
    public function iGreetTheWorld()
    {
        $command = 'app:hello-world';
        $input = new ArgvInput(['behat-test', $command, '--env=test']);
        $this->application->doRun($input, $this->output);
    }

    /**
     * @Then I should say :sentence
     */
    public function iShouldSay($sentence)
    {
        $output = $this->output->fetch();

        Assert::same($sentence, $output);
    }

I am the system

In the first Behat step we assert that the PHP interface is the cli. Not sure how it could be anything else in this case, but let’s have that in there.

I greet the world

The second Behat step is where the fun part happens, where we run the command. The ArgvInput takes an array of parameters from the CLI in the argv format. In the case of bin/console it ends up being populated from $_SERVER['argv']. In this case though, we need to populate it on our own.

The first argument is always the name that was used to run the script and it ends up being just a “placeholder”, hence the behat-test value. We can put in anything there, really.

The second parameter is the command that we want to run: app:hello-world. It is the same string we would use when executing that command through bin/console. Because we created an instance of the Application in the constructor, Symfony will know exactly what command that is.

The third parameter is an option to tell Symfony to run the command in the test environment.

Once we have the input ready, we tell the application to run using the doRun method, passing in the input and the output (which is a BufferedOutput).

I should say :sentence

In the third Behat step we fetch the output and assert that it is the same as the output we expected it to be.

Make it reusable

To make it a bit more reusable, the running of the command in the iGreetTheWorld step can be extracted to a private method so that it all reads a little bit nicer. The final result looks something like this:

./features/bootstrap/SystemContext.php

<?php

use App\Kernel;
use Behat\Behat\Context\Context;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Output\BufferedOutput;
use Webmozart\Assert\Assert;

class SystemContext implements Context
{
    /**
     * @var Application
     */
    private $application;

    /**
     * @var BufferedOutput
     */
    private $output;

    public function __construct(Kernel $kernel)
    {
        $this->application = new Application($kernel);
        $this->output = new BufferedOutput();
    }

    /**
     * @Given I am the system
     */
    public function iAmTheSystem()
    {
        Assert::same('cli', php_sapi_name());
    }

    /**
     * @When I greet the world
     */
    public function iGreetTheWorld()
    {
        $this->runCommand('app:hello-world');
    }

    /**
     * @Then I should say :sentence
     */
    public function iShouldSay($sentence)
    {
        $output = $this->output->fetch();

        Assert::same($sentence, $output);
    }

    private function runCommand(string $command)
    {
        $input = new ArgvInput(['behat-test', $command, '--env=test']);
        $this->application->doRun($input, $this->output);
    }

Happy hackin’!

Versions used for examples: Symfony 4.1, Behat 3.4, Behat Symfony2 Extension 2.1.
Tags: symfony, behat, commands, bdd, testing, php.
Categories: Programming, Development.

A lookback on 2018

published on January 01, 2019.

2018 was a good year. A year of changes.

My wife and I are expecting a baby in March 2019. We bought a house. We traveled. We drank some lovely tea. We read books. We ate great food in good company. We made new friends in a new city.

I changed jobs. I spoke at four conferences, one uncon, and two meetups. I wrote a two part article on Mockery for phparch. I gave a talk at the new job how to better use test doubles. I became a Dungeon Master for my Dungeons & Dragons group.

Looking forward to 2019

I want to be home as much as possible with my wife and our kid, so I’ll continue working from home. I’m gonna dial it back on the conferences, so my only plan for this year is to visit the PHP Serbia conference in May. But the learning can’t stop, the plan is to redirect the conference budget to online courses and materials.

In 2019 I want to learn how not to create total shite User Experiences and User Interfaces on the web. Bought the Refactoring UI material as a first step. Started learning what makes a modern web app in this day and age. I’ll keep learning about Domain-Driven Design and do my best to implement what I’ve learned so far. Keep blogging about it all.

I want to pick up woodworking as a hobby. Together with the house we bought a bunch of tools from the previous owners, so now it’s just the matter of going down to the garage and practicing. I also want to create a herb garden.

Here’s to another amazing year.

Happy hackin’!

Tags: 2018, a good year, new house, new job.
Categories: Blablabla.
Robert Basic

Robert Basic

Software engineer, consultant, open source contributor.

Let's work together!

If you require outsourcing or consulting help on your projects, I'm available!

Robert Basic © 2008 — 2019
Get the feed