Skip to content

awslabs/aws-code-habits

Repository files navigation

logo

TestGitHub IssuesGitHub Starshygiene

AWS Code Habits

A library of Make targets, Ansible playbooks, and Jinja templates that you add to a project as a Git submodule to standardize common development tasks.

screenshot-1
Installing AWS Code Habits

Overview

AWS Code Habits is a reusable library you embed in your own repository. It groups everyday development tasks behind consistent make targets so that every contributor runs the same commands to install tools, format code, run linters, manage infrastructure, and generate documentation.

The library has three parts:

  • Make targets under lib/make/ provide the commands you run, such as terraform/plan, python/test, and doc/build.
  • Ansible playbooks under lib/ansible/ perform multi-step actions, such as scaffolding .github/ directories and rendering the README.
  • Jinja templates render files such as README.md from data in doc/habits.yaml.

You add the library to a project as a Git submodule (or as a vendored copy) and include its Make targets from your own Makefile. It is intended for teams that want a shared, version-controlled set of development commands across many repositories.

The following diagram shows how your project consumes the library:

flowchart LR
    project["Your project"]
    makefile["Your Makefile<br/>includes lib/make/*/*.mk<br/>and lib/make/*.mk"]
    targets["make targets<br/>(terraform/plan, python/test, doc/build)"]
    tools["Tools<br/>(Terraform, AWS CDK, Python, Node.js, Go)"]
    ansible["Ansible playbooks<br/>(lib/ansible/)"]

    project --> makefile
    makefile -->|include .mk glob| targets
    targets -->|run a tool directly| tools
    targets -->|multi-step actions| ansible
Loading

Features

  • Run common tasks through consistent make targets across repositories.
  • Install and pin developer tools (Terraform, AWS CDK, Python, Node.js, Go, and more) through dedicated targets.
  • Generate README.md from a single source file, doc/habits.yaml.
  • Scaffold project files: .gitignore, pre-commit configuration, and .github/ directories for actions, workflows, issues, and pull requests.
  • Gate destructive targets behind a confirmation prompt and verify downloaded binaries with optional SHA256 checks. See docs/HARDENING.md.

Prerequisites

The library supports Linux, macOS, and Windows (with some limitations). Many targets include cross-platform detection and use the appropriate installation method for the host.

You need the following installed before you use the library:

  • Python 3 — used by several targets and by the documentation tooling.
  • pip — the Python package installer.
  • GNU Make — runs the targets the library defines.

Installation

You use AWS Code Habits as a Git submodule. From the root directory of your project, run:

git submodule add --name habits -b main https://github.com/awslabs/aws-code-habits.git habits

This clones the library into a habits/ directory that tracks the main branch.

Pin the submodule to a release. Tracking main exposes you to unannounced changes. After you add the submodule, check out a tagged release (or a specific commit SHA) and commit the resulting submodule pointer:

git -C habits fetch --tags
git -C habits checkout v1.5.0   # or any tag from CHANGELOG.md
git add habits && git commit -m "chore: pin habits to v1.5.0"

See CHANGELOG.md for available releases. To move to a newer release later, repeat the checkout step against a newer tag.

When you next clone your repository, pass --recurse-submodules so the submodule is fetched:

git clone --recurse-submodules <your-repository-url>

If you already cloned the repository without --recurse-submodules, initialize and fetch the submodule with:

git submodule update --init --recursive

To automate the installation steps, use the helper scripts in the scripts/ directory.

Getting started

  1. Add the submodule with the command in Installation.

  2. Create a Makefile in your project root (or add these lines to an existing one):

    export WORKSPACE = $(shell pwd)
    export HABITS = $(WORKSPACE)/habits
    
    include $(WORKSPACE)/tools.env # pin the version of your tools
    
    include $(HABITS)/lib/make/*/*.mk
    include $(HABITS)/lib/make/*.mk
  3. List the available targets:

    make help

    You see a list of targets with one-line descriptions:

    Available targets:
    
      doc/build                           Builds documentation
      doc/init                            Initialize documentation
      habits/check                        Performs checks
      ...
    

Usage

List every target with the default help target:

make help

For the full target reference, see Makefile.md.

Several technology-specific Makefiles add their own help target:

make terraform/help
make nodejs/help
make python/help
make go/help
make gitignore/help

Initialize pre-commit configuration

Create a .pre-commit-config.yaml in your working directory:

make pre-commit/init

Run all pre-commit hooks against every file:

make pre-commit/run

Maintain documentation

  1. Initialize the documentation files. This creates a doc/ directory containing habits.yaml:

    make doc/init
  2. Edit doc/habits.yaml, then rebuild the README:

    make doc/build

README.md is rendered from doc/habits.yaml. Do not edit README.md by hand — your changes are overwritten on the next make doc/build.

Compose your own targets

Add aggregate targets to your Makefile that call library targets. For example, to combine documentation and pre-commit checks:

.PHONY: hygiene
hygiene: doc/build pre-commit/run

To drive an AWS CloudFormation workflow:

.PHONY: hygiene
hygiene: aws/cloudformation/hygiene

.PHONY: plan
plan: aws/cloudformation/create-change-set

.PHONY: discard
discard: aws/cloudformation/delete-change-set

.PHONY: apply
apply: aws/cloudformation/execute-change-set

Use technology-specific targets

Each technology groups its targets under a common prefix.

Terraform:

make terraform/install
make terraform/init
make terraform/plan
make terraform/apply
make terraform/workspace/list
make terraform/workspace/new WORKSPACE_NAME=dev

AWS Cloud Development Kit (AWS CDK):

make aws/cdk/install
make aws/cdk/bootstrap
make aws/cdk/deploy
make aws/cdk/synth

Python:

make python/install
make python/virtualenv/init
make python/poetry/install
make python/poetry/init
make python/test

Node.js:

make nodejs/install
make nodejs/init/express
make nodejs/init/react
make nodejs/init/vue
make nodejs/add PACKAGE=express
make nodejs/add/dev PACKAGE=jest

Go:

make go/install
make go/app/build OUTPUT=myapp
make go/app/test

Gitignore:

make gitignore/init/web
make gitignore/init/python
make gitignore/init/node

Run checks

Verify that a project has the files the library expects:

make habits/check

Run technology-specific tests:

make python/test
make python/test/coverage
make nodejs/test
make go/app/test
make go/app/test/coverage

Configuration

You configure the library through environment files that your Makefile includes and through variables you pass on the command line.

  • tools.env — pins tool versions. Every *_VERSION variable uses ?=, so a value you set in tools.env overrides the default.
  • *_SHA256 variables — when set, the matching tool installer verifies the downloaded archive with sha256sum -c and aborts on mismatch. When unset, the installer prints a warning and proceeds.
  • CONFIRM — set CONFIRM=yes to skip the confirmation prompt on destructive targets, for example in continuous integration.

Destructive targets are gated behind a confirmation prompt: terraform/apply, terraform/destroy, aws/cdk/destroy*, nuke/run, docker/remove-images, docker/remove-volumes, and docker/prune. For the full list of safety variables and recommended values, see docs/HARDENING.md.

How it works

You include the library's .mk files from your Makefile. Each .mk file under lib/make/ defines targets for one tool or technology. Targets that perform multi-step actions, such as doc/build and doc/init, delegate to Ansible playbooks under lib/ansible/.

README.md is generated. The doc/build target runs an Ansible playbook that renders the Jinja template lib/ansible/templates/readme.j2 using the data in doc/habits.yaml, then writes the result to README.md.

The following diagram shows the documentation render pipeline:

flowchart LR
    cmd["make doc/build"]
    target["doc/build target<br/>(lib/make/doc.mk)"]
    playbook["Ansible playbook<br/>(lib/ansible/playbooks/doc/build.yaml)"]
    data["doc/habits.yaml<br/>(source data)"]
    template["readme.j2<br/>(lib/ansible/templates/)"]
    readme["README.md<br/>(generated)"]

    cmd --> target
    target --> playbook
    data --> playbook
    template --> playbook
    playbook -->|render| readme
Loading

Contributing

See Contributing.

Security

See Security to report a vulnerability. Do not file public GitHub issues for security reports.

License

This project is licensed under the MIT-0 License. See the LICENSE file.

Copyright

Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.

About

A library with Make targets, Ansible playbooks, Jinja templates (and more) designed to boost common software development tasks and enhance governance.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

86 stars

Watchers

3 watching

Forks

Packages

 
 
 

Contributors