tfv 5.0.1 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/.github/workflows/publish.yml +27 -3
  2. package/README.md +190 -132
  3. package/demo.gif +0 -0
  4. package/demo.tape +230 -0
  5. package/index.js +0 -4
  6. package/lib/commands/apply.js +8 -3
  7. package/lib/commands/current.js +25 -0
  8. package/lib/commands/destroy.js +8 -3
  9. package/lib/commands/fmt.js +26 -0
  10. package/lib/commands/init.js +26 -0
  11. package/lib/commands/install.js +22 -13
  12. package/lib/commands/list.js +20 -11
  13. package/lib/commands/pin.js +26 -0
  14. package/lib/commands/plan.js +8 -3
  15. package/lib/commands/remove.js +17 -12
  16. package/lib/commands/shell-init.js +25 -0
  17. package/lib/commands/switch.js +28 -7
  18. package/lib/commands/upgrade.js +26 -0
  19. package/lib/commands/use.js +17 -13
  20. package/lib/commands/validate.js +21 -0
  21. package/lib/modules/current.js +52 -0
  22. package/lib/modules/install.js +155 -89
  23. package/lib/modules/list.js +66 -105
  24. package/lib/modules/pin.js +35 -0
  25. package/lib/modules/ps1.js +37 -29
  26. package/lib/modules/remote.js +68 -15
  27. package/lib/modules/remove.js +35 -21
  28. package/lib/modules/shell-init.js +113 -0
  29. package/lib/modules/switch.js +125 -41
  30. package/lib/modules/terraform-command.js +49 -67
  31. package/lib/modules/upgrade.js +93 -0
  32. package/lib/modules/use.js +58 -54
  33. package/lib/utils/formatVersions.js +57 -5
  34. package/lib/utils/paths.js +156 -0
  35. package/lib/utils/postInstall.js +37 -13
  36. package/lib/utils/store.js +17 -6
  37. package/package.json +11 -9
  38. package/test/extractTargets.test.js +75 -0
  39. package/test/formatVersions.test.js +126 -0
  40. package/test/moduleImports.test.js +45 -0
  41. package/test/paths.test.js +69 -0
  42. package/test/versionResolution.test.js +92 -0
@@ -2,27 +2,51 @@ name: Publish tfv to npm registry
2
2
 
3
3
  on:
4
4
  push:
5
- branches: [main]
5
+ tags:
6
+ - 'v[0-9]+.[0-9]+.[0-9]+' # only trigger on semver tags: v6.0.0, v6.1.0, etc.
6
7
 
7
8
  permissions:
8
9
  contents: read
9
10
  id-token: write
10
11
 
11
12
  jobs:
12
- publish:
13
+ test:
13
14
  runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - uses: actions/setup-node@v4
19
+ with:
20
+ node-version: 22
21
+ cache: 'npm'
14
22
 
23
+ - run: npm ci
24
+
25
+ - run: npm test
26
+
27
+ publish:
28
+ needs: test
29
+ runs-on: ubuntu-latest
15
30
  steps:
16
31
  - uses: actions/checkout@v4
17
32
 
18
33
  - uses: actions/setup-node@v4
19
34
  with:
20
- node-version: 18
35
+ node-version: 22
21
36
  registry-url: https://registry.npmjs.org
22
37
  cache: 'npm'
23
38
 
24
39
  - run: npm ci
25
40
 
41
+ - name: Verify package version matches git tag
42
+ run: |
43
+ PKG_VERSION="v$(node -p "require('./package.json').version")"
44
+ GIT_TAG="${{ github.ref_name }}"
45
+ if [ "$PKG_VERSION" != "$GIT_TAG" ]; then
46
+ echo "Version mismatch: package.json=$PKG_VERSION, tag=$GIT_TAG"
47
+ exit 1
48
+ fi
49
+
26
50
  - run: npm publish --access public
27
51
  env:
28
52
  NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
package/README.md CHANGED
@@ -1,5 +1,6 @@
1
- # Use `tfv` to manage multiple versions of terraform with ease
1
+ # tfv Terraform & OpenTofu Version Manager
2
2
 
