Repository: warrensbox/terraform-switcher (go)

Issue:
Feature request: option to dry-run
I'd like to ask to implement a feature which would allow me to run `tfswitch` in a dry-run mode where it only outputs whether it would switch terraform version in current directory or not with different exit codes for the two operations (e.g. `0` for when no switching is required and `1` for when `tfswitch` would switch versions).

My use case: we're managing different infrastructures from different repositories including legacy setups – most of these are using different versions of terraform and we're not planning to unify them. Most of the time I need to switch terraform version when I work on something in several different setups at the same time but it's not always that I need to actually switch terraform version (e.g. when I only need to cd into dir to check something) hence suggested `cdtfswitch()` Bash alias is not something I indeed need but would rather want to inject something like `tfswitch --dry-run >/dev/null || echo "tfswitch to use correct terraform version"` into my `PROMPT_COMMAND` env var so that I get notified when my Terraform version doesn't match Terraform version constraint every time I hit enter on the command line.

Thanks in advance.


Discussion:
As an interim solution (sort of FWIW) here's the ugly bit of Go code I came up with:
```Go
package main

import (
	"fmt"
	"os"

	"github.com/hashicorp/go-version"
	"github.com/jessevdk/go-flags"
)

var opts struct {
	Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"`
}

func usage() {
	fmt.Fprintf(os.Stderr, "Usage: %s [-v] <tf version> <tf version constraint>\n", os.Args[0])
	os.Exit(2)
}

func main() {
	args, err := flags.Parse(&opts)
	if err != nil {
		usage()
	}

	if len(args) != 2 {
		usage()
	}

	v1, err := version.NewVersion(args[0])
	if err != nil {
		fmt.Println("ERROR:", err)
		usage()
	}

	constraints, err := version.NewConstraint(args[1])
	if err != nil {
		fmt.Println("ERROR:", err)
		usage()
	}

	if constraints.Check(v1) {
		if len(opts.Verbose) > 0 {
			fmt.Printf("\"%s\" satisfies constraint \"%s\"\n", v1, constraints)
		}
		os.Exit(0)
	} else {
		if len(opts.Verbose) > 0 {
			fmt.Printf("\"%s\" DOES NOT satisfy constraint \"%s\"\n", v1, constraints)
		}
		os.Exit(1)
	}
}
```
```Bash
> terraform version | head -1
Terraform v0.13.6

> fgrep required_version *.tf
  required_version = "~> 1.0.0"

> tf_version_check -v "$(terraform version -json | jq -r .terraform_version)" "$(awk '/^[[:space:]]+required_version[[:space:]]+/ {print gensub("^.+= \"(.+)\"^M?$","\\1","g");}' *.tf 2>/dev/null)"
"0.13.6" DOES NOT satisfy constraint "~> 1.0.0"

> tf_version_check "$(terraform version -json | jq -r .terraform_version)" "$(awk '/^[[:space:]]+required_version[[:space:]]+/ {print gensub("^.+= \"(.+)\"^M?$","\\1","g");}' *.tf 2>/dev/null)" && echo GOOD || echo BAD
BAD

> tfswitch
Reading configuration from home directory for .tfswitch.toml
Reading required version from terraform file
Reading required version from constraint: ~> 1.0.0
Matched version: 1.0.11
Switched terraform to version "1.0.11"

> tf_version_check -v "$(terraform version -json | jq -r .terraform_version)" "$(awk '/^[[:space:]]+required_version[[:space:]]+/ {print gensub("^.+= \"(.+)\"^M?$","\\1","g");}' *.tf 2>/dev/null)"
"1.0.11" satisfies constraint "~> 1.0.0"

