diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 7e895b8e..2e9602b5 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -6,7 +6,7 @@ In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal +level of experience, education, socioeconomic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards diff --git a/README.md b/README.md index e61956fa..52f47700 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ ## About The Project Welcome to **tenv**, a versatile version manager for [OpenTofu](https://opentofu.org), -[Terraform](https://www.terraform.io/) [Terragrunt](https://terragrunt.gruntwork.io/) and +[Terraform](https://www.terraform.io/), [Terragrunt](https://terragrunt.gruntwork.io/) and [Atmos](https://atmos.tools), written in Go. Our tool simplifies the complexity of handling different versions of these powerful tools, ensuring developers and DevOps professionals can focus on what matters most - building and deploying efficiently. **tenv** is a successor of [tofuenv](https://github.com/tofuutils/tofuenv) and [tfenv](https://github.com/tfutils/tfenv). @@ -32,7 +32,7 @@ Welcome to **tenv**, a versatile version manager for [OpenTofu](https://opentofu ### Key Features - Versatile version management: Easily switch between different versions of OpenTofu, -Terraform Terragrunt and Atmos. +Terraform, Terragrunt and Atmos. - [Semver 2.0.0](https://semver.org/) Compatibility: Utilizes [go-version](https://github.com/hashicorp/go-version) for semantic versioning and use the [HCL](https://github.com/hashicorp/hcl) parser to extract required version constraint from OpenTofu/Terraform/Terragrunt files (see [required_version](#required_version) and [Terragrunt hcl](#terragrunt-hcl-file)). - Signature verification: Supports [cosign](https://github.com/sigstore/cosign) (if present on your machine) and PGP (via [gopenpgp](https://github.com/ProtonMail/gopenpgp)), see [signature support](#signature-support). - Intuitive installation: Simple installation process with Homebrew and manual options. @@ -44,7 +44,7 @@ Terraform Terragrunt and Atmos. asdf is generic and extensible with a plugin system, key **tenv** differences : -- **tenv** is more specific and has features dedicated to OpenTofu, Terraform Terragrunt +- **tenv** is more specific and has features dedicated to OpenTofu, Terraform, Terragrunt and Atmos, like [HCL](https://github.com/hashicorp/hcl) parsing based detection (see [Key Features](#key-features)). - **tenv** is distributed as independent binaries and does not rely on any shell or other CLI executable. @@ -651,7 +651,7 @@ Same as TENV_FORCE_REMOTE.
TOFUENV_INSTALL_MODE
-String (Default: "api") +String (the default depend on TOFUENV_REMOTE, without change on it, it is "api" else it is "direct") - "api" install mode retrieve download url of OpenTofu from [Github REST API](https://docs.github.com/en/rest?apiVersion=2022-11-28) (TOFUENV_REMOTE must comply with it). - "direct" install mode generate download url of OpenTofu based on TOFUENV_REMOTE. @@ -663,7 +663,7 @@ See [advanced remote configuration](#advanced-remote-configuration) for more det
TOFUENV_LIST_MODE
-String (Default: "api") +String (the default depend on TOFUENV_LIST_URL, without change on it, it is "api" else it is "html") - "api" list mode retrieve information of OpenTofu releases from [Github REST API](https://docs.github.com/en/rest?apiVersion=2022-11-28) (TOFUENV_LIST_URL must comply with it). - "html" list mode extract information of OpenTofu releases from parsing an html page in TOFUENV_LIST_URL. @@ -675,12 +675,9 @@ See [advanced remote configuration](#advanced-remote-configuration) for more det
TOFUENV_LIST_URL
-String (Default: "") - -Allow to override the remote url only for the releases listing, default value depend on TOFUENV_LIST_MODE : +String (Default: copy TOFUENV_REMOTE) -- with "api" mode use default API URL (https://api.github.com/repos/opentofu/opentofu/releases) -- with "html" mode same as TOFUENV_REMOTE +Allow to override the remote url only for the releases listing. See [advanced remote configuration](#advanced-remote-configuration) for more details. @@ -702,7 +699,7 @@ Allow to specify a local file path to OpenTofu PGP public key, if not present do String (Default: https://api.github.com/repos/opentofu/opentofu/releases) -URL to install OpenTofu, when TOFUENV_REMOTE differ from its default value, TOFUENV_INSTALL_MODE is set to direct (assume an artifact proxy usage, however releases listing continue to use API). +URL to install OpenTofu, when TOFUENV_REMOTE differ from its default value, TOFUENV_INSTALL_MODE is set to "direct" and TOFUENV_LIST_MODE is set to "html" (assume an artifact proxy usage). `tenv tofu` subcommands `detect`, `install`, `list-remote` and `use` support a `--remote-url`, `-u` flag version. @@ -819,7 +816,7 @@ See [advanced remote configuration](#advanced-remote-configuration) for more det
TFENV_LIST_MODE
-String (Default: "api") +String (the default depend on TFENV_LIST_URL, without change on it, it is "api" else it is "html") - "api" list mode retrieve information of Terraform releases from [Hashicorp Release API](https://releases.hashicorp.com/docs/api/v1) (TFENV_LIST_URL must comply with it). - "html" list mode extract information of Terraform releases from parsing an html page in TFENV_LIST_URL. @@ -831,12 +828,9 @@ See [advanced remote configuration](#advanced-remote-configuration) for more det
TFENV_LIST_URL
-String (Default: "") - -Allow to override the remote url only for the releases listing, default value depend on TFENV_LIST_MODE : +String (Default: copy TFENV_REMOTE) -- with "api" mode use default API URL (https://releases.hashicorp.com) -- with "html" mode same as TFENV_REMOTE +Allow to override the remote url only for the releases listing. See [advanced remote configuration](#advanced-remote-configuration) for more details. @@ -847,7 +841,7 @@ See [advanced remote configuration](#advanced-remote-configuration) for more det String (Default: https://releases.hashicorp.com) -URL to install Terraform (can differ from its default, an artifact proxy will not disturb the retrieving of release index.json, however releases listing continue to use API). +URL to install Terraform, changing it assume an artifact proxy use (TFENV_LIST_URL copy it, and if it differ from its default value, TFENV_LIST_MODE is set to "html", because an artifact proxy usage will not disturb the retrieving of index.json for a release, but will freeze the json list of releases). `tenv tf` subcommands `detect`, `install`, `list-remote` and `use` support a `--remote-url`, `-u` flag version. @@ -917,7 +911,7 @@ is 1.7.2. You can update by downloading from https://www.terraform.io/downloads.
TG_INSTALL_MODE
-String (Default: "api") +String (the default depend on TG_REMOTE, without change on it, it is "api" else it is "direct") - "api" install mode retrieve download url of Terragrunt from [Github REST API](https://docs.github.com/en/rest?apiVersion=2022-11-28) (TG_REMOTE must comply with it). - "direct" install mode generate download url of Terragrunt based on TG_REMOTE. @@ -929,7 +923,7 @@ See [advanced remote configuration](#advanced-remote-configuration) for more det
TG_LIST_MODE
-String (Default: "api") +String (the default depend on TG_LIST_URL, without change on it, it is "api" else it is "html") - "api" list mode retrieve information of Terragrunt releases from [Github REST API](https://docs.github.com/en/rest?apiVersion=2022-11-28) (TG_LIST_URL must comply with it). - "html" list mode extract information of Terragrunt releases from parsing an html page in TG_LIST_URL. @@ -941,12 +935,9 @@ See [advanced remote configuration](#advanced-remote-configuration) for more det
TG_LIST_URL
-String (Default: "") - -Allow to override the remote url only for the releases listing, default value depend on TG_LIST_MODE : +String (Default: copy TG_REMOTE) -- with "api" mode use default API URL (https://api.github.com/repos/gruntwork-io/terragrunt/releases) -- with "html" mode same as TG_REMOTE +Allow to override the remote url only for the releases listing. See [advanced remote configuration](#advanced-remote-configuration) for more details. @@ -957,7 +948,7 @@ See [advanced remote configuration](#advanced-remote-configuration) for more det String (Default: https://api.github.com/repos/gruntwork-io/terragrunt/releases) -URL to install Terragrunt, when TG_REMOTE differ from its default value, TG_INSTALL_MODE is set to "direct" (assume an artifact proxy usage, however releases listing continue to use API). +URL to install Terragrunt, when TG_REMOTE differ from its default value, TG_INSTALL_MODE is set to "direct" and TG_LIST_MODE is set to "html" (assume an artifact proxy usage). `tenv tg` subcommands `detect`, `install`, `list-remote` and `use` support a `--remote-url`, `-u` flag version. @@ -1013,7 +1004,7 @@ terragrunt version v0.54.1
ATMOS_INSTALL_MODE
-String (Default: "api") +String (the default depend on ATMOS_REMOTE, without change on it, it is "api" else it is "direct") - "api" install mode retrieve download url of Atmos from [Github REST API](https://docs.github.com/en/rest?apiVersion=2022-11-28) (ATMOS_REMOTE must comply with it). - "direct" install mode generate download url of Atmos based on ATMOS_REMOTE. @@ -1025,7 +1016,7 @@ See [advanced remote configuration](#advanced-remote-configuration) for more det
ATMOS_LIST_MODE
-String (Default: "api") +String (the default depend on ATMOS_LIST_URL, without change on it, it is "api" else it is "html") - "api" list mode retrieve information of Atmos releases from [Github REST API](https://docs.github.com/en/rest?apiVersion=2022-11-28) (ATMOS_LIST_URL must comply with it). - "html" list mode extract information of Atmos releases from parsing an html page in ATMOS_LIST_URL. @@ -1037,12 +1028,9 @@ See [advanced remote configuration](#advanced-remote-configuration) for more det
ATMOS_LIST_URL
-String (Default: "") - -Allow to override the remote url only for the releases listing, default value depend on ATMOS_LIST_MODE : +String (Default: copy ATMOS_REMOTE) -- with "api" mode use default API URL (https://api.github.com/repos/cloudposse/atmos/releases) -- with "html" mode same as ATMOS_REMOTE +Allow to override the remote url only for the releases listing. See [advanced remote configuration](#advanced-remote-configuration) for more details. @@ -1053,7 +1041,7 @@ See [advanced remote configuration](#advanced-remote-configuration) for more det String (Default: https://api.github.com/repos/cloudposse/atmos/releases) -URL to install Atmos when ATMOS_REMOTE differ from its default value, ATMOS_INSTALL_MODE is set to "direct" (assume an artifact proxy usage, however releases listing continue to use API). +URL to install Atmos when ATMOS_REMOTE differ from its default value, ATMOS_INSTALL_MODE is set to "direct" and ATMOS_LIST_MODE is set to "html" (assume an artifact proxy usage). `tenv atmos` subcommands `detect`, `install`, `list-remote` and `use` support a `--remote-url`, `-u` flag version. @@ -1318,14 +1306,14 @@ Those examples assume that a GitHub proxy at https://artifactory.example.com/art - mirror https://github.com/opentofu/opentofu/releases/download/v1.6.0/tofu_1.6.0_linux_amd64.zip at https://artifactory.example.com/artifactory/github/opentofu/opentofu/releases/download/v1.6.0/tofu_1.6.0_linux_amd64.zip. - have at https://artifactory.example.com/artifactory/github/opentofu/opentofu/releases/download an html page with links on existing sub folder like "v1.6.0/" -Example 1 : Retrieve Terraform binaries and list available releases from the mirror. +Example 1 : Retrieve Terraform binaries and list available releases from the mirror (TFENV_LIST_MODE is optional because TFENV_LIST_URL differ from its default(when TFENV_LIST_URL is not set, it copy TFENV_REMOTE)). ```console TFENV_REMOTE=https://artifactory.example.com/artifactory/hashicorp TFENV_LIST_MODE=html ``` -Example 2 : Retrieve Terraform binaries from the mirror and list available releases from the Hashicorp releases API (TFENV_LIST_URL is optional because it default to https://releases.hashicorp.com with the default list mode "api"). +Example 2 : Retrieve Terraform binaries from the mirror and list available releases from the Hashicorp releases API. ```console TFENV_REMOTE=https://artifactory.example.com/artifactory/hashicorp @@ -1334,7 +1322,7 @@ TFENV_LIST_URL=https://releases.hashicorp.com Example 1 & 2, does not need install mode (by release index.json is figed in mirror without problem), however create a rewrite rule from "https://releases.hashicorp.com" to "https://artifactory.example.com/artifactory/hashicorp" to obtains correct download URLs. -Example 3 : Retrieve OpenTofu binaries and list available releases from the mirror (TOFUENV_INSTALL_MODE is optional because overloading TOFUENV_REMOTE already set it to "direct"). +Example 3 : Retrieve OpenTofu binaries and list available releases from the mirror (TOFUENV_INSTALL_MODE and TOFUENV_LIST_MODE are optional because overloading TOFUENV_REMOTE already change them). ```console TOFUENV_REMOTE=https://artifactory.example.com/artifactory/github @@ -1342,7 +1330,7 @@ TOFUENV_INSTALL_MODE=direct TOFUENV_LIST_MODE=html ``` -Example 4 : Retrieve OpenTofu binaries from the mirror and list available releases from the GitHub API (TOFUENV_INSTALL_MODE is optional because overloading TOFUENV_REMOTE already set it to "direct", and TOFUENV_LIST_URL is optional because it default to https://api.github.com/repos/opentofu/opentofu/releases with the default list mode "api"). +Example 4 : Retrieve OpenTofu binaries from the mirror and list available releases from the GitHub API (TOFUENV_INSTALL_MODE is optional because overloading TOFUENV_REMOTE already set it to "direct"). ```console TOFUENV_REMOTE=https://artifactory.example.com/artifactory/github diff --git a/config/remote.go b/config/remote.go index 05a548cb..956e94bb 100644 --- a/config/remote.go +++ b/config/remote.go @@ -21,6 +21,7 @@ package config import ( "errors" "os" + "strings" ) const ( @@ -70,24 +71,25 @@ func (r RemoteConfig) GetInstallMode() string { } func (r RemoteConfig) GetListMode() string { - return r.getValueForcedDefault("list_mode", r.listMode, ModeAPI) + defaultListMode := ListModeHTML + if r.GetListURL() == r.defaultURL { + defaultListMode = ModeAPI + } + + return r.getValueForcedDefault("list_mode", r.listMode, defaultListMode) } func (r RemoteConfig) GetListURL() string { - defaultListURL := r.defaultURL - if r.GetListMode() == ListModeHTML { - defaultListURL = r.GetRemoteURL() - } - - return r.getValueForcedDefault("list_url", r.listURL, defaultListURL) + return strings.TrimRight(r.getValueForcedDefault("list_url", r.listURL, r.GetRemoteURL()), "/") } func (r RemoteConfig) GetRemoteURL() string { - if r.RemoteURL != "" { - return r.RemoteURL + remoteURL := r.RemoteURL + if remoteURL == "" { + remoteURL = r.getValueForcedDefault("url", r.RemoteURLEnv, r.defaultURL) } - return r.getValueForcedDefault("url", r.RemoteURLEnv, r.defaultURL) + return strings.TrimRight(remoteURL, "/") } func (r RemoteConfig) GetRewriteRule() []string { @@ -97,41 +99,22 @@ func (r RemoteConfig) GetRewriteRule() []string { return []string{oldBase, newBase} } - defaultListMode := r.GetListMode() == ModeAPI + if r.GetInstallMode() == InstallModeDirect { + return nil // build correct url + } + listURL := r.GetListURL() remoteURL := r.GetRemoteURL() - sameURL := remoteURL == listURL - if defaultListMode && sameURL { + defaultList := listURL == r.defaultURL + defaultRemote := remoteURL == r.defaultURL + if defaultList && defaultRemote { return nil // no special behaviour, no rewriting } - oneDisabled := defaultListMode || sameURL - if r.GetInstallMode() == ModeAPI { - if oldBase == "" { - oldBase = r.defaultBaseURL - } - - if newBase == "" { - if oneDisabled { - newBase = remoteURL - } else { - newBase = listURL - } - } - - return []string{oldBase, newBase} - } - - if oneDisabled { - return nil // build correct url (direct install mode) - } - - if oldBase == "" { - oldBase = remoteURL - } - - if newBase == "" { - newBase = listURL + oldBase = r.defaultBaseURL + newBase = listURL + if defaultList { + newBase = remoteURL } return []string{oldBase, newBase} @@ -146,7 +129,7 @@ func (r RemoteConfig) getValueForcedDefault(name string, forcedValue string, def } func MapGetDefault(m map[string]string, key string, defaultValue string) string { - if value := m[key]; value != "" { + if value := strings.TrimSpace(m[key]); value != "" { return value } diff --git a/go.mod b/go.mod index a82d376e..9ff1bd6b 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,12 @@ module github.com/tofuutils/tenv go 1.21 require ( - github.com/BurntSushi/toml v1.3.2 + github.com/BurntSushi/toml v1.4.0 github.com/ProtonMail/gopenpgp/v2 v2.7.5 github.com/PuerkitoBio/goquery v1.9.2 github.com/fatih/color v1.17.0 github.com/hashicorp/go-hclog v1.6.3 - github.com/hashicorp/go-version v1.6.0 + github.com/hashicorp/go-version v1.7.0 github.com/hashicorp/hcl/v2 v2.20.1 github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 diff --git a/go.sum b/go.sum index 08a282f0..ae551c59 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= +github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= @@ -35,6 +37,8 @@ github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB1 github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/hcl/v2 v2.20.1 h1:M6hgdyz7HYt1UN9e61j+qKJBqR3orTWbI1HKBJEdxtc= github.com/hashicorp/hcl/v2 v2.20.1/go.mod h1:TZDqQ4kNKCbh1iJp99FdPiUaVDDUPivbqxZulxDYqL4= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=