HashiQube - DevOps Lab
Youtube Channel Medium Posts Riaan Nolan Linkedin Riaan Nolan Hashicorp Ambassador

.

Tools Container

A development environment that helps you become a better developer using Git pre-commit hooks

Pre-Commit

๐Ÿš€ 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:

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>