rendr
rendr is a scaffolding tool which allows generating entire projects (or anything else) from blueprints, using standard templating engines and simple customization via parameters. It is generic enough to apply to a wide variety of applications and tech stacks, but powerful and flexible enough to provide value, fast. The tool itself is really a generic template renderer. It's up to you, the template creator, to decide what to put in your template.
Use cases
Here are just a few possible use cases:
- Enable rapid spin-up of new projects, complete with CI/CD pipelines, code quality gates, security analysis, and more
- Ship "Hello, World!" projects immediately to production, enabling instant iteration on features
- Include CI/CD standards baked into projects from the start, easily kept up to date
- Simplify repeated patterns like creating new microservices, libraries, or submodules on an existing project
Contributing
Feedback and pull requests are welcome! Let us know if you have issues using the tool, or see use cases that are not yet supported. We'd love to expand its usefulness!
Installation
Homebrew
To install the latest release:
brew install jamf/tap/rendr
Cargo (from source)
Again, the latest release can be installed with:
cargo install rendr
Binaries for Linux and macOS
Alternatively, you can download the CLI binary directly from the Releases page and put it on your system path.
Rendering Blueprints
See the options
View the available commands with rendr --help
:
❯ rendr --help
A project scaffolding tool
USAGE:
rendr [SUBCOMMAND]
FLAGS:
-h, --help Prints help information
-V, --version Prints version information
SUBCOMMANDS:
create Creates a project from a blueprint
create-blueprint Creates a new blueprint scaffold
help Prints this message or the help of the given subcommand(s)
info Displays blueprint info for an existing project
To see usage for a subcommand, use rendr [command] --help
:
❯ rendr create --help
rendr-create
Creates a project from a blueprint
USAGE:
rendr create [FLAGS] [OPTIONS] --blueprint <blueprint> --dir <dir>
FLAGS:
--debug Enables debug logging
--git-init Initializes a Git repository in the rendered project
-h, --help Prints help information
--no-git-init Skips initializing Git repository in the rendered project
-V, --version Prints version information
-w, --watch After generating the project, watch the blueprint files for changes and regenerate the project
on change
OPTIONS:
-b, --blueprint <blueprint> The location of the blueprint (a Git repo or a local directory)
-d, --dir <dir> The output directory name
-n, --name <name> The name of the project
-p, --password <password> The password for Git authentication (insecure - use the GIT_PASS env var instead)
-k, --ssh-key <ssh-key> The path to the private SSH key for Git auth
-u, --user <user> The user for Git authentication
-v, --value <value>... Custom value provided the blueprint (flag may be repeated)
Render a project
Use rendr create
to render a project from a blueprint. The basic usage looks
like this:
rendr create --blueprint https://github.com/your/template --dir my-project
Provide custom values
By default, if you don't provide any values when running rendr create
, you will
be prompted for each required value. To provide values non-interactively, use
the -v
flag. This flag is repeated once for each value.
rendr create -b https://github.com/your/template -d my-project -v name:foo -v version:1.0.0
Important! A note about scripts
Blueprints can contain scripts that execute as part of the rendering process. Blueprint creators can use this mechanism to provide custom functionality when the blueprint is rendered, like creating a repository or configuring a CI pipeline. However, be careful to only use templates from trusted sources, as these scripts execute with the same privileges as the user that invoked them. A malicious template script could modify files on your system, send your personal data somewhere, install malware, etc.
Upgrading to a new blueprint version
If a new version is released of the blueprint used in your project, your
project can be easily upgraded using the rendr upgrade
command. Blueprint
authors can include new files, or make custom upgrades to existing files in a
project. The upgrade logic is entirely up to the blueprint author.
This is a powerful mechanism that allows maintaining common code, configuration and best practices across multiple codebases.
Use rendr upgrade --help
for more details on usage.
Blueprint developer mode
If you are developing a blueprint, you will likely want to edit your templates
and then render them to see the output, make more edits, render them again, in
a continuous loop. To make this easier, use the --watch
(-w
) flag for
rendr create
.
rendr create --blueprint ../my-blueprint --dir foo --watch
Output directory: "foo". Creating your new scaffold...
Success. Enjoy!
Watching for blueprint changes...
The next time you make changes to the files in the my-blueprint
directory,
the entire blueprint will be re-rendered automatically. Use Ctrl-C
to cancel
the watch command.
Creating blueprints
Blueprints consist of template files, scripts, and metadata.
- Template files live in the
template
directory, and are rendered by the templating engine - Metadata is provided in a
metadata.yaml
file in the root of the blueprint directory. It lists specific values that can be provided to the template, among other things. - Scripts live in a
scripts
directory in the blueprint directory. This is the place to customize the generated files or automate followup actions (like creating a remote repository or pipeline).
With these basic features, blueprints are already highly customizable! If you have other use cases that are not supported, feel free to let us know in the issues!
Template
Each blueprint has a template
directory at its root level. This directory
contains all the template files and directories that will be rendered into the
final project.
Template engine
The template engine used by rendr
is Mustache,
"The logic-less template engine". See the link for the (extremely simple)
Mustache manual and demos to get started.
To get started even without reading the manual, it's enough to know that
Mustache uses "tags", which are indicated by double "mustaches", like {{ name }}
or {{ my_custom_url }}
. When given a context of key/value pairs, Mustache
replaces the tags with the values from the context. For example, given this
template:
Hello {{ name }}!
and this context:
name:foo
will produce the following text:
Hello foo!
Pretty simple.
rendr
handles passing the context to the templating engine for you. The way
to provide values to the rendering context is by using rendr
's "values",
which are defined in the metadata.yaml
and provided by the user via prompts
or the --value
flag when rendering the blueprint. See the metadata
format and the command line usage for more details
there.
Sample template
directory
Here's a concrete example of creating templates in rendr
. We have a template
directory with just two files:
template
├── main.go
└── README.md
The README.md
has this for contents:
# Project {{ name }}
Welcome to your new project!
Please run `go run main.go` to run the app at http://localhost:{{ port }}.
You will notice that the template has two tags, name
and port
. These must
be defined in the metadata.yaml
file like this:
...
values:
- name: name
description: The name of the project
required: true
- name: port
description: The port where the app runs
default: "8000"
These values are then provided by the user rendering the blueprint like this:
rendr create --dir foo --blueprint <url> --value name:foo --value port:3000
This will result in all the files in the template
directory being rendered by
the template engine and copied into the specified new project directory (in
this case named foo
):
foo
├── main.go
└── README.md
The contents of the rendered README.md
look like this:
# Project foo
Welcome to your new project!
Please run `go run main.go` to run the app at http://localhost:3000.
Any files or directories you like can go in the template
directory, and they
will rendered into the generated project directory.
Excluding files
Sometimes your template will contain files that you don't want to render with
Mustache, and want them to be copied over to the rendered project without
modification. Some examples of this would be binary files like images, or
third-party files that are included in the project. These files can be excluded
by using the exclusions:
list in metadata.yaml
. See the
Metadata docs for details.
Dynamic file or directory names
Sometimes you want your rendered files or directories to have custom names
based on the values the user supplied. This can't be done using the Mustache
templating engine directly. The way to accomplish this is to rename the files
or directories in the post-render.sh
script. See Scripts for
more details.
Additional use cases
Between the Mustache templating and customization via pre- and post-render
scripts, rendr
provides immense flexibility to generate projects for nearly
any tech stack. If you have specific use cases that you find are not supported,
please open a issue over at the GitHub
Issues, describe your problem and what
functionality is missing, and we will consider it.
Support
Still need help or more examples? Open an issue at rendr
's GitHub
Issues and describe your problem, and
we'd be happy to help!
Metadata
Each blueprint has a metadata.yaml
file at its root level. This file defines
things like the blueprint name, version and description, as well as values
which the user can provide when rendering the blueprint.
Here is a simple example:
name: foo
version: 1
author: thecodesmith
description: A simple microservice blueprint
values:
- name: name
description: The name of your project
required: true
- name: port
description: The port where the service listens
default: "8000"
exclusions:
- "images/*"
Let's break it down:
Parameter | Description |
---|---|
name | The blueprint name |
version | The blueprint version |
author | The blueprint author |
description | The blueprint description |
values | A list of values that will be provided to the template rendering |
exclusions | A list of glob patterns to exclude from rendering |
upgrades | An optional list of upgrade scripts |
There can be any number of items in the values
list. The structure of each
item looks like this:
Parameter | Description |
---|---|
name | The value key name |
description | The description of this value; becomes the interactive prompt text |
required | Whether the value must be provided by the user (true or false ) |
default | The default value if one is not provided by the user |
The required
field defaults to false
, and can be omitted.
The default
field can also be omitted. If there is no default, the user will
be prompted for this value (if not provided with the -v
flag).
The upgrades
field can have any number of upgrade scripts in the list. The structure of
each upgrade script is like this:
Parameter | Description
version
| The blueprint version where this script will be run (format: integer)
script
| The name of the script file in the blueprint scripts
directory
executable
| The executable (program) to use to run the script
Scripts
Blueprints can optionally contain scripts. This is a powerful mechanism that enables blueprint creators to customize how the blueprint is rendered.
Scripts live in the scripts
directory at the root level of the blueprint.
Currently only pre-render.sh
and post-render.sh
scripts are supported. This
can be expanded in the future if there are other integration points where
scripts are useful.
The pre-render script
If a script named pre-render.sh
exists in the blueprint's scripts
directory, it will be run immediately after the generated project directory is
created, and before any template files are rendered.
The values used to render the template are also provided to the script as
environment variables. So, if a user specifies --value foo:42
, there will be
a variable named foo
that can be accessed in the script like this:
#!/bin/sh
echo "The value of foo is $foo!"
This script will print:
The value of foo is 42!
NOTE: The script must be executable to be run. Make it executable like this:
chmod +x scripts/pre-render.sh
The post-render script
If there is a script named post-render.sh
in the blueprint's scripts
directory, it will be
run automatically after the template files are rendered by the templating engine.
Use the post-render script to customize files and directories, or to create remote repositories, CI/CD pipelines, etc.
For more details, see the notes above on the pre-render
script regarding
environment variables and executable file permissions, which apply here just
the same.
Development
This chapter includes information pertaining to rendr
contributors.
Local iteration
You'll need Rust and Cargo. You can get the whole toolchain here!
After checking out this repository, cd
into the directory. You can use the standard Cargo commands. Below you'll find the most important ones.
Compile the whole project
This should get you the usual dev build.
cargo build
This one is the same, but it produces an optimized release build. It takes more time.
cargo build --release
Tests
Run the unit tests and documentation tests.
cargo test
Docs
Build the reference manual and open it in your browser.
cargo doc --open
Run the application
Run the application.
cargo run
Get the helpfile.
cargo run -- -h
Get the help text for the create
subcommand.
cargo run -- create -h
Initialize a project from the Go microservice blueprint.
cargo run -- create --blueprint https://github.com/jamf/rendr-sample-blueprint-go-microservice.git --dir my-project -v name:foo