Streamlining Development with Custom Shell Functions: Reusing a command with a custom config for each project
As a freelance technical agile coach, working across multiple projects means dealing with a variety of tech stacks. Every client has their own preferred tools, some with Docker, some without, and often there are custom setups or hacks. Over time, managing these different workflows can become mentally exhausting. You don’t want to waste time remembering specific commands for each environment or tool every time you start a project.
To solve this, I’ve created custom shell functions to simplify and streamline my workflow. These helpers sit on top of the usual tools, allowing me to invoke commands without remembering intricate details or worrying about specific configurations for each project.
Here’s how I did it.
Example: Custom Shell Function Command for PHPUnit
Here’s an example of a custom bash function I’ve written for PHPUnit. This function is placed in my shell alias file.
phpunit() {
if [ -f "./my-conf" ]; then
cmd=$(grep ^PHPUNIT ./my-conf | awk -F"PHPUNIT=" '{print $2}')
fi
if [ ! -z "$cmd" ]; then
eval $cmd $@
elif [ -f "my-phpunit.xml" ]; then
vendor/bin/phpunit -c my-phpunit.xml $@
else
vendor/bin/phpunit $@
fi
}
Breaking it down:
- Check for a custom configuration file: The function first looks for a file called
my-conf
in the current project directory. This file can override the default behavior by specifying custom commands. - Extract custom PHPUnit command: If
my-conf
contains a line starting withPHPUNIT=
, the script grabs that line and usesawk
to extract the command that follows. This allows me to define a custom PHPUnit command per project if necessary. For instance, some projects require running PHPUnit inside a Docker container; I just don’t want to have to think about that. - Execute the custom command if found: If a custom PHPUnit command is found, it is executed using
eval
. - Fallbacks to default behavior:
- If no custom command is found, the function checks for a
my-phpunit.xml
configuration file and runs PHPUnit with that. I don’t remember why I put that in, as it supposed to be the default PHPUnit behavior. No code is perfect, and at least you get the idea if you want to include some configuration in your command by default. - If neither is available, it runs the default PHPUnit command from the vendor folder.
- If no custom command is found, the function checks for a
This setup allows me to run PHPUnit across multiple projects without having to remember specific configurations for each one.
I’ve created such function for every tool that is reused accross project
The my-conf
File: Customizing Behavior for Each Project
In each project, I can create a my-conf
file that overrides the default behavior for specific tools. This file is included in my global .gitignore
, so it doesn’t get committed to version control.
Here’s an example of what a my-conf
file might look like for a Laravel project using Sail and Docker:
PHPSTAN=sail php ./vendor/bin/phpstan --memory-limit=-1
RECTOR=docker compose -f my-docker-compose.yml run --rm -it rector ./bin/rector
COMPOSER=sail composer
PHPUNIT=./bin/phpunit
In this example, I have custom commands for various tools like PHPStan, Rector, Composer, and PHPUnit. This file allows me to run these commands seamlessly without having to think about whether I need to use Sail or Docker in a specific project.
Why Use Custom Shell Functions?
Using custom shell functions gives me several key advantages:
- Consistency: I can run the same command across different projects without worrying about project-specific details.
- Efficiency: With these helpers in place, I don’t have to spend mental energy remembering how each tool is configured in each project.
- Flexibility: I can easily adapt to new client setups by modifying the
my-conf
file without touching the global setup. - Collaboration: Teams can have their own configurations, while I keep my personalized workflow without impacting theirs.
Conclusion
By creating custom shell functions for tools like PHPUnit, Composer, PHPStan, and others, I’ve streamlined my workflow significantly. These helpers give me the flexibility to work across multiple projects with different setups, while maintaining a consistent and efficient workflow.
If you’re working across multiple projects and stacks like me, this method can save you valuable time and mental energy. And if your team isn’t quite ready to adopt these shortcuts, no worries — you can keep them in your local environment without disrupting the broader team workflow.
Want to streamline your team’s workflow or improve your technical agility? Book a session with me here and let’s discuss how we can make your development process smoother.