Skip to content

Commit

Permalink
Merge pull request #6 from ned1313/change-error-handling
Browse files Browse the repository at this point in the history
update formatting and error checking
  • Loading branch information
ned1313 authored Jun 11, 2024
2 parents 130b3dc + 464920f commit 5245820
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 40 deletions.
31 changes: 20 additions & 11 deletions cmd/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ the root directory of this source tree.
package cmd

import (
"encoding/json"
"fmt"
"log/slog"

"github.com/spf13/cobra"
"github.com/jedib0t/go-pretty/v6/table"
)

// checkCmd represents the check command
Expand All @@ -26,7 +26,7 @@ var checkCmd = &cobra.Command{
mod lock file. Will return an error if the hash for found modules do not match or if a module
is not found in the lock file.`,
RunE: func(cmd *cobra.Command, args []string) error {
slog.Info("check command called")
slog.Debug("check command called")
// Get path value
path, err := setPath(Source)
if err != nil {
Expand Down Expand Up @@ -82,24 +82,33 @@ var checkCmd = &cobra.Command{
}

if len(noMatchHash.Modules) > 0 {
fmt.Println("Non matching modules were found:")
bytes, _ := json.MarshalIndent(noMatchHash.Modules, "", " ")
fmt.Println(string(bytes))
fmt.Println("You may wish to update the module lock file using the upgrade command.")
tw := table.NewWriter()
tw.SetTitle("Non Matching Modules")
tw.AppendHeader(table.Row{"Name","Version","Source"})
for _,v := range noMatchHash.Modules {
tw.AppendRow(table.Row{v.Key,v.Version,v.Source})
}
fmt.Println(tw.Render())
fmt.Print("You can update these modules with the upgrade command.\n\n")
}

if len(notFoundMods.Modules) > 0 {
fmt.Println("The following modules were not found in the lock file:")
bytes, _ := json.MarshalIndent(notFoundMods.Modules, "", " ")
fmt.Println(string(bytes))
fmt.Println("You may wish to add these modules using the upgrade command.")
tw := table.NewWriter()
tw.SetTitle("Missing Modules")
tw.AppendHeader(table.Row{"Name","Version","Source"})
for _,v := range notFoundMods.Modules {
tw.AppendRow(table.Row{v.Key,v.Version,v.Source})
}
fmt.Println(tw.Render())
fmt.Print("You can add these modules with the upgrade command.\n\n")
}

if len(noMatchHash.Modules) > 0 || len(notFoundMods.Modules) > 0 {
fmt.Printf("\nSummary: %v modules mising, %v non matching modules\n\n", len(notFoundMods.Modules), len(noMatchHash.Modules))
return fmt.Errorf("non matching or missing modules found in the configuration")
}

slog.Info("all modules match the lock file")
fmt.Println("All modules match the mod lock file")
return nil

},
Expand Down
14 changes: 13 additions & 1 deletion cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (

"encoding/json"
"github.com/spf13/cobra"
"github.com/jedib0t/go-pretty/v6/table"
)

// initCmd represents the init command
Expand All @@ -27,7 +28,7 @@ var initCmd = &cobra.Command{
file if one doesn't already exist. This command will error if a mod lock file
is found or the Terraform configuration hasn't been initialized yet.`,
RunE: func(cmd *cobra.Command, args []string) error {
slog.Info("init command called")
slog.Debug("init command called")

path, err := setPath(Source)
if err != nil {
Expand Down Expand Up @@ -55,13 +56,24 @@ var initCmd = &cobra.Command{
return nil
}

tw := table.NewWriter()
tw.AppendHeader(table.Row{"Name","Version","Source"})
for _,v := range sourcedMods.Modules {
tw.AppendRow(table.Row{v.Key,v.Version,v.Source})
}
fmt.Println("The following modules are being added to the mod lock file:")
fmt.Println(tw.Render())


//Prepare the json to look nice
bytes, _ := json.MarshalIndent(sourcedMods, "", " ")

// Create the mod lock file
slog.Debug("writing modules out to file")
os.WriteFile(path + modFileName, bytes, os.ModePerm)

fmt.Printf("\n\nSummary: %v modules added to mod lock file.\n\n", len(sourcedMods.Modules))

return nil
},
}
Expand Down
30 changes: 16 additions & 14 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,18 @@ use this file except in compliance with the License.
You may obtain a copy of the License at the LICENSE file in
the root directory of this source tree.
*/
package cmd

import (
"os"
"log/slog"
"encoding/json"
"fmt"
"log/slog"
"os"
"strings"
"encoding/json"

"github.com/spf13/cobra"
"github.com/gosimple/hashdir"
"github.com/spf13/cobra"
)

// rootCmd represents the base command when called without any subcommands
Expand Down Expand Up @@ -52,12 +51,15 @@ const modFileName = ".terraform.module.hcl"

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
func Execute() error {
rootCmd.SilenceUsage = true
rootCmd.SilenceErrors = true
err := rootCmd.Execute()
if err != nil {
slog.Error(err.Error())
os.Exit(1)
fmt.Fprintf(os.Stderr, "Error: %s\n", err)
return err
}
return nil
}

func init() {
Expand Down Expand Up @@ -114,14 +116,14 @@ func processModules(path string) (modules, error) {
for _, m := range mods.Modules {
// All downloaded modules will reside in the .terraform/modules directory
if strings.Split(m.Dir, "/")[0] != ".terraform" {
slog.Info("skipping module: " + m.Key)
slog.Debug("skipping module: " + m.Key)
}else{
// Add a hash based on Dir contents
hash, err := hashdir.Make(path+m.Dir, "sha256")
if err != nil {
return sourcedMods, fmt.Errorf("could not create hash for %v: %v", m.Key, err)
}
slog.Info("hash generated: " + hash)
slog.Debug("hash generated: " + hash)
newMod := moduleEntry{
Key: m.Key,
Dir: m.Dir,
Expand Down Expand Up @@ -171,17 +173,17 @@ func setPath(path string) (string, error) {
if err != nil {
return path, fmt.Errorf("unable to find the current working directory: %v", err)
}
slog.Info("working path set to current directory: " + setPath)
slog.Debug("working path set to current directory: " + setPath)
return (setPath + "/"), nil
} else {
setPath = path
slog.Info("working path set to source directory: " + setPath)
slog.Debug("working path set to source directory: " + setPath)
}
// If the path doesn't end with a '/' add it
if strings.HasSuffix(strings.TrimSpace(setPath), "/") {
slog.Info("trailing slash found in " + setPath)
slog.Debug("trailing slash found in " + setPath)
return setPath, nil
}
slog.Info("no trailing slash found in " + setPath)
slog.Debug("no trailing slash found in " + setPath)
return (setPath + "/"), nil
}
61 changes: 53 additions & 8 deletions cmd/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,32 @@ use this file except in compliance with the License.
You may obtain a copy of the License at the LICENSE file in
the root directory of this source tree.
*/
package cmd

import (
"bufio"
"encoding/json"
"fmt"
"log/slog"
"os"
"encoding/json"
"strings"

"github.com/jedib0t/go-pretty/v6/table"
"github.com/spf13/cobra"
)

var autoApprove bool

// upgradeCmd represents the upgrade command
var upgradeCmd = &cobra.Command{
Use: "upgrade",
Short: "upgrade the lock file from the configuration",
Long: `Upgrade will replace the entries in the mod lock file with the module references found
in the Terraform configuration. Later this will be updated to target specific modules.`,
RunE: func(cmd *cobra.Command, args []string) error {
slog.Info("upgrade command called")
// Get path value
slog.Debug("upgrade command called")

// Get path value
path, err := setPath(Source)
if err != nil {
Expand Down Expand Up @@ -56,26 +60,65 @@ var upgradeCmd = &cobra.Command{
return fmt.Errorf("error processing %v file: %v", modFileName, err)
}

var updateMods modules
//updated and added are used for table generation and summary
var updateMods, updated, added, unchanged modules
updateMods.Modules = make(map[string]moduleEntry)
updated.Modules = make(map[string]moduleEntry)
added.Modules = make(map[string]moduleEntry)
unchanged.Modules = make(map[string]moduleEntry)

//Cycle through each sourceMod
// All source Mods will be added to the updateMods variable
// Logging provides context on what is changing
// TODO: Add support for single module upgrades
// TODO: Log modules present in lock file, but missing from update
for k, s := range sourcedMods.Modules {
l, ok := lockedMods.Modules[k]
if ok {
if l.Hash != s.Hash || l.Version != s.Version {
slog.Info("updating hash or version for module " + k)
slog.Debug("updating hash or version for module " + k)
updated.Modules[k] = s
}else{
slog.Info("no change to module " + k)
slog.Debug("no change to module " + k)
unchanged.Modules[k] = s
}
}else{
slog.Info("adding new module " + k)
slog.Debug("adding new module " + k)
added.Modules[k] = s
}
updateMods.Modules[k] = s
}

if len(added.Modules) == 0 && len(updated.Modules) == 0 {
fmt.Println("No changes detected for modules. Exiting...")
return nil
}

tw := table.NewWriter()
tw.AppendHeader(table.Row{"Name","Version","Change","Source"})
for _,v := range updated.Modules {
tw.AppendRow(table.Row{v.Key,v.Version,"Update",v.Source})
}
for _,v := range added.Modules {
tw.AppendRow(table.Row{v.Key,v.Version,"Added",v.Source})
}
for _,v := range unchanged.Modules {
tw.AppendRow(table.Row{v.Key,v.Version,"Unchanged",v.Source})
}

fmt.Println("The following changes were detected:")
fmt.Println(tw.Render())
fmt.Printf("\nSummary: %v to update, %v to add, %v unchanged\n", len(updated.Modules),len(added.Modules),len(unchanged.Modules))
if !autoApprove {
fmt.Print("Confirm changes by entering yes: ")
var in = bufio.NewReader(os.Stdin)
name, _ := in.ReadString('\n')
if strings.TrimSpace(name) != "yes" {
slog.Debug("changes not accepted for mod lock file update")
return fmt.Errorf("changes not accepted for mod lock file update")
}
}

// Write out new mod lock file to path
//Prepare the json to look nice
bytes, _ := json.MarshalIndent(updateMods, "", " ")
Expand All @@ -84,6 +127,7 @@ var upgradeCmd = &cobra.Command{
slog.Debug("writing modules out to file")
os.WriteFile(path + modFileName, bytes, os.ModePerm)

fmt.Println("Changes to mod lock file have been made successfully!")

return nil
},
Expand All @@ -101,4 +145,5 @@ func init() {
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// upgradeCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
upgradeCmd.Flags().BoolVar(&autoApprove,"auto-approve",false,"Automatically approve mod lock file changes")
}
2 changes: 1 addition & 1 deletion cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
"github.com/spf13/cobra"
)

const coreVersion = "0.0.6"
const coreVersion = "0.0.7"

var versionCmd = &cobra.Command{
Use: "version",
Expand Down
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ toolchain go1.22.4

require (
github.com/gosimple/hashdir v1.0.2
github.com/jedib0t/go-pretty/v6 v6.5.9
github.com/spf13/cobra v1.8.0
)

require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/sys v0.17.0 // indirect
)
15 changes: 15 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gosimple/hashdir v1.0.2 h1:3h8l8CfLUeRgcJGDxJyJjfYFzDuZZo6HjwEm7I4inv4=
github.com/gosimple/hashdir v1.0.2/go.mod h1:BqFbiXPzCbJAzK1ppHf+idDESsuauUqgq/hHYTBQnzE=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jedib0t/go-pretty/v6 v6.5.9 h1:ACteMBRrrmm1gMsXe9PSTOClQ63IXDUt03H5U+UV8OU=
github.com/jedib0t/go-pretty/v6 v6.5.9/go.mod h1:zbn98qrYlh95FIhwwsbIip0LYpwSG8SUOScs+v9/t0E=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
11 changes: 8 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@ use this file except in compliance with the License.
You may obtain a copy of the License at the LICENSE file in
the root directory of this source tree.
*/
package main

import "terrahash/cmd"
import (
"os"
"terrahash/cmd"
)

func main() {
cmd.Execute()
err := cmd.Execute()
if err != nil {
os.Exit(1)
}
}
Loading

0 comments on commit 5245820

Please sign in to comment.