3
+ ```
3
4
  _ ________ __
4
5
  _| |__ / _____|\ \ / /
5
6
  |_ ___\ | |___ \ \ / /
@@ -7,229 +8,286 @@
7
8
  | |___ | | \ \/ /
8
9
  \______\_| \__/
9
10
 
10
- Happy terraforming 😍🥂!
11
- ---------------------------------------
11
+ Happy terraforming! 😍🥂
12
+ ---------------------------------
13
+ ```
14
+
15
+ `tfv` lets you install, switch, and manage multiple versions of **Terraform** and **OpenTofu** without `sudo`. All binaries live in `~/.tfv/` — upgrading `tfv` itself never wipes your installed versions.
12
16
 
13
- ## Installation
17
+ ![tfv demo](demo.gif)
14
18
 
15
- > **_NOTE:_** `tfv` should be installed `globally` so that it can be run from anywhere on your computer.
19
+ ---
20
+
21
+ ## Installation
16
22
 
17
23
  ```sh
18
24
  npm install -g tfv
19
25
  ```
20
26
 
21
- Run with alias
27
+ `tfv` automatically adds `~/.tfv/bin` to your PATH on install (shell configs + Windows User PATH). Restart your terminal once after install.
22
28
 
23
- ```sh
24
- npm i -g tfv
25
- ```
29
+ ---
26
30
 
27
- ## Help
31
+ ## How it works
28
32
 
29
- ```sh
30
- tfv --help
33
+ ```
34
+ npm install -g tfv
35
+
36
+
37
+ postInstall.js
38
+ ├── creates ~/.tfv/bin/, ~/.tfv/store/, ~/.tfv/cache/
39
+ └── adds ~/.tfv/bin to PATH (shell configs / Windows registry)
40
+
41
+
42
+ tfv install 1.9.0
43
+ ├── fetches version list → ~/.tfv/cache/terraform-versions.json (1hr TTL)
44
+ ├── downloads zip → system temp dir (with progress bar)
45
+ ├── verifies SHA256 → HashiCorp / OpenTofu checksums
46
+ ├── extracts binary only → ~/.tfv/store/terraform/1.9.0
47
+ └── records arch → ~/.tfv/store/terraform/arch.json
48
+
49
+
50
+ tfv use 1.9.0
51
+ ├── copies ~/.tfv/store/terraform/1.9.0 → ~/.tfv/bin/terraform
52
+ └── writes active version → ~/.tfv/active.json
53
+
54
+
55
+
56
+ terraform plan ← resolves to ~/.tfv/bin/terraform (same binary as tfv)
57
+ tfv plan ← spawns ~/.tfv/bin/terraform directly (no PATH lookup)
31
58
  ```
32
59
 
33
- Run with alias
60
+ Both `terraform` and `tfv` commands always use the **exact same binary**.
34
61
 
35
- ```sh
36
- tfv -h
37
- ```
62
+ ---
38
63
 
39
- > **_OUTPUT:_**
64
+ ## Store layout
40
65
 
41
66
  ```
