tfv 5.0.0 → 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 -129
  3. package/demo.gif +0 -0
  4. package/demo.tape +230 -0
  5. package/index.js +0 -4
  6. package/lib/commands/apply.js +9 -4
  7. package/lib/commands/current.js +25 -0
  8. package/lib/commands/destroy.js +9 -4
  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 +9 -4
  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,226 +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: tfv apply --file main.tf --file network.tf -- -auto-approve -target=<TARGET> -var="env=prod"
104
+ ### Switch version
59
105
 
60
- tfv destroy Run terraform destroy with optional file-based targets.
61
- Accepts all terraform flags after --
62
- Example: 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
+ ```
63
111
 
64
- tfv plan Run terraform plan with optional file-based targets.
65
- Accepts all terraform flags after --
66
- Example: tfv plan --file main.tf --file network.tf -- -auto-approve -target=<TARGET> -var="env=prod"
112
+ No `sudo`. Copies binary to `~/.tfv/bin/terraform`.
67
113
 
68
- Options:
69
- -h, --help Show help [boolean]
70
- -v, --version Show version number [boolean]
71
- ```
114
+ ---
72
115
 
73
- # Usage
116
+ ### Auto-switch
74
117
 
75
- 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.
76
119
 
77
- # Table of Contents
120
+ ```sh
121
+ tfv auto-switch
122
+ tfv as # alias
123
+ tfv as --provider tofu
124
+ ```
78
125
 
79
- <!--ts-->
80
- * [Table of Contents](#table-of-contents)
81
- * [Modules](#modules)
82
- * [install](#install)
83
- * [use](#use)
84
- * [list](#list)
85
- * [remove](#remove)
86
- * [auto-switch](#auto-switch)
87
- * [plan](#plan)
88
- * [apply](#apply)
89
- * [destroy](#destroy)
90
- <!--te-->
126
+ Reads version from (in priority order):
91
127
 
92
- ### 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"`
93
132
 
94
- - #### _INSTALL_
133
+ ---
95
134
 
96
- | Version | Description |
97
- | ---------------- | ------------------------------------------ |
98
- | x.x.x | Installs terraform version x.x.x |
99
- | x^ | Installs latest version of release x |
100
- | x.x.^ | Installs latest version of release x.x |
101
- | latest | Installs latest version of terraform |
135
+ ### Shell hook — auto-switch on `cd`
102
136
 
103
- ```sh
104
- tfv install <version>
105
- ```
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).
106
138
 
107
- Run with option
139
+ A directory is considered a terraform project if it contains:
140
+ - a `.terraform-version` file, **or**
141
+ - any `*.tf` files
108
142
 
109
143
  ```sh
110
- 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
111
148
  ```
112
149
 
113
- EXAMPLE:
150
+ Setup (one-time, add to your shell config):
114
151
 
115
152
  ```sh
116
- tfv install 1.5.7 -arch amd64
117
- ```
118
-
119
- > 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
120
155
 
121
- - #### _USE_
156
+ # Zsh
157
+ echo 'eval "$(tfv shell-init zsh)"' >> ~/.zshrc
122
158
 
123
- | Version | Description |
124
- | ---------------- | ----------------------------------------- |
125
- | x.x.x | use terraform version x.x.x |
126
- | latest | use latest version of terraform |
159
+ # Fish
160
+ echo 'tfv shell-init fish | source' >> ~/.config/fish/config.fish
127
161
 
128
- ```sh
129
- tfv use <version>
162
+ # PowerShell
163
+ echo 'Invoke-Expression (tfv shell-init powershell | Out-String)' >> $PROFILE
130
164
  ```
131
165
 
132
- > **_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.
133
167
 
134
- - #### _LIST_
168
+ ---
135
169
 
136
- | Option | Option Alias | Description |
137
- | ---------------|---------------|--------------------------------------------------------------------------------|
138
- | | | Defaults to listing terraform versions installed locally (in tfv store) |
139
- | `--local` | `-l` | Lists all terraform versions installed locally |
140
- | `--remote` | `-r` | Lists all terraform versions available remotely, on terraform server |
170
+ ### List versions
141
171
 
142
172
  ```sh
143
- 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
144
176
  ```
145
177
 
146
- Run with alias
178
+ Active version is marked with 🚀.
147
179
 
148
- ```sh
149
- tfv ls [option]
150
- ```
151
-
152
- - #### _REMOVE_
180
+ ---
153
181
 
154
- Remove terraform versions managed by tfv
182
+ ### Current version
155
183
 
156
184
  ```sh
157
- tfv remove <versions>
185
+ tfv current # shows active version + PATH status
186
+ tfv which # alias
187
+ tfv current --provider tofu
158
188
  ```
159
189
 
160
- Run with alias
161
-
162
- ```sh
163
- 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
164
196
  ```
165
197
 
166
- 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`:
167
203
 
168
204
  ```sh
169
- 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
170
208
  ```
171
209
 
172
- - #### _AUTO-SWITCH_
210
+ ---
173
211
 
174
- Auto-detects your project terraform version, downloads it if it's not in tfv store, and switch to the version
212
+ ### Upgrade
175
213
 
176
214
  ```sh
177
- 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
178
219
  ```
179
220
 
180
- 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
181
226
 
182
227
  ```sh
183
- 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
184
231
  ```
185
232
 
186
- - #### _PLAN_
233
+ Warns if you're removing the currently active version.
187
234
 
188
- Run terraform plan with optional file-based targets. Parses terraform files to extract resources, data sources, and modules as targets.
235
+ ---
189
236
 
190
- ```sh
191
- tfv plan --file main.tf
192
- ```
237
+ ### Terraform commands (via tfv)
193
238
 
194
- With multiple files
239
+ All commands use the tfv-managed binary and accept extra terraform flags after `--`:
195
240
 
196
241
  ```sh
197
- 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
198
254
  ```
199
255
 
200
- 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.
201
257
 
202
- ```sh
203
- tfv plan --file main.tf -- -var="env=prod" -out=plan.out
204
- ```
258
+ All commands support `--provider tofu` to use OpenTofu instead.
259
+
260
+ ---
205
261
 
206
- - #### _APPLY_
262
+ ## OpenTofu support
207
263
 
208
- Run terraform apply with optional file-based targets.
264
+ Every command works with OpenTofu via `--provider tofu` (or `--provider opentofu`):
209
265
 
210
266
  ```sh
211
- 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
212
272
  ```
213
273
 
214
- With auto-approve
274
+ OpenTofu binaries are stored separately from Terraform in `~/.tfv/store/opentofu/` and activated as `~/.tfv/bin/tofu`.
215
275
 
216
- ```sh
217
- tfv apply --file main.tf -- -auto-approve
218
- ```
276
+ ---
219
277
 
220
- - #### _DESTROY_
278
+ ## Windows support
221
279
 
222
- Run terraform destroy with optional file-based targets.
280
+ Everything works on Windows without administrator privileges:
223
281
 
224
- ```sh
225
- tfv destroy --file main.tf
226
- ```
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`
227
285
 
228
- With auto-approve
286
+ ---
287
+
288
+ ## Help
229
289
 
230
290
  ```sh
231
- tfv destroy --file main.tf -- -auto-approve
291
+ tfv --help
292
+ tfv <command> --help
232
293
  ```
package/demo.gif ADDED
Binary file