> tf_version_check "$(terraform version -json | jq -r .terraform_version)" "$(awk '/^[[:space:]]+required_version[[:space:]]+/ {print gensub("^.+= \"(.+)\"^M?$","\\1","g");}' *.tf 2>/dev/null)" && echo GOOD || echo BAD
GOOD
```

Patch:
diff --git a/lib/download.go b/lib/download.go
--- a/lib/download.go
+++ b/lib/download.go
@@ -7,37 +7,40 @@ import (
 	"os"
 	"path/filepath"
 	"strings"
+	"sync"
 )
 
 // DownloadFromURL : Downloads the terraform binary and its hash from the source url
-func DownloadFromURL(installLocation string, mirrorURL string, tfversion string, versionPrefix string, goos string, goarch string) (string, error) {
+func DownloadFromURL(installLocation, mirrorURL, tfversion, versionPrefix, goos, goarch string) (string, error) {
+	var wg sync.WaitGroup
+	defer wg.Done()
 	pubKeyFilename := filepath.Join(installLocation, "/", PubKeyPrefix+PubKeyId+pubKeySuffix)
 	zipUrl := mirrorURL + tfversion + "/" + versionPrefix + tfversion + "_" + goos + "_" + goarch + ".zip"
 	hashUrl := mirrorURL + tfversion + "/" + versionPrefix + tfversion + "_SHA256SUMS"
 	hashSignatureUrl := mirrorURL + tfversion + "/" + versionPrefix + tfversion + "_SHA256SUMS." + PubKeyId + ".sig"
 
-	err := downloadPublicKey(installLocation, pubKeyFilename)
+	err := downloadPublicKey(installLocation, pubKeyFilename, &wg)
 	if err != nil {
 		logger.Error("Could not download public PGP key file.")
 		return "", err
 	}
 
 	logger.Infof("Downloading %q", zipUrl)
-	zipFilePath, err := downloadFromURL(installLocation, zipUrl)
+	zipFilePath, err := downloadFromURL(installLocation, zipUrl, &wg)
 	if err != nil {
 		logger.Error("Could not download zip file.")
 		return "", err
 	}
 
 	logger.Infof("Downloading %q", hashUrl)
-	hashFilePath, err := downloadFromURL(installLocation, hashUrl)
+	hashFilePath, err := downloadFromURL(installLocation, hashUrl, &wg)
 	if err != nil {
 		logger.Error("Could not download hash file.")
 		return "", err
 	}
 
 	logger.Infof("Downloading %q", hashSignatureUrl)
-	hashSigFilePath, err := downloadFromURL(installLocation, hashSignatureUrl)
+	hashSigFilePath, err := downloadFromURL(installLocation, hashSignatureUrl, &wg)
 	if err != nil {
 		logger.Error("Could not download hash signature file.")
 		return "", err
@@ -70,7 +73,7 @@ func DownloadFromURL(installLocation string, mirrorURL string, tfversion string,
 	var filesToCleanup []string
 	filesToCleanup = append(filesToCleanup, hashFilePath)
 	filesToCleanup = append(filesToCleanup, hashSigFilePath)
-	defer cleanup(filesToCleanup)
+	defer cleanup(filesToCleanup, &wg)
 
 	verified := checkSignatureOfChecksums(publicKeyFile, hashFile, signatureFile)
 	if !verified {
@@ -83,7 +86,8 @@ func DownloadFromURL(installLocation string, mirrorURL string, tfversion string,
 	return zipFilePath, err
 }
 
-func downloadFromURL(installLocation string, url string) (string, error) {
+func downloadFromURL(installLocation string, url string, wg *sync.WaitGroup) (string, error) {
+	wg.Add(1)
 	tokens := strings.Split(url, "/")
 	fileName := tokens[len(tokens)-1]
 	logger.Infof("Downloading to %q", filepath.Join(installLocation, "/", fileName))
@@ -119,12 +123,12 @@ func downloadFromURL(installLocation string, url string) (string, error) {
 	return filePath, nil
 }
 
-func downloadPublicKey(installLocation string, targetFileName string) error {
+func downloadPublicKey(installLocation string, targetFileName string, wg *sync.WaitGroup) error {
 	logger.Debugf("Looking up public key file at %q", targetFileName)
 	publicKeyFileExists := FileExistsAndIsNotDir(targetFileName)
 	if !publicKeyFileExists {
 		// Public key does not exist. Let's grab it from hashicorp
-		pubKeyFile, errDl := downloadFromURL(installLocation, PubKeyUri)
+		pubKeyFile, errDl := downloadFromURL(installLocation, PubKeyUri, wg)
 		if errDl != nil {
 			logger.Errorf("Error fetching public key file from %s", PubKeyUri)
 			return errDl
@@ -138,8 +142,9 @@ func downloadPublicKey(installLocation string, targetFileName string) error {
 	return nil
 }
 
-func cleanup(paths []string) {
+func cleanup(paths []string, wg *sync.WaitGroup) {
 	for _, path := range paths {
+		wg.Add(1)
 		logger.Infof("Deleting %q", path)
 		err := os.Remove(path)
 		if err != nil {
diff --git a/lib/files.go b/lib/files.go
--- a/lib/files.go
+++ b/lib/files.go
@@ -59,16 +59,18 @@ func Unzip(src string, dest string) ([]string, error) {
 	if err != nil {
 		logger.Fatalf("Could not open destination: %v", err)
 	}
-	var wg sync.WaitGroup
+	var unzipWaitGroup sync.WaitGroup
 	for _, f := range reader.File {
-		wg.Add(1)
-		unzipErr := unzipFile(f, destination, &wg)
+		unzipWaitGroup.Add(1)
+		unzipErr := unzipFile(f, destination, &unzipWaitGroup)
 		if unzipErr != nil {
 			logger.Fatalf("Error unzipping %v", unzipErr)
 		} else {
 			filenames = append(filenames, filepath.Join(destination, f.Name))
 		}
 	}
+	logger.Debug("Waiting for deferred functions.")
+	unzipWaitGroup.Wait()
 	return filenames, nil
 }
 
diff --git a/lib/install.go b/lib/install.go
--- a/lib/install.go
+++ b/lib/install.go
@@ -5,7 +5,9 @@ import (
 	"os"
 	"path/filepath"
 	"runtime"
+	"strconv"
 	"strings"
+	"sync"
 
 	"github.com/manifoldco/promptui"
 
@@ -37,9 +39,9 @@ func initialize(binPath string) {
 	}
 }
 
-// getInstallLocation : get location where the terraform binary will be installed,
+// GetInstallLocation : get location where the terraform binary will be installed,
 // will create the installDir if it does not exist
-func getInstallLocation(installPath string) string {
+func GetInstallLocation(installPath string) string {
 	/* set installation location */
 	installLocation = filepath.Join(installPath, InstallDir)
 
@@ -50,6 +52,7 @@ func getInstallLocation(installPath string) string {
 
 // install : install the provided version in the argument
 func install(tfversion string, binPath string, installPath string, mirrorURL string) {
+	var wg sync.WaitGroup
 	/* Check to see if user has permission to the default bin location which is  "/usr/local/bin/terraform"
 	 * If user does not have permission to default bin location, proceed to create $HOME/bin and install the tfswitch there
 	 * Inform user that they don't have permission to default location, therefore tfswitch was installed in $HOME/bin
@@ -58,7 +61,7 @@ func install(tfversion string, binPath string, installPath string, mirrorURL str
 	binPath = installableBinLocation(binPath)
 
 	initialize(binPath)                               //initialize path
-	installLocation = getInstallLocation(installPath) //get installation location -  this is where we will put our terraform binary file
+	installLocation = GetInstallLocation(installPath) //get installation location -  this is where we will put our terraform binary file
 
 	goarch := runtime.GOARCH
 	goos := runtime.GOOS
@@ -88,7 +91,7 @@ func install(tfversion string, binPath string, installPath string, mirrorURL str
 		CreateSymlink(installFileVersionPath, binPath)
 		logger.Infof("Switched terraform to version %q", tfversion)
 		addRecent(tfversion, installPath) //add to recent file for faster lookup
-		os.Exit(0)
+		return
 	}
 
 	//if does not have slash - append slash
@@ -112,6 +115,8 @@ func install(tfversion string, binPath string, installPath string, mirrorURL str
 		logger.Fatalf("Unable to unzip %q file: %v", zipFile, errUnzip)
 	}
 
+	logger.Debug("Waiting for deferred functions.")
+	wg.Wait()
 	/* rename unzipped file to terraform version name - terraform_x.x.x */
 	installFilePath := ConvertExecutableExt(filepath.Join(installLocation, installFile))
 	RenameFile(installFilePath, installFileVersionPath)
@@ -130,13 +135,13 @@ func install(tfversion string, binPath string, installPath string, mirrorURL str
 	CreateSymlink(installFileVersionPath, binPath)
 	logger.Infof("Switched terraform to version %q", tfversion)
 	addRecent(tfversion, installPath) //add to recent file for faster lookup
-	os.Exit(0)
+	return
 }
 
 // addRecent : add to recent file
 func addRecent(requestedVersion string, installPath string) {
 
-	installLocation = getInstallLocation(installPath) //get installation location -  this is where we will put our terraform binary file
+	installLocation = GetInstallLocation(installPath) //get installation location -  this is where we will put our terraform binary file
 	versionFile := filepath.Join(installLocation, recentFile)
 
 	fileExist := CheckFileExist(versionFile)
@@ -179,7 +184,7 @@ func addRecent(requestedVersion string, installPath string) {
 // getRecentVersions : get recent version from file
 func getRecentVersions(installPath string) ([]string, error) {
 
-	installLocation = getInstallLocation(installPath) //get installation location -  this is where we will put our terraform binary file
+	installLocation = GetInstallLocation(installPath) //get installation location -  this is where we will put our terraform binary file
 	versionFile := filepath.Join(installLocation, recentFile)
 
 	fileExist := CheckFileExist(versionFile)
@@ -217,7 +222,7 @@ func getRecentVersions(installPath string) ([]string, error) {
 
 // CreateRecentFile : create RECENT file
 func CreateRecentFile(requestedVersion string, installPath string) {
-	installLocation = getInstallLocation(installPath) //get installation location -  this is where we will put our terraform binary file
+	installLocation = GetInstallLocation(installPath) //get installation location -  this is where we will put our terraform binary file
 	_ = WriteLines([]string{requestedVersion}, filepath.Join(installLocation, recentFile))
 }
 
@@ -274,19 +279,21 @@ func installableBinLocation(userBinPath string) string {
 }
 
 // InstallLatestVersion install latest stable tf version
-func InstallLatestVersion(customBinaryPath, installPath string, mirrorURL string) {
+func InstallLatestVersion(dryRun bool, customBinaryPath, installPath string, mirrorURL string) {
 	tfversion, _ := getTFLatest(mirrorURL)
-	install(tfversion, customBinaryPath, installPath, mirrorURL)
+	if !dryRun {
+		install(tfversion, customBinaryPath, installPath, mirrorURL)
+	}
 }
 
 // InstallLatestImplicitVersion install latest - argument (version) must be provided
-func InstallLatestImplicitVersion(requestedVersion, customBinaryPath, installPath string, mirrorURL string, preRelease bool) {
+func InstallLatestImplicitVersion(dryRun bool, requestedVersion, customBinaryPath, installPath string, mirrorURL string, preRelease bool) {
 	_, err := version.NewConstraint(requestedVersion)
 	if err != nil {
 		logger.Errorf("Error parsing constraint %q: %v", requestedVersion, err)
 	}
 	tfversion, err := getTFLatestImplicit(mirrorURL, preRelease, requestedVersion)
-	if err == nil && tfversion != "" {
+	if err == nil && tfversion != "" && !dryRun {
 		install(tfversion, customBinaryPath, installPath, mirrorURL)
 	}
 	logger.Errorf("Error parsing constraint %q: %v", requestedVersion, err)
@@ -294,45 +301,46 @@ func InstallLatestImplicitVersion(requestedVersion, customBinaryPath, installPat
 }
 
 // InstallVersion install with provided version as argument
-func InstallVersion(arg, customBinaryPath, installPath string, mirrorURL string) {
-	if validVersionFormat(arg) {
-		requestedVersion := arg
-
-		//check to see if the requested version has been downloaded before
-		installLocation := getInstallLocation(installPath)
-		installFileVersionPath := ConvertExecutableExt(filepath.Join(installLocation, VersionPrefix+requestedVersion))
-		recentDownloadFile := CheckFileExist(installFileVersionPath)
-		if recentDownloadFile {
-			ChangeSymlink(installFileVersionPath, customBinaryPath)
-			logger.Infof("Switched terraform to version %q", requestedVersion)
-			addRecent(requestedVersion, installPath) //add to recent file for faster lookup
-			os.Exit(0)
-		}
+func InstallVersion(dryRun bool, version, customBinaryPath, installPath, mirrorURL string) {
+	logger.Debugf("Install version %s. Dry run: %s", version, strconv.FormatBool(dryRun))
+	if !dryRun {
+		if validVersionFormat(version) {
+			requestedVersion := version
+
+			//check to see if the requested version has been downloaded before
+			installLocation := GetInstallLocation(installPath)
+			installFileVersionPath := ConvertExecutableExt(filepath.Join(installLocation, VersionPrefix+requestedVersion))
+			recentDownloadFile := CheckFileExist(installFileVersionPath)
+			if recentDownloadFile {
+				ChangeSymlink(installFileVersionPath, customBinaryPath)
+				logger.Infof("Switched terraform to version %q", requestedVersion)
+				addRecent(requestedVersion, installPath) //add to recent file for faster lookup
+				return
+			}
 
-		// If the requested version had not been downloaded before
-		// Set list all true - all versions including beta and rc will be displayed
-		tflist, _ := getTFList(mirrorURL, true)         // Get list of versions
-		exist := versionExist(requestedVersion, tflist) // Check if version exists before downloading it
+			// If the requested version had not been downloaded before
+			// Set list all true - all versions including beta and rc will be displayed
+			tflist, _ := getTFList(mirrorURL, true)         // Get list of versions
+			exist := versionExist(requestedVersion, tflist) // Check if version exists before downloading it
 
-		if exist {
-			install(requestedVersion, customBinaryPath, installPath, mirrorURL)
+			if exist {
+				install(requestedVersion, customBinaryPath, installPath, mirrorURL)
+			} else {
+				logger.Fatal("The provided terraform version does not exist.\n Try `tfswitch -l` to see all available versions")
+			}
 		} else {
-			logger.Fatal("The provided terraform version does not exist.\n Try `tfswitch -l` to see all available versions")
+			PrintInvalidTFVersion()
+			logger.Error("Args must be a valid terraform version")
+			UsageMessage()
 			os.Exit(1)
 		}
-
-	} else {
-		PrintInvalidTFVersion()
-		logger.Error("Args must be a valid terraform version")
-		UsageMessage()
-		os.Exit(1)
 	}
 }
 
 // InstallOption displays & installs tf version
 /* listAll = true - all versions including beta and rc will be displayed */
 /* listAll = false - only official stable release are displayed */
-func InstallOption(listAll bool, customBinaryPath, installPath string, mirrorURL string) {
+func InstallOption(listAll, dryRun bool, customBinaryPath, installPath string, mirrorURL string) {
 	tflist, _ := getTFList(mirrorURL, listAll)          // Get list of versions
 	recentVersions, _ := getRecentVersions(installPath) // Get recent versions from RECENT file
 	tflist = append(recentVersions, tflist...)          // Append recent versions to the top of the list
@@ -360,7 +368,8 @@ func InstallOption(listAll bool, customBinaryPath, installPath string, mirrorURL
 			logger.Fatalf("Prompt failed %v", errPrompt)
 		}
 	}
-
-	install(tfversion, customBinaryPath, installPath, mirrorURL)
+	if !dryRun {
+		install(tfversion, customBinaryPath, installPath, mirrorURL)
+	}
 	os.Exit(0)
 }
diff --git a/lib/param_parsing/parameters.go b/lib/param_parsing/parameters.go
--- a/lib/param_parsing/parameters.go
+++ b/lib/param_parsing/parameters.go
@@ -10,6 +10,7 @@ type Params struct {
 	ChDirPath        string
 	CustomBinaryPath string
 	DefaultVersion   string
+	DryRun           bool
 	HelpFlag         bool
 	InstallPath      string
 	LatestFlag       bool
@@ -34,6 +35,7 @@ func GetParameters() Params {
 	getopt.StringVarLong(&params.ChDirPath, "chdir", 'c', "Switch to a different working directory before executing the given command. Ex: tfswitch --chdir terraform_project will run tfswitch in the terraform_project directory")
 	getopt.StringVarLong(&params.CustomBinaryPath, "bin", 'b', "Custom binary path. Ex: tfswitch -b "+lib.ConvertExecutableExt("/Users/username/bin/terraform"))
 	getopt.StringVarLong(&params.DefaultVersion, "default", 'd', "Default to this version in case no other versions could be detected. Ex: tfswitch --default 1.2.4")
+	getopt.BoolVarLong(&params.DryRun, "dry-run", 'r', "Only show what tfswitch would do. Don't download anything.")
 	getopt.BoolVarLong(&params.HelpFlag, "help", 'h', "Displays help message")
 	getopt.StringVarLong(&params.InstallPath, "install", 'i', "Custom install path. Ex: tfswitch -i /Users/username. The binaries will be in the sub installDir directory e.g. /Users/username/"+lib.InstallDir)
 	getopt.BoolVarLong(&params.LatestFlag, "latest", 'u', "Get latest stable version")
@@ -90,6 +92,7 @@ func initParams(params Params) Params {
 	params.ChDirPath = lib.GetCurrentDirectory()
 	params.CustomBinaryPath = lib.ConvertExecutableExt(lib.GetDefaultBin())
 	params.DefaultVersion = lib.DefaultLatest
+	params.DryRun = false
 	params.HelpFlag = false
 	params.InstallPath = lib.GetHomeDirectory()
 	params.LatestFlag = false
diff --git a/main.go b/main.go
--- a/main.go
+++ b/main.go
@@ -44,32 +44,32 @@ func main() {
 		os.Exit(0)
 	case parameters.ListAllFlag:
 		/* show all terraform version including betas and RCs*/
-		lib.InstallOption(true, parameters.CustomBinaryPath, parameters.InstallPath, parameters.MirrorURL)
+		lib.InstallOption(true, parameters.DryRun, parameters.CustomBinaryPath, parameters.InstallPath, parameters.MirrorURL)
 	case parameters.LatestPre != "":
 		/* latest pre-release implicit version. Ex: tfswitch --latest-pre 0.13 downloads 0.13.0-rc1 (latest) */
-		lib.InstallLatestImplicitVersion(parameters.LatestPre, parameters.CustomBinaryPath, parameters.InstallPath, parameters.MirrorURL, true)
+		lib.InstallLatestImplicitVersion(parameters.DryRun, parameters.LatestPre, parameters.CustomBinaryPath, parameters.InstallPath, parameters.MirrorURL, true)
 	case parameters.ShowLatestPre != "":
 		/* show latest pre-release implicit version. Ex: tfswitch --latest-pre 0.13 downloads 0.13.0-rc1 (latest) */
 		lib.ShowLatestImplicitVersion(parameters.ShowLatestPre, parameters.MirrorURL, true)
 	case parameters.LatestStable != "":
 		/* latest implicit version. Ex: tfswitch --latest-stable 0.13 downloads 0.13.5 (latest) */
-		lib.InstallLatestImplicitVersion(parameters.LatestStable, parameters.CustomBinaryPath, parameters.InstallPath, parameters.MirrorURL, false)
+		lib.InstallLatestImplicitVersion(parameters.DryRun, parameters.LatestStable, parameters.CustomBinaryPath, parameters.InstallPath, parameters.MirrorURL, false)
 	case parameters.ShowLatestStable != "":
 		/* show latest implicit stable version. Ex: tfswitch --show-latest-stable 0.13 downloads 0.13.5 (latest) */
 		lib.ShowLatestImplicitVersion(parameters.ShowLatestStable, parameters.MirrorURL, false)
 	case parameters.LatestFlag:
 		/* latest stable version */
-		lib.InstallLatestVersion(parameters.CustomBinaryPath, parameters.InstallPath, parameters.MirrorURL)
+		lib.InstallLatestVersion(parameters.DryRun, parameters.CustomBinaryPath, parameters.InstallPath, parameters.MirrorURL)
 	case parameters.ShowLatestFlag:
 		/* show latest stable version */
 		lib.ShowLatestVersion(parameters.MirrorURL)
 	case parameters.Version != "":
-		lib.InstallVersion(parameters.Version, parameters.CustomBinaryPath, parameters.InstallPath, parameters.MirrorURL)
+		lib.InstallVersion(parameters.DryRun, parameters.Version, parameters.CustomBinaryPath, parameters.InstallPath, parameters.MirrorURL)
 	case parameters.DefaultVersion != "":
 		/* if default version is provided - Pick this instead of going for prompt */
-		lib.InstallVersion(parameters.DefaultVersion, parameters.CustomBinaryPath, parameters.InstallPath, parameters.MirrorURL)
+		lib.InstallVersion(parameters.DryRun, parameters.DefaultVersion, parameters.CustomBinaryPath, parameters.InstallPath, parameters.MirrorURL)
 	default:
 		// Set list all false - only official release will be displayed
-		lib.InstallOption(false, parameters.CustomBinaryPath, parameters.InstallPath, parameters.MirrorURL)
+		lib.InstallOption(false, parameters.DryRun, parameters.CustomBinaryPath, parameters.InstallPath, parameters.MirrorURL)
 	}
 }


Test patch:
diff --git a/lib/download_test.go b/lib/download_test.go
--- a/lib/download_test.go
+++ b/lib/download_test.go
@@ -6,6 +6,7 @@ import (
 	"os"
 	"path/filepath"
 	"runtime"
+	"sync"
 	"testing"
 
 	"github.com/mitchellh/go-homedir"
@@ -13,7 +14,7 @@ import (
 
 // TestDownloadFromURL_FileNameMatch : Check expected filename exist when downloaded
 func TestDownloadFromURL_FileNameMatch(t *testing.T) {
-
+	logger = InitLogger("DEBUG")
 	hashiURL := "https://releases.hashicorp.com/terraform/"
 	installVersion := "terraform_"
 	tempDir := t.TempDir()
@@ -45,10 +46,11 @@ func TestDownloadFromURL_FileNameMatch(t *testing.T) {
 
 	/* test download old terraform version */
 	lowestVersion := "0.11.0"
-
+	var wg sync.WaitGroup
+	defer wg.Done()
 	urlToDownload := hashiURL + lowestVersion + "/" + installVersion + lowestVersion + macOS
 	expectedFile := filepath.Join(installLocation, installVersion+lowestVersion+macOS)
-	installedFile, errDownload := downloadFromURL(installLocation, urlToDownload)
+	installedFile, errDownload := downloadFromURL(installLocation, urlToDownload, &wg)
 
 	if errDownload != nil {
 		t.Logf("Expected file name %v to be downloaded", expectedFile)
diff --git a/lib/param_parsing/parameters_test.go b/lib/param_parsing/parameters_test.go
--- a/lib/param_parsing/parameters_test.go
+++ b/lib/param_parsing/parameters_test.go
@@ -2,7 +2,9 @@ package param_parsing
 
 import (
 	"github.com/pborman/getopt"
+	"github.com/warrensbox/terraform-switcher/lib"
 	"os"
+	"path/filepath"
 	"testing"
 )
 
@@ -41,11 +43,13 @@ func TestGetParameters_params_are_overridden_by_toml_file(t *testing.T) {
 	if actual != expected {
 		t.Error("Version Param was not as expected. Actual: " + actual + ", Expected: " + expected)
 	}
-}
-func TestGetParameters_toml_params_are_overridden_by_cli(t *testing.T) {
 	t.Cleanup(func() {
 		getopt.CommandLine = getopt.New()
 	})
+}
+
+func TestGetParameters_toml_params_are_overridden_by_cli(t *testing.T) {
+	logger = lib.InitLogger("DEBUG")
 	expected := "../../test-data/integration-tests/test_tfswitchtoml"
 	os.Args = []string{"cmd", "--chdir=" + expected, "--bin=/usr/test/bin"}
 	params := GetParameters()
@@ -64,6 +68,27 @@ func TestGetParameters_toml_params_are_overridden_by_cli(t *testing.T) {
 	if actual != expected {
 		t.Error("Version Param was not as expected. Actual: " + actual + ", Expected: " + expected)
 	}
+	t.Cleanup(func() {
+		getopt.CommandLine = getopt.New()
+	})
+}
+
+func TestGetParameters_dry_run_wont_download_anything(t *testing.T) {
+	logger = lib.InitLogger("DEBUG")
+	expected := "../../test-data/integration-tests/test_versiontf"
+	os.Args = []string{"cmd", "--chdir=" + expected, "--bin=/tmp", "--dry-run"}
+	params := GetParameters()
+	installLocation := lib.GetInstallLocation(params.InstallPath)
+	installFileVersionPath := lib.ConvertExecutableExt(filepath.Join(installLocation, lib.VersionPrefix+params.Version))
+	// Make sure the file tfswitch WOULD download is absent
+	_ = os.Remove(installFileVersionPath)
+	lib.InstallVersion(params.DryRun, params.Version, params.CustomBinaryPath, params.InstallPath, params.MirrorURL)
+	if lib.FileExistsAndIsNotDir(installFileVersionPath) {
+		t.Error("Dry run should NOT download any files.")
+	}
+	t.Cleanup(func() {
+		getopt.CommandLine = getopt.New()
+	})
 }
 
 func TestGetParameters_check_config_precedence(t *testing.T) {
@@ -76,4 +101,7 @@ func TestGetParameters_check_config_precedence(t *testing.T) {
 	if parameters.Version != expected {
 		t.Error("Version Param was not as expected. Actual: " + parameters.Version + ", Expected: " + expected)
 	}
+	t.Cleanup(func() {
+		getopt.CommandLine = getopt.New()
+	})
 }