About midway through 2018 we reached a few of the milestones we were looking for:

Over 5,000 monthly active users

Breaking more things than we were fixing on each release

High levels of technical debt

More support requests than we could handle

While the amount of monthly active users and support requests were very surprising (and encouraging) to us the other two were not because SPOILER ALERT: our beta releases were essentially proof of concepts; prototypes hacked together to demonstrate whether people actually wanted something like Lando or not. Our conclusion from this data was that not only do the people want something like Lando but they crave it.

Since then we've been listening to users and heeding their advice as we try to lock down the core set of Lando's functionality and figure out what we needed to do to take Lando to the next level. This has been a very enlightening process, aided by the lessons learned during the Kalabox project and culminating in this release.

At time of writing Lando has peaked very close to 9,000 monthly active users and has averaged around 8,000 for the last quarter or so.

We never dreamed we'd have this many users before a stable release and have been working very hard to cut a release that lays the foundation for more growth and adoption in the future.

Speaking of new foundations we'd like to tell you all what we've done to prep Lando for a stable release and beyond...

Reducing Techincal Debt

Hitherto, and as mentioned above, Lando has been essentially a prototype. We've been haphazardly pushing up new code while leaving no thought for the morrow as we try to confirm the features users need to be successful developing their projects. That process, while important and illuminating, resulted in a massive amount of techincal debt.

Lando RC2 is in many ways a bottom-up rewrite to address this problem; to consolidate code around an emergent set of community-agreed-upon features.

Believe it or not the technical debt ratio at the beginning of 2018 was actually around 60%!.

While this reduction has been much needed we've implemented CI tests to make sure no new code introduced into Lando increases its technical debt beyond an unacceptable threshold.

Locking Down the API

Refactoring the code to reduce technical debt and getting a better sense of the core features means we can now also provide better docs and API stability. To that end you can now read our lips when we say no new breaking changes.

This means that RC2, while still not a stable release, will not be changing its core syntax and will guarantee backwards compatibility here on out.

Config Docs

API Docs

We've put in a ton of effort to document and test the above so there is a considerable amount of inertia required to substantially change any of them. This means that you can count on our laziness for future stability.

Testing

While reducing techincal debt was important to make things simpler, more stable, more mangeable and more maintainable, good testing was equally critical to identify regressions and ensure that things remain simple, stable, manageable and maintainable.

To that end we've implemented both unit and functional tests.

Unit Tests

We don't have 100% coverage yet but we are covering the most important things.

Functional Tests

We wrote our own functional testing framework called leia to help us do functional testing. Leia helps us ensure that Lando is the real hero we all know him to be. Leia uses markdown files and bash commands to do functional testing.

Here is a sample screenshot of one part of one test we run on one of the 10 concurrent CircleCI machines that run on every build.

Tooling

Native command emulation

One of the most common uses of tooling is to emulate native commands like php, composer or yarn.

tooling:php:service: appserver

The above will run php inside of the appserver and also pass in any additional args or options you specify. That means that you can run lando php in the exact same way as php. This greatly reduces the hassle involved in invoking said commands directly with docker, docker-compose or even lando ssh. See below:

Note that each line of the above runs in a separate subshell so if you source a file in the first command like we unwisely did above it's not going to be available in any of the others. If you need that sort of behavior consider something like this instead

Multi-service Multi-command tooling

You can also omit the service and define cmd as an array of objects where the key is the service and the value is the command. This can allow you to consolidate complex testing and build steps that need to happen across many different services.

It also allows you to reuse a common interface across many different Landofiles, eg lando test may differ from project to project but it's always what we use to run our tests.

Dynamic service commands

Sometimes you have, need, or want a single command that can be used on a user-specified service. In these situations you can tell Lando to set the service with an option.

Note that the : prefix is what tells Lando to use an option instead of a literal string. Also note that you should be careful to avoid collisions between options you specify and options the underlying command does.

tooling:php-version:service::service
cmd: php -v
options:service:default: appserver
describe: Run php in different service

# Get the version in the appserver
lando php-version
# Get the version in the second appserver
lando php-version --service appserver2
# Get the version in the third appserver
lando php-version --service appserver3

This can help avoid the following messy and hard-to-scale implementation

Options driven tooling

You can also define your own options for use in tooling. These options follow the same spec as Lando tasks and are generally used in combination with an underlying script.

Note that the options interface just provides a way to define and then inject options into a given command. It is up to the user to make sure the underlying command or script knows what to do with such options. Note that if you use interactive options you need to set level: app as below.

More Landofiles

You can now use pre and post Landofiles to set base and overrides configurations. You can do the following things:

Base File

If you are developing a project start state or have a set of Lando configurations you'd like to ship with all your projects you can use a "base" file with defaults that can then be overriden by your usual .lando.yml. By default Lando will detect any of the following files automatically and load them before your .lando.yml

.lando.base.yml
.lando.dist.yml
.lando.upstream.yml

Override File

On the flip side you might have some user-specific configuration you'd like to use on only your computer. For these situations Lando similarly offers an "override" file that will be loaded AFTER all base files and your .lando.yml. Generally you will want to .gitignore this file.

.lando.local.yml

Restart vs. Rebuild

If you change your Landofiles you now need to explicitly run lando rebuild instead of running lando restart. This helps to provide stability between restarts until you explicitly ask for things to change and vastly speeds up stops and starts.

old

changed .lando.yml

lando restart

new

changed .lando.yml

lando rebuild -y

Lando init

We've completely reworked lando init to be more modular and intuitive. This means if you've got scripts relying on lando init you will likely need to make some changes. While there are many changes the biggest are the removal of the "init method" in favor of the --source option.

old

lando init pantheon

new

lando init --source pantheon

No Registry

There is no longer a register of apps stored at ~/.lando/cache/registry. As a consequence you can no longer do things like lando start MYAPP

old

lando start MYAPP

new

cd /path/to/MYAPP
lando start

Environment Files

You now have to explicitly set the top level env_file if you want to load a env file.

old

Had a .env file in Lando root directory

new

env_file:- .env

Drush Handling

We've vastly simplified our Drush handling. You can now only set drush to a particular version for global installation. If you've installed drush via composer then Lando will use that version instead of the one in your Landofile.

old

recipe: drupal8
config:drush: none

recipe: drupal8
config:drush: composer

recipe: drupal8
config:drush: /path/to/my/drush

new

recipe: drupal8

recipe: drupal8
config:drush: 8.1.15

Global Opts

Lando no longer uses -- to differentiate between its options and tooling options.

Plugins

If you have written your own custom plugins

Sorry!! :/

Once you see the new format you'll feel better :)

We've finally locked down a Plugin System that uses the Lando and App APIs and while we still don't have a great way to manage the installation and management of these plugins, it is going to be the defining feature of 3.1.0.