Giter Club home page Giter Club logo

mbt's Introduction

mbt

mbt

Build utility for monorepos

Build Status Build status Go Report Card Coverage Status

Monorepo Build Tool (mbt) is a utility that supports differential builds, dependency tracking and metadata management for monorepos stored in git.

In the context of mbt, term 'Module' is used to refer to a part of source tree that can be developed, built and released independently. Modules can be built with different programming languages and their native build tools.

For example, a repository could have .NET modules built with msbuild and NodeJS modules built with npm scripts. Module developers should be able to use the build tools native to their tool-chain.

Each module in a repository is stored in its own directory with a spec file called .mbt.yml. Presence of the spec file indicates mbt that the directory contains module and how to build it.

Spec File

.mbt.yml file must be in yaml and has the following structure.

name: module-a      # name of the module
build:              # list of build commands to execute in each platform
  darwin:
    cmd: npm        # build command
    args: [run, build]    # optional list of arguments to be passed when invoking the build command
  linux:
    cmd: npm
    args: [run, build]
  windows:
    cmd: npm
    args: [run, build]

In the preceding spec file, we are basically telling mbt that, module-a can be built by running npm run build on OSX, Linux and Windows. With this committed to the repository, we can start using mbt cli to build in several ways as shown below.

# Build the current branch 
mbt build branch --in .

# Build a specific branch
mbt build branch feature --in .

# Build only the modules changed in a specific branch relative to another
mbt build pr --src feature --dst master --in .

# Build only the modules changed between two commits
mbt build diff --from <commit-sha> --to <commit-sha> --in .

Currently, all mbt commands interrogates the git repository for source files required by the operation. Therefore, side effects of un-committed changes will not be visible.

Dependencies

Sometimes a change to a module could require the build of the modules that depend on it. We can define these dependencies in .mbt.yml files and mbt takes care of triggering the build in the topological order.

For example, module-a could define a dependency on module-b, so that any time module-b is changed, build command for module-a is also executed.

name: module-a 
dependencies: [module-b]

One example of where this could be useful is shared libraries. A shared library could be developed independently of its consumers. However, all consumers gets automatically built whenever the shared library is modified.

Another situation could be where one module is a single page web app and the other module is the back-end API and the host application of that. It's a prevalent model to develop such modules in different programming languages and usually host app build contains the steps to pack the web app into the deployment package. Using the dependency feature, host module could depend on the client app module so that anytime the web app changes the host module is also built.

Build Environment

When mbt executes the build command specified for a module, it sets up several important attributes as environment variables. These variables can be used by the actual build tools in the process.

Variable Name Description
MBT_MODULE_NAME Name of the module
MBT_MODULE_VERSION SHA1 hash calculated based on the content of the module directory and the content of any of its dependencies (recursively)
MBT_BUILD_COMMIT Git commit SHA of the commit being built

In addition to the variables listed above, module properties (arbitrary list of key/value pairs described below) is also populated in the form of MBT_MODULE_PROPERTY_XXX where XXX denotes the key.

One useful scenario of these variables would be, a build command that produces a docker image. In that case, we could tag it with MBT_MODULE_VERSION so that the image produced as of a particular Git commit SHA can be identified accurately. (We will also discuss how this information can be used to automatically produce deployment artifacts later in this document)

Describing the Change

When working in a dense, modular codebase it is sometimes important to assess the impact of your changes to the overall system. Each mbt build command variation has a mbt describe counterpart to see what modules are going to to be built. For example, to list modules affected between two git branches, we could run:

mbt describe pr --src <source-branch-name> --dst <destination-branch-name> --in .

Furthermore, you can specify --json flag to get the output of describe formatted in json so that it can be easily parsed and used by tools in the rest of your CD pipeline.

Going Beyond the Build

mbt produces a data structure based on the information presented in .mbt.yml files. That is what basically drives the build behind scenes. Since it contains information about all modules in a repository, it could also be useful for producing other assets such as deployment scripts. This can be achieved with mbt apply command. It gives us the ability to apply module information discovered by mbt to a go template stored within the repository.

As a simple but rather useless example of this can be illustrated with a template as shown below.

{{ $module := range .Modules }}
{{ $module.Name }}
{{ end }}

With this template committed into repo, we could run mbt apply in several useful ways to produce the list of module names in the repository.

# Apply the state of master branch
mbt apply branch --to <path to the template> --in <path to repo>

# Apply the state of another branch
mbt apply branch <branch-name> --to <path to the template> --in <path to repo>

# Apply the state as of a particular commit
mbt apply commit <git-commit-sha> --to <path to the template> --in <path to repo>

Output of above commands written to stdout by default but can be directed to a file using --out argument.

It's hard to imagine useful template transformation scenarios with just the basic information about modules. To make it little bit more flexible, we add a couple user-defined properties the data structure used in template transformation. First one of them is called, .Env. This is a map of key/value pairs containing arbitrary environment variables provisioned for mbt command.

For example, running mbt command with an environment variable as shown below would make the key TARGET available with value PRODUCTION in .Env property.

TARGET=PRODUCTION mbt apply branch --in .

Second property is available in each module and can be specified in .mbt.yml file.

name: module-a
properties:
  a: foo
  b: bar 

module-a shown in above .mbt.yml snippet would make properties a and b available to templates via .Properties property as illustrated below.

{{ $module := range .Modules }}
{{ $module.Properties["a"] }} {{ $module.Properties["b"] }}
{{ end }}

More realistic example of this capability is demonstrated in this example repo. It generates docker images for two web applications hosted in nginx, pushes them to specified docker registry and generates a Kubernetes deployment manifest using mbt apply command.

CLI Documentation

Complete documentation

Demo

asciicast

Install

curl -L -o /usr/local/bin/mbt [get the url for your target from the links below]
chmod +x /usr/local/bin/mbt

Builds

OS Download
darwin x86_64 Download
linux x86_64 Download
windows Download

This blog post covers some initial thinking behind the tool.

Credits

mbt is powered by these awesome libraries

Icons made by Freepik from www.flaticon.com is licensed by CC 3.0 BY

mbt's People

Contributors

buddhike avatar dvrkps avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.