Switching to a new workstation can be a painful process until you manage to have the exact same setup you did in the previous one.
The last time I was about to upgrade my workstation I began by analyzing which stuff I had installed, which I'd need in the new one and I came up with a list (this recent post goes over most of them).
It wasn't that long but installing everything manually felt like a waste of time, especially because eventually I'd have to upgrade the OS through an installation from scratch or even switch to a newer workstation again.
So I began to look for how did everyone else automate their development environment setup. Most examples were using bash scripts but I also found some that were using Ansible, a configuration management tool like Puppet or Chef. I started reading a bit about it and then focused on how to configure a local machine instead of a remote server, which is the common scenario.
I'm not gonna get into much details about Ansible itself, mainly because my only experience with it is building the playbooks (Ansible's configuration language) to automate the setup of my development environment. All I can say about it is that it makes installation and configuration much easier than, say, using bash scripts.
For instance, the following playbook installs a debian package using apt-get
, through the apt
module:
The key here is that you can parametrize it using the with_items
loop statement:
Ansible also allows to combine playbooks so, for instance, the list of packages to install can be defined in a separate file and included in others.
The applications and tools to be installed may be distributed differently:
apt-get
tar.gz
filesThat implies that each type of distribution method requires specific installation steps. After having the applications and tools installed, we can also apply a custom configuration like setting up our own dot files.
I chose to separate the installation steps from the actual things to be installed. In the vars.yml
file I defined the list of stuff to install (for convenience, this is just an excerpt):
Installing debian packages requires:
The apt_key
, apt_repository
and apt
modules, respectively, let you do that:
On the other hand, manually installed debian packages require:
.deb
filesThe apt
module can install the package from a local .deb
file, which is automatically downloaded if we specify it as an URL:
The applications packaged as tar.gz
files usually contain a root folder related to the application version (i.e. myApp.2.3.1_build33
). That folder might be referenced somewhere else, like a shortcut or a command, and that's likely to break if we upgrade the application. In this case I added an indirection layer using a symlink.
An example of this is IntelliJ IDEA:
tar.gz
file you can download is named ideaIC-2016.3.2.tar.gz
idea-IC-163.10154.41
ideaIC
-> idea-IC-163.10154.41
Thus, the process must:
tar.gz
filesThe get_url
module allows you to download a remote file and the unarchive
module lets you extract a compressed file. Finally, with the file
module you can create a symlink specifying the state=link
property:
Installing the binaries requires:
/usr/local/bin
folderWith the get_url
module you can download a remote file to the desired local folder and make it executable specifying the mode=0755
property, all at once:
I use SDKMAN!, a tool for managing parallel versions of multiple SDKs, to install Java, Sbt and Maven. To be able to do so you have to:
In this case, the installation and configuration is done entirely with bash scripts.
This is the most specific part, because it depends on the degree of customization to apply. I do the following:
zsh
as the default shellzsh
and place the completion files there (for docker-compose
, hub
and sdk
)oh-my-zsh
by cloning its repo and symlink my custom theme.zshrc
, .gitconfig
, .aliases
.config
folder and symlink configuration files for terminator
idea
's desktop file so the application appears in the HUDguake
's autostart fileStarting with a freshly installed OS we need to bootstrap the automated setup process. Since the Ansible scripts are stored in a GitHub repository we need to begin with:
git
and ansible
Those are the steps that the bootstrap.sh
file performs:
While I was developing these scripts I had to execute them a gazillion times, and each and every time I had to:
bootstrap.sh
filebootstrap.sh
file content to the new fileThat was clearly improvable, so I googled how to execute a remote bash script and ended up with this:
wget -qO- https://raw.github.com/pbassiner/dev-env/master/bootstrap.sh | bash
After that, running the scripts was just:
README
file)In order to test any changes in the scripts, while keeping the master
branch as the working version, the bootstrap.sh
file allows to define the branch to use with -b|--branch <BRANCH>
(default is master
).
The Ansible playbooks I wrote also take care of updating the dependencies. After the initial setup, running again the bootstrap.sh
file will handle the upgrades of the applications and tools (you can check the complete bootstrap.sh
file here).
Anyway, from time to time I still have to check for updates of the manually installed packages.
Would you like to leave a comment? Since this blog is hosted on GitHub Pages there's no straightforward way to do so.
Instead, you can add a comment in this GitHub issue. If you'd like to see it here, refresh this page after posting the comment.