42
- tfv <command>
67
+ ~/.tfv/
68
+ bin/
69
+ terraform ← active terraform binary (no sudo, no symlinks)
70
+ tofu ← active opentofu binary
71
+ store/
72
+ terraform/
73
+ 1.9.0 ← installed versions (binary renamed to version number)
74
+ 1.7.3
75
+ arch.json ← { "1.9.0": "arm64", "1.7.3": "amd64" }
76
+ opentofu/
77
+ 1.8.0
78
+ arch.json
79
+ cache/
80
+ terraform-versions.json ← remote list cached for 1 hour
81
+ opentofu-versions.json
82
+ active.json ← { "terraform": "1.9.0", "opentofu": null }
83
+ ```
43
84
 
44
- Commands:
85
+ ---
45
86
 
46
- tfv install <version> [option] Install a terraform version [aliases: i]
87
+ ## Commands
47
88
 
48
- tfv list [option] List installed or available terraform versions [aliases: ls]
89
+ ### Install
49
90
 
50
- tfv remove <version> Remove terraform versions from tfv store [aliases: rm]
91
+ ```sh
92
+ tfv install latest # latest stable
93
+ tfv install 1.9.0 # exact version
94
+ tfv install 1.9.^ # latest 1.9.x patch
95
+ tfv install 1.8.0-beta1 # explicit pre-release (warns you)
96
+ tfv install latest --provider tofu # OpenTofu
97
+ tfv install 1.9.0 --arch amd64 # override architecture
98
+ ```
51
99
 
52
- tfv auto-switch Auto-detect and switch to your project terraform version [aliases: as]
100
+ Aliases: `tfv i`
53
101
 
54
- tfv use <version> Switch to a specified terraform version
102
+ ---
55
103
 
56
- tfv apply Run terraform apply with optional file-based targets.
57
- Accepts all terraform flags after --
58
- Example:
59
- tfv apply --file main.tf --file network.tf -- -auto-approve -target=<TARGET> -var="env=prod"
104
+ ### Switch version
60
105
 
61
- tfv destroy Run terraform destroy with optional file-based targets.
62
- Accepts all terraform flags after --
63
- Example:
64
- tfv destroy --file main.tf --file network.tf -- -auto-approve -target=<TARGET> -var="env=prod"
106
+ ```sh
107
+ tfv use 1.9.0
108
+ tfv use latest # latest installed version
109
+ tfv use 1.8.0 --provider tofu
110
+ ```
65
111
 
66
- tfv plan Run terraform plan with optional file-based targets.
67
- Accepts all terraform flags after --
68
- Example:
69
- tfv plan --file main.tf --file network.tf -- -auto-approve -target=<TARGET> -var="env=prod"
112
+ No `sudo`. Copies binary to `~/.tfv/bin/terraform`.
70
113
 
71
- Options:
72
- -h, --help Show help [boolean]
73
- -v, --version Show version number [boolean]
74
- ```
114
+ ---
75
115
 
76
- # Usage
116
+ ### Auto-switch
77
117
 
78
- https://github.com/marcdomain/tfv/assets/25563661/fa44f0f2-2dca-4f22-9fea-c74e4b8f767c
118
+ Detects and switches to the version your project requires. Installs it if not already in store.
79
119
 
80
- # Table of Contents
120
+ ```sh
121
+ tfv auto-switch
122
+ tfv as # alias
123
+ tfv as --provider tofu
124
+ ```
81
125
 
82
- <!--ts-->
83
- * [Table of Contents](#table-of-contents)
84
- * [Modules](#modules)
85
- * [install](#install)
86
- * [use](#use)
87
- * [list](#list)
88
- * [remove](#remove)
89
- * [auto-switch](#auto-switch)
90
- * [plan](#plan)
91
- * [apply](#apply)
92
- * [destroy](#destroy)
93
- <!--te-->
126
+ Reads version from (in priority order):
94
127
 
95
- ### Modules
128
+ 1. `.terraform-version` file in current directory
129
+ 2. `terraform.tfstate` → `terraform_version` field
130
+ 3. `required_version` in any `.tf` file — supports all constraint operators:
131
+ `=`, `>=`, `>`, `<=`, `<`, `!=`, `~>`, and compound `">= 1.3, < 2.0"`
96
132
 
97
- - #### _INSTALL_
133
+ ---
98
134
 
99
- | Version | Description |
100
- | ---------------- | ------------------------------------------ |
101
- | x.x.x | Installs terraform version x.x.x |
102
- | x^ | Installs latest version of release x |
103
- | x.x.^ | Installs latest version of release x.x |
104
- | latest | Installs latest version of terraform |
135
+ ### Shell hook — auto-switch on `cd`
105
136
 
106
- ```sh
107
- tfv install <version>
108
- ```
137
+ Wraps `cd` so that entering a directory automatically switches the terraform version — but **only if the directory looks like a terraform project**. Non-terraform folders have zero overhead (one filesystem check, no subprocess).
109
138
 
110
- Run with option
139
+ A directory is considered a terraform project if it contains:
140
+ - a `.terraform-version` file, **or**
141
+ - any `*.tf` files
111
142
 
112
143
  ```sh
113
- tfv install <version> --arch <system-architecture>
144
+ cd ~/Downloads # no .tf files → nothing happens
145
+ cd ~/projects/react-app # no .tf files → nothing happens
146
+ cd ~/projects/infra # has main.tf → auto-switch runs silently
147
+ cd ~/projects/platform # has .terraform-version → auto-switch runs silently
114
148
  ```
115
149
 
116
- EXAMPLE:
150
+ Setup (one-time, add to your shell config):
117
151
 
118
152
  ```sh
119
- tfv install 1.5.7 -arch amd64
120
- ```
121
-
122
- > NOTE: The default *system-architecture* is the architecture of your computer (arm64, amd64, x64, etc...)
153
+ # Bash
154
+ echo 'eval "$(tfv shell-init bash)"' >> ~/.bashrc
123
155
 
124
- - #### _USE_
156
+ # Zsh
157
+ echo 'eval "$(tfv shell-init zsh)"' >> ~/.zshrc
125
158
 
126
- | Version | Description |
127
- | ---------------- | ----------------------------------------- |
128
- | x.x.x | use terraform version x.x.x |
129
- | latest | use latest version of terraform |
159
+ # Fish
160
+ echo 'tfv shell-init fish | source' >> ~/.config/fish/config.fish
130
161
 
131
- ```sh
132
- tfv use <version>
162
+ # PowerShell
163
+ echo 'Invoke-Expression (tfv shell-init powershell | Out-String)' >> $PROFILE
133
164
  ```
134
165
 
135
- > **_NOTE:_** You would get a password prompt. Accept it. This is a one-time request to set the terraform executable in your system path.
166
+ After setup, entering a terraform project switches the version automatically no manual `tfv as` needed.
136
167
 
137
- - #### _LIST_
168
+ ---
138
169
 
139
- | Option | Option Alias | Description |
140
- | ---------------|---------------|--------------------------------------------------------------------------------|
141
- | | | Defaults to listing terraform versions installed locally (in tfv store) |
142
- | `--local` | `-l` | Lists all terraform versions installed locally |
143
- | `--remote` | `-r` | Lists all terraform versions available remotely, on terraform server |
170
+ ### List versions
144
171
 
145
172
  ```sh
146
- tfv list [option]
173
+ tfv list # installed versions (default)
174
+ tfv ls --remote # all available versions from HashiCorp
175
+ tfv ls --remote --provider tofu # all available OpenTofu versions
147
176
  ```
148
177
 
149
- Run with alias
178
+ Active version is marked with 🚀.
150
179
 
151
- ```sh
152
- tfv ls [option]
153
- ```
154
-
155
- - #### _REMOVE_
180
+ ---
156
181
 
157
- Remove terraform versions managed by tfv
182
+ ### Current version
158
183
 
159
184
  ```sh
160
- tfv remove <versions>
185
+ tfv current # shows active version + PATH status
186
+ tfv which # alias
187
+ tfv current --provider tofu
161
188
  ```
162
189
 
163
- Run with alias
164
-
165
- ```sh
166
- tfv rm <versions>
190
+ Example output:
191
+ ```
192
+ Active terraform version: 1.9.0
193
+ Binary: /Users/you/.tfv/bin/terraform
194
+ Reported: Terraform v1.9.0
195
+ PATH OK — 'terraform' resolves to tfv-managed binary
167
196
  ```
168
197
 
169
- Example
198
+ ---
199
+
200
+ ### Pin version
201
+
202
+ Writes a `.terraform-version` file in the current directory so teammates get the same version via `tfv auto-switch`:
170
203
 
171
204
  ```sh
172
- tfv rm x.y.z z.x.y
205
+ tfv pin # pin currently active version
206
+ tfv pin 1.9.0 # pin a specific version
207
+ tfv pin --provider tofu
173
208
  ```
174
209
 
175
- - #### _AUTO-SWITCH_
210
+ ---
176
211
 
177
- Auto-detects your project terraform version, downloads it if it's not in tfv store, and switch to the version
212
+ ### Upgrade
178
213
 
179
214
  ```sh
180
- tfv auto-switch
215
+ tfv upgrade # upgrade active 1.6.3 → latest 1.6.x patch
216
+ tfv upgrade 1.9 # install + use latest 1.9.x
217
+ tfv upgrade latest # install + use absolute latest
218
+ tfv upgrade --provider tofu
181
219
  ```
182
220
 
183
- Run with alias
221
+ Also re-anchors `~/.tfv/bin` in PATH to ensure it takes precedence over any system-installed terraform.
222
+
223
+ ---
224
+
225
+ ### Remove
184
226
 
185
227
  ```sh
186
- tfv as
228
+ tfv remove 1.7.3
229
+ tfv rm 1.7.3 1.6.6 # remove multiple
230
+ tfv rm 1.8.0 --provider tofu
187
231
  ```
188
232
 
189
- - #### _PLAN_
233
+ Warns if you're removing the currently active version.
190
234
 
191
- Run terraform plan with optional file-based targets. Parses terraform files to extract resources, data sources, and modules as targets.
235
+ ---
192
236
 
193
- ```sh
194
- tfv plan --file main.tf
195
- ```
237
+ ### Terraform commands (via tfv)
196
238
 
197
- With multiple files
239
+ All commands use the tfv-managed binary and accept extra terraform flags after `--`:
198
240
 
199
241
  ```sh
200
- tfv plan --file main.tf --file network.tf
242
+ tfv init
243
+ tfv validate
244
+ tfv fmt
245
+ tfv fmt -- -recursive
246
+
247
+ tfv plan
248
+ tfv plan --file main.tf # extract targets from file
249
+ tfv plan --file main.tf --file network.tf # multiple files
250
+ tfv plan --file main.tf -- -var="env=prod" # with extra terraform flags
251
+
252
+ tfv apply --file main.tf -- -auto-approve
253
+ tfv destroy --file main.tf -- -auto-approve
201
254
  ```
202
255
 
203
- With extra terraform flags
256
+ `--file` parses `.tf` files and auto-generates `-target` flags for every `resource`, `data`, and `module` block found. Comments are stripped before parsing.
204
257
 
205
- ```sh
206
- tfv plan --file main.tf -- -var="env=prod" -out=plan.out
207
- ```
258
+ All commands support `--provider tofu` to use OpenTofu instead.
259
+
260
+ ---
208
261
 
209
- - #### _APPLY_
262
+ ## OpenTofu support
210
263
 
211
- Run terraform apply with optional file-based targets.
264
+ Every command works with OpenTofu via `--provider tofu` (or `--provider opentofu`):
212
265
 
213
266
  ```sh
214
- tfv apply --file main.tf
267
+ tfv install latest --provider tofu
268
+ tfv use 1.8.0 --provider tofu
269
+ tfv list --remote --provider tofu
270
+ tfv current --provider tofu
271
+ tfv plan --provider tofu
215
272
  ```
216
273
 
217
- With auto-approve
274
+ OpenTofu binaries are stored separately from Terraform in `~/.tfv/store/opentofu/` and activated as `~/.tfv/bin/tofu`.
218
275
 
219
- ```sh
220
- tfv apply --file main.tf -- -auto-approve
221
- ```
276
+ ---
222
277
 
223
- - #### _DESTROY_
278
+ ## Windows support
224
279
 
225
- Run terraform destroy with optional file-based targets.
280
+ Everything works on Windows without administrator privileges:
226
281
 
227
- ```sh
228
- tfv destroy --file main.tf
229
- ```
282
+ - Store: `%USERPROFILE%\.tfv\`
283
+ - PATH: updated via `[Environment]::SetEnvironmentVariable("PATH", ..., "User")` (User scope, no admin)
284
+ - Shell hooks: PowerShell profile integration via `tfv shell-init powershell`
230
285
 
231
- With auto-approve
286
+ ---
287
+
288
+ ## Help
232
289
 
233
290
  ```sh
234
- tfv destroy --file main.tf -- -auto-approve
291
+ tfv --help
292
+ tfv <command> --help
235
293
  ```
package/demo.gif ADDED
Binary file