.
Tools Container
A development environment that helps you become a better developer using Git pre-commit hooks
๐ Introduction
This is an example repository showing how to use Git pre-commit to help you become a better developer. The container supports multiple operating systems and architectures (Windows, Linux, Mac - Intel and ARM chipsets).
It performs useful checks such as validating YAML and JSON syntax, while also helping you stay secure by scanning your repository for AWS credentials and SSH private key files.
๐ ๏ธ Installation
You will need the following tools to get started before you can use this repo and commence local development:
- Docker Desktop
- Visual Studio Code (with Remote Development in Containers extension)
- Git
- Pre-Commit
Build Agent Requirements
For CI/CD pipelines, you'll need these tools on your build agent:
- Git
- Docker Daemon
- Docker Compose
๐ CI/CD Integration
Sample GitLab Build Pipeline
Here's a sample GitLab pipeline that only requires Docker and Docker Compose on the build agent. All commands execute within the Docker container, minimizing your dependency toolchain.
.gitlab-ci.yml
:
[filename](gitlab-ci.yml ':include :type=code yaml')
๐ณ Dockerfile
The Dockerfile installs all necessary tools such as Terraform, kubectl, AWS CLI, Google Cloud CLI, Azure CLI, and more:
[filename](Dockerfile.txt ':include :type=code docker')
๐งช Pre-Commit
Pre-commit is a framework for managing and maintaining multi-language pre-commit hooks.
.pre-commit.yaml
:
[filename](pre-commit-config.yaml ':include :type=code yaml')
You can add your own pre-commit hooks, and there is support for all operating systems and most languages.
๐ Supported Tools
Tool | Included |
---|---|
Azure CLI | โ |
Google Cloud CLI | โ |
AWS CLI | โ |
Kubectl | โ |
DBT | โ |
Terraform | โ |
Terragrunt | โ |
TFENV | โ |
Python | โ |
Pip | โ |
Packer | โ |
Cookiecutter | โ |
Pre-Commit | โ |
๐ป Operating System & Architecture Support
OS | AMD64 | ARM64 |
---|---|---|
Linux | โ | โ |
macOS | โ | โ |
Windows | โ | โ |
๐ Features
- Dockerfile for local development and testing
- Pre-Commit Git hooks (pre-commit.com and antonbabenko/pre-commit-terraform)
- GitLab Pipeline configuration
- Terraform Docs integration
- Example Terraform Module
- Multi-OS (Linux, macOS) and Multi-Architecture (AMD64 and ARM64) support
๐ฆ Pre-Commit Examples
Example: Failed Commit
git commit -am "update default tgenv to amd64"
check for added large files..............................................Passed
check for merge conflicts................................................Passed
check vcs permalinks.....................................................Passed
forbid new submodules................................(no files to check)Skipped
don't commit to branch...................................................Failed
- hook id: no-commit-to-branch
- exit code: 1
fix end of files.........................................................Passed
trim trailing whitespace.................................................Passed
check yaml...........................................(no files to check)Skipped
check for merge conflicts................................................Passed
check for broken symlinks............................(no files to check)Skipped
check json...........................................(no files to check)Skipped
check for case conflicts.................................................Passed
mixed line ending........................................................Passed
detect aws credentials...................................................Passed
detect private key.......................................................Passed
Terraform fmt........................................(no files to check)Skipped
Terraform docs.......................................(no files to check)Skipped
Lint Dockerfiles.........................................................Passed
Fixing the Error
Create a feature branch instead of committing to main:
git checkout -b feature/pre-commit
Example: Successful Commit
git commit -am "fix pre-commit dont commit to branch"
pre-commit installed at /home/ubuntu/.git-template/hooks/pre-commit
[INFO] Initializing environment for https://github.com/pre-commit/pre-commit-hooks.
[INFO] Initializing environment for https://github.com/antonbabenko/pre-commit-terraform.
[INFO] Initializing environment for https://github.com/hadolint/hadolint.
[INFO] Installing environment for https://github.com/pre-commit/pre-commit-hooks.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
check for added large files..............................................Passed
check for merge conflicts................................................Passed
check vcs permalinks.....................................................Passed
forbid new submodules................................(no files to check)Skipped
don't commit to branch...................................................Passed
fix end of files.........................................................Passed
trim trailing whitespace.................................................Passed
check yaml...........................................(no files to check)Skipped
check for merge conflicts................................................Passed
check for broken symlinks............................(no files to check)Skipped
check json...........................................(no files to check)Skipped
check for case conflicts.................................................Passed
mixed line ending........................................................Passed
detect aws credentials...................................................Passed
detect private key.......................................................Passed
Terraform fmt........................................(no files to check)Skipped
Terraform docs.......................................(no files to check)Skipped
Lint Dockerfiles.........................................................Passed
๐ Usage
To activate pre-commit hooks in your repository:
pre-commit install
For local development, use Docker and Docker Compose via the provided run.sh
script.
๐ Resources
<!DOCTYPE html>
<html>
<head>
<title>HashiQube - A Hands on DevOps Development Lab Using All the HashiCorp Products and other Popular Applications such as Docker, Kubernetes, Traefik, Ansible, AWX Ansible Tower and loads more.</title>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-LWNG2RV7KC"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-LWNG2RV7KC');
</script>
<!-- script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-5855657010614500" crossorigin="anonymous"></script -->
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta property="og:url" content="https://hashiqube.com/" />
<meta property="og:type" content="website" />
<meta property="og:title" content="HashiQube - The Ultimate Hands on DevOps Lab in a Docker Container" />
<meta property="og:description" content="HashiQube is a Hands on DevOps Development Lab Using All the HashiCorp Products and other Popular Applications such as Docker, Kubernetes, Traefik, Ansible, AWX Ansible Tower and loads more." />
<meta property="og:image" content="https://hashiqube.com/images/youtube-hashiqube-the-jedi-devops-lab.png" />
<meta charset="UTF-8">
<link rel="icon" type="image/png" href="/images/logo-bright.png">
<link rel="stylesheet" href="/docsify/lib/vue.css" disabled>
<link rel="stylesheet" href="/docsify/lib/buble.css" disabled>
<link rel="stylesheet" href="/docsify/lib/dark.css" disabled>
<link rel="stylesheet" href="/docsify/lib/pure.css" disabled>
<link rel="stylesheet" href="/docsify/lib/mermaid.min.css">
<link rel="stylesheet" href="/docsify/lib/docsify-accordion-style.css">
<!-- Theme: Simple (latest v0.x.x) -->
<link
rel="stylesheet"
href="/docsify/lib/docsify-darklight-theme-style.min.css"
title="docsify-darklight-theme"
type="text/css"
/>
<script src="/docsify/lib/mermaid.min.js"></script>
<style>
/*
Hashiqube Theme
Version 0.0.3
*/
:root {
--hashi-gradient: 90deg,
#370960 0%,
#ea216b 10%,
#ff5800 20%,
#fefb00 30%,
#61e190 40%,
#5cdeff 50%,
#61e190 60%,
#fefb00 70%,
#ff5800 80%,
#ea216b 90%,
#370960 100%;
--hashi-blue: #5cdeff;
--hashi-green: #61e190;
--hashi-yellow: #fefb00;
--hashi-orange: #ff5800;
--hashi-pink: #ea216b;
--hashi-purple: #370960;
--docsifytabs-border-color: #ededed;
--docsifytabs-tab-highlight-color: purple;
}
.yellow {
background: var(--hashi-yellow);
}
.orange {
background: var(--hashi-orange);
}
.blue {
background: var(--hashi-blue);
}
.green {
background: var(--hashi-green);
}
.purple {
background: var(--hashi-purple);
}
.pink {
background: var(--hashi-pink);
}
.header img {
width: 80%;
display: none;
top: 0px;
right: 0px;
}
.app-name-link img {
max-width: 160px;
-webkit-transition-property: all;
-webkit-transition-duration: 0.3s;
-webkit-transition-timing-function: ease;
}
.app-name-link img:hover {
transform: scale(1.3);
}
.sidebar-nav ul ul,
.sidebar nav ul ul {
margin-left: 0px;
}
.search .input-wrap {
margin-top: 10px !important;
}
aside.sidebar {
width: auto;
display: flex;
flex-direction: column;
padding-top: 110px;
}
aside.sidebar :nth-child(1) {
order: 2;
}
aside.sidebar :nth-child(2) {
order: 1;
}
aside.sidebar :nth-child(3) {
order: 3;
}
.sidebar-toggle {
position: fixed !important;
bottom: auto;
left: 0px;
right: 0px;
background: linear-gradient(var(--hashi-gradient));
display: block;
height: 70px;
padding: 0;
width: 100% !important;
}
.sidebar-toggle-button {
display: flex;
width: 70px;
height: 70px;
text-align: center;
flex-direction: column;
justify-content: center;
align-items: center;
background: var(--hashi-blue);
right: 0;
top: 0;
position: absolute;
}
.sidebar-toggle span {
background-color: #000000;
display: block;
margin-bottom: 4px;
width: 20px;
height: 2px;
}
.sidebar ul li a {
font-size: 18px;
}
#docsify-darklight-theme {
background-color: #000000;
background-repeat: no-repeat;
background-size: 30px;
background-position: center;
position: fixed;
right: 140px;
top: 0;
width: 70px;
left: auto;
height: 70px;
z-index: 1000;
}
.content {
padding-top: 10px;
left: 240px;
}
.markdown-section {
padding-top: 110px;
max-width: 1050px;
}
.markdown-section iframe {
border: 0px solid #eee;
}
.markdown-section pre>code,
.markdown-section code {
font-size: 1rem;
}
.footer {
position: relative;
/* display: none; */
text-align: center;
bottom: 10px;
}
.github-corner svg {
fill: transparent;
color: #ffffff;
padding: 0px;
margin: 0px;
margin-left: 0px;
position: relative;
right: 15px;
height: 70px;
width: 70px;
}
.github-corner {
border-bottom: 0;
position: fixed;
right: 70px;
text-decoration: none;
top: 0;
z-index: 1;
box-sizing: border-box;
width: 70px;
height: 70px;
margin-left: -12px;
overflow: hidden;
background: var(--hashi-purple);
z-index: 100;
box-sizing: border-box;
padding: 8px 0 0 5px;
}
.progress-bar {
background: linear-gradient(var(--hashi-gradient));
height: 7px;
position: fixed;
bottom: 0px;
left: 0px;
width: 100%;
padding-bottom: 10px;
}
.hasinav {
position: fixed;
left: auto;
right: 210px;
z-index: 100;
top: 0;
height: 70px;
display: flex;
}
.hasinav .qube {
width: 70px;
display: inline-flex;
box-sizing: border-box;
height: 70px;
align-items: center;
justify-content: center;
}
.hasinav .qube:hover {
opacity: 0.8;
}
.hasinav .qube img {
max-width: 30px;
max-height: 30px;
width: auto;
height: auto;
}
</style>
<body>
<!-- Google Tag Manager (noscript) -->
<noscript>
<iframe src="https://www.googletagmanager.com/ns.html?id=GTM-MQ56PNF"
height="0" width="0" style="display:none;visibility:hidden"></iframe>
</noscript>
<!-- End Google Tag Manager (noscript) -->
<div class="header"><img title="HashiQube - DevOps Lab" alt="HashiQube - DevOps Lab" src="/images/hashiqube-banner.png"></div>
<div class="hasinav">
<a href="https://www.youtube.com/@hashiqube/featured" target="_blank" class="qube yellow"><img src="/images/youtube-logo.svg" border="0" alt="Youtube Channel" title="Youtube Channel"></a>
<a href="https://medium.com/search?q=hashiqube" target="_blank" class="qube green"><img src="/images/medium-logo.svg" border="0" alt="Medium Posts" title="Medium Posts"></a>
<a href="https://www.linkedin.com/in/riaannolan/" target="_blank" class="qube blue"><img src="/images/linkedin-logo.png" border="0" alt="Riaan Nolan Linkedin" title="Riaan Nolan Linkedin"></a>
<a href="https://www.hashicorp.com/ambassadors/directory?q=riaan" target="_blank" class="qube pink"><img src="/images/hashicorp-logo.svg" border="0" alt="Riaan Nolan Hashicorp Ambassador" title="Riaan Nolan Hashicorp Ambassador"></a>
</div>
<div id="app"></div>
<article class="markdown-section" id="main"></article>
<script>
window.$docsify = {
routerMode: 'history', //hash (default) or history, history mode (SEO friendly) is possible if you host on https://www.netlify.com/ see rewrite rules in _redirects file
notFoundPage: '/',
nameLink: '/',
basePath: '/',
alias: {
'/.*/SUMMARY.md': '/SUMMARY.md'
},
topMargin: 80,
logo: '/images/logo-bright.png',
name: 'HashiQube',
repo: 'https://github.com/star3am/hashiqube',
search: 'auto',
auto2top: true,
relativePath: false,
homepage: 'README.md',
loadSidebar: 'SUMMARY.md',
subMaxLevel: 3,
formatUpdated: '{MM}/{DD} {HH}:{mm}',
plugins: [
function (hook, vm) {
hook.beforeEach(function (html) {
return html.replace(/{% *.* %}/mg, '')
})
}
],
markdown: {
renderer: {
code: function(code, lang) {
if (lang === "mermaid") {
return (
'<div class="mermaid">' + mermaid.render('mermaid-svg-' + num++, code) + "</div>"
);
}
if (lang === 'drawio') {
if (window.drawioConverter) {
console.log('drawio')
return window.drawioConverter(code)
} else {
return `<div class='drawio-code'>${code}</div>`
}
}
return this.origin.code.apply(this, arguments);
}
}
},
themeable: {
readyTransition : true,
responsiveTables: true
},
// Style Guide: https://github.com/dracula/dracula-theme
darklightTheme: {
siteFont: "PT Sans",
defaultTheme: 'light',
codeFontFamily: 'Roboto Mono, Monaco, courier, monospace',
bodyFontSize: '18px',
dark: {
accent: '#8be9fd',
toggleBackground: '#f8f8f2',
background: '#240129',
textColor: '#f8f8f2',
codeTextColor: '#5cdeff',
codeBackgroundColor: '#000524',
borderColor: '#0d2538',
blockQuoteColor: '#5cdeff',
highlightColor: '#fefb00',
sidebarSublink: '#61e190',
codeTypeColor: '#5cdeff',
coverBackground: 'linear-gradient(to left bottom, hsl(118, 100%, 85%) 0%,hsl(181, 100%, 85%) 100%)',
toggleImage: 'url(/docsify/lib/docsify-darklight-theme-sun.svg)'
},
light: {
accent: '#ed2f74',
toggleBackground : '#091a28',
background: '#ffffff',
textColor: '#444444',
codeTextColor : '#370960',
codeBackgroundColor : '#f8f8f8',
borderColor : 'rgba(0, 0, 0, 0.07)',
blockQuoteColor : '#858585',
highlightColor : '#d22778',
sidebarSublink : '#34495e',
codeTypeColor : '#370960',
coverBackground: 'linear-gradient(to left bottom, hsl(118, 100%, 85%) 0%,hsl(181, 100%, 85%) 100%)',
toggleImage: 'url(/docsify/lib/docsify-darklight-theme-moon.svg)'
}
},
tabs: {
persist: true, // default
sync: true, // default
tabComments: true, // default
tabHeadings: true // default
},
// pagination: {
// crossChapter: true
// },
}
var num = 0;
mermaid.initialize({ logLevel:0, startOnLoad: false, themeCSS:'.label { font-family: Source Sans Pro,Helvetica Neue,Arial,sans-serif; }' });
</script>
<script src="/docsify/lib/docsify.min.js"></script>
<script src="/docsify/lib/plugins-emoji.min.js"></script>
<script src="/docsify/lib/docsify-copy-code.js"></script>
<script src="/docsify/lib/plugins-search.min.js"></script>
<script src="/docsify/lib/prism-bash.js"></script>
<script src="/docsify/lib/prism-yaml.js"></script>
<script src="/docsify/lib/prism-log.js"></script>
<script src="/docsify/lib/prism-hcl.js"></script>
<script src="/docsify/lib/prism-docker.js"></script>
<script src="/docsify/lib/prism-python.js"></script>
<script src="/docsify/lib/prism-ruby.js"></script>
<script src="/docsify/libprism-groovy.min.js"></script>
<script src="/docsify/libprism-typescript.min.js"></script>
<script src="/docsify/lib/docsify-darklight-theme-index.min.js"></script>
<!-- script src="/docsify/lib/docsify-pagination.min.js"></script -->
<script src="/docsify/lib/docsify-slides.min.js"></script>
<script src="/docsify/lib/docsify-accordion.js"></script>
<script src="/docsify/lib/docsify-drawio-viewer.min.js"></script>
<script src='/docsify/lib/docsify-drawio-drawio.js'></script>
<script src="/docsify/lib/docsify-tabs.js"></script>
<div class="footer"></div>
<div class="progress-bar"></div>
</body>
</html>