Skip to content

Commit

Permalink
Initial development (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
brettcurtis authored Jun 23, 2024
1 parent 99b0b59 commit 698e684
Show file tree
Hide file tree
Showing 7 changed files with 230 additions and 0 deletions.
17 changes: 17 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# .gitignore
# https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files

# Datadog Static Analysis
static-analysis.datadog.yml

# Infracost
.infracost

# Other Files
*.log
*.bak
*.swp
*.tmp
*.gz
*.tgz
*.tar
8 changes: 8 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
hooks:
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
- id: check-symlinks
5 changes: 5 additions & 0 deletions .pre-commit-hooks.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
- id: terraform-fmt
name: Terraform Format
entry: hooks/terraform/format
language: golang
files: \.tf$
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/osinfra-io/pre-commit-hooks

go 1.22.4
42 changes: 42 additions & 0 deletions hooks/helpers/outputs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package outputs

import (
"fmt"
)

// ANSI escape codes for color
const (
Reset = "\033[0m"
Red = "\033[31m"
Green = "\033[32m"
Yellow = "\033[33m"
Blue = "\033[34m"
Purple = "\033[35m"
Cyan = "\033[36m"
White = "\033[37m"
)

// Colorize function to wrap text with given color
func Colorize(text, color string) string {
return fmt.Sprintf("%s%s%s", color, text, Reset)
}

// Emoji constants
const (
Error = "💀"
Warning = "🚧"
Working = "🔨"
Running = "🔩"
ThumbsUp = "👍"
ThumbsDown = "👎"
Diamond = "🔸"
)

// Generic function to combine emoji and colored text
func EmojiColorText(emoji, text, color string) string {
return fmt.Sprintf("%s %s", emoji, Colorize(text, color))
}

// Example usage:
// fmt.Println(EmojiColorText(ThumbsUp, "All Terraform files are formatted.", Green))
// fmt.Println(EmojiColorText(Warning, "Found unformatted Terraform files:", Yellow))
60 changes: 60 additions & 0 deletions hooks/terraform/format.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package main

import (
"fmt"
"os"
"os/exec"
"strings"

outputs "github.com/osinfra-io/pre-commit-hooks/hooks/helpers"
)

func checkTerraformInstalled() bool {
_, err := exec.LookPath("terraform")
return err == nil
}

func main() {
if !checkTerraformInstalled() {
fmt.Println("Terraform is not installed or not in PATH.")
// Handle the error, e.g., exit the program or inform the user.
os.Exit(1)
}

fmt.Println(outputs.EmojiColorText(outputs.Running, "Running terraform fmt...", outputs.Purple))

// Find unformatted Terraform files
cmd := exec.Command("terraform", "fmt", "-check", "-recursive")
output, err := cmd.CombinedOutput()
if err != nil {
// Check if the error is an ExitError and the exit code is 3
if exitErr, ok := err.(*exec.ExitError); ok && exitErr.ExitCode() == 3 {
fmt.Println(outputs.EmojiColorText(outputs.Warning, "Found unformatted Terraform files:", outputs.Yellow))
} else {
fmt.Printf(outputs.EmojiColorText(outputs.Error, "Error running terraform fmt: %v\n", outputs.Red), err)
os.Exit(1)
}
}

unformattedFiles := strings.TrimSpace(string(output))
if unformattedFiles != "" {
// Split the unformattedFiles string into a slice of file names
fileNames := strings.Split(unformattedFiles, "\n")
for _, file := range fileNames {
fmt.Println(" " + outputs.EmojiColorText(outputs.Diamond, (file), outputs.Yellow))
}

fmt.Println(outputs.EmojiColorText(outputs.Working, "Formatting files with terraform fmt...", outputs.Purple))
cmd := exec.Command("terraform", "fmt", "-recursive")
err := cmd.Run()

if err != nil {
fmt.Println(outputs.EmojiColorText(outputs.Error, "Error running terraform fmt:", outputs.Red), err)
} else {
fmt.Println(outputs.EmojiColorText(outputs.ThumbsUp, "Files formatted successfully with terraform fmt.", outputs.Green))
}
} else {
// This line will now only run if unformattedFiles is empty
fmt.Println(outputs.EmojiColorText(outputs.ThumbsUp, "All Terraform files are formatted.", outputs.Green))
}
}
95 changes: 95 additions & 0 deletions hooks/terraform/format_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package main

import (
"bytes"
"os"
"path/filepath"
"strings"
"testing"
)

func TestTerraformFormat(t *testing.T) {
// Step 1: Create temporary directory
tempDir, err := os.MkdirTemp("", ".go_test")
if err != nil {
t.Fatalf("Failed to create temp directory: %v", err)
}
defer os.RemoveAll(tempDir) // Cleanup

// Step 2: Create Terraform files
formattedContent := `variable "example" {}`
unformattedContent := `variable "example" {}` // Extra spaces

formattedFilePath, err := filepath.Abs(filepath.Join(tempDir, "formatted.tf"))
if err != nil {
t.Fatalf("Failed to get absolute path: %v", err)
}
unformattedFilePath, err := filepath.Abs(filepath.Join(tempDir, "unformatted.tf"))
if err != nil {
t.Fatalf("Failed to get absolute path: %v", err)
}

if err := os.WriteFile(formattedFilePath, []byte(formattedContent), 0644); err != nil {
t.Fatalf("Failed to write formatted file: %v", err)
}
if err := os.WriteFile(unformattedFilePath, []byte(unformattedContent), 0644); err != nil {
t.Fatalf("Failed to write unformatted file: %v", err)
}

// Ensure tempDir is an absolute path
absTempDir, err := filepath.Abs(tempDir)
if err != nil {
t.Fatalf("Failed to get absolute path for %s: %v", tempDir, err)
}

// Get the current working directory as an absolute path
originalWd, err := os.Getwd()
if err != nil {
t.Fatalf("Failed to get current working directory: %v", err)
}

// Change working directory to absTempDir
if err := os.Chdir(absTempDir); err != nil {
t.Fatalf("Failed to change directory to %s: %v", absTempDir, err)
}

// Defer the restoration of the original working directory
defer func() {
if err := os.Chdir(originalWd); err != nil {
t.Fatalf("Failed to restore original working directory to %s: %v", originalWd, err)
}
}()

// Step 3: Capture output
originalStdout := os.Stdout // Keep backup of the real stdout
r, w, err := os.Pipe()
if err != nil {
t.Fatalf("Failed to create pipe: %v", err)
}
os.Stdout = w

main()

w.Close()
os.Stdout = originalStdout // Restore original stdout

var buf bytes.Buffer
if _, err := buf.ReadFrom(r); err != nil {
t.Fatalf("Failed to read from reader: %v", err)
}
output := buf.String()

// Step 4: Verify results
if !strings.Contains(output, "Files formatted successfully with terraform fmt.") {
t.Errorf("Expected success message not found in output")
}

// Verify unformatted file is now formatted
unformattedResult, err := os.ReadFile(unformattedFilePath)
if err != nil {
t.Fatalf("Failed to read file %s: %v", unformattedFilePath, err)
}
if string(unformattedResult) != formattedContent {
t.Errorf("File was not formatted correctly")
}
}

0 comments on commit 698e684

Please sign in to comment.