mirror of
https://github.com/hashicorp/setup-terraform.git
synced 2025-12-17 17:02:36 +00:00
Compare commits
182 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
92e4d08fe1 | ||
|
|
071811a162 | ||
|
|
712b43959e | ||
|
|
4c5fdabea2 | ||
|
|
982f6f017c | ||
|
|
889df91364 | ||
|
|
c529327889 | ||
|
|
afa38526df | ||
|
|
fe38bfbb36 | ||
|
|
2ee5124c44 | ||
|
|
7a460deeba | ||
|
|
08cace2060 | ||
|
|
7a4a568111 | ||
|
|
2531c42cf3 | ||
|
|
922a7f49a5 | ||
|
|
8d2314a5a5 | ||
|
|
2583b7f7b0 | ||
|
|
0d13b7f42d | ||
|
|
c0a118784f | ||
|
|
1428cf0603 | ||
|
|
71c625de8e | ||
|
|
c6dbe8c0cb | ||
|
|
6195e86a29 | ||
|
|
5a8481b19f | ||
|
|
8c8499e9e3 | ||
|
|
4bb2b63d92 | ||
|
|
1ef107dd85 | ||
|
|
a0612fb3ce | ||
|
|
06d7cc5c8c | ||
|
|
a8fd1d197b | ||
|
|
25dabe9f9b | ||
|
|
607bf09de2 | ||
|
|
77d3b26ee9 | ||
|
|
71e23deaae | ||
|
|
1f2422a204 | ||
|
|
852ca175a6 | ||
|
|
2f1b53ffa5 | ||
|
|
0c8c41f96f | ||
|
|
009a8b75dc | ||
|
|
e708d31c3d | ||
|
|
7d2407faba | ||
|
|
9e5c386f98 | ||
|
|
f717f5cabe | ||
|
|
1748f9de39 | ||
|
|
8c5bde2a38 | ||
|
|
49dee962d5 | ||
|
|
817023b5c8 | ||
|
|
344fef46b6 | ||
|
|
638baae343 | ||
|
|
fd3bf06534 | ||
|
|
4fab011903 | ||
|
|
273780a335 | ||
|
|
4b8e29db07 | ||
|
|
98aecdfa81 | ||
|
|
76fd07bad3 | ||
|
|
c4396e588c | ||
|
|
c23d9fb1b7 | ||
|
|
7d0fcea6b8 | ||
|
|
a0b6ede12c | ||
|
|
b9cd54a3c3 | ||
|
|
47b7a54660 | ||
|
|
20bffecdc7 | ||
|
|
7f4493e155 | ||
|
|
bda29761c6 | ||
|
|
3235006f3a | ||
|
|
81777d53ca | ||
|
|
c5b46f3a20 | ||
|
|
0ec620c10e | ||
|
|
02909a6782 | ||
|
|
e2c57ad734 | ||
|
|
69dd27efac | ||
|
|
79dc7f98ba | ||
|
|
8f68c2ad45 | ||
|
|
070c2081b2 | ||
|
|
f985329c37 | ||
|
|
e991776e16 | ||
|
|
fa933962d0 | ||
|
|
21093d5e31 | ||
|
|
e08428bc1b | ||
|
|
608a0c2d63 | ||
|
|
85c6779ba6 | ||
|
|
77b7878004 | ||
|
|
e0e08fea34 | ||
|
|
651471c36a | ||
|
|
423ba69560 | ||
|
|
99441ecd44 | ||
|
|
5f32e8acaf | ||
|
|
e6e8bf240a | ||
|
|
1f0219f06b | ||
|
|
4d5f12e9c6 | ||
|
|
97f030cf6d | ||
|
|
c9227a4b06 | ||
|
|
22013f72bd | ||
|
|
a75f1a3cce | ||
|
|
b033326c2c | ||
|
|
0051b26884 | ||
|
|
e45327d894 | ||
|
|
2417443146 | ||
|
|
e12a01440e | ||
|
|
521e785974 | ||
|
|
2dfb501e55 | ||
|
|
6ac2b085ea | ||
|
|
725b9fbf91 | ||
|
|
3209a7815b | ||
|
|
69c00852f1 | ||
|
|
fc6630a3dc | ||
|
|
f8aa68a57c | ||
|
|
d116bd78c2 | ||
|
|
1f997cc1ff | ||
|
|
b4be958214 | ||
|
|
d648ba0239 | ||
|
|
1b93182764 | ||
|
|
ee8c4d7d5b | ||
|
|
90c9a43546 | ||
|
|
a1502cd9e7 | ||
|
|
070aa52467 | ||
|
|
cfd668c07b | ||
|
|
4dff81de7e | ||
|
|
4c41f96f26 | ||
|
|
9507e1d5bb | ||
|
|
599d383196 | ||
|
|
1697eea208 | ||
|
|
8fa54e78fa | ||
|
|
bf6ea8ac71 | ||
|
|
9c564c0569 | ||
|
|
34acbbf033 | ||
|
|
f231b15c96 | ||
|
|
e192cfcbae | ||
|
|
f3affec3d5 | ||
|
|
2804f806e0 | ||
|
|
082dadaefd | ||
|
|
56fd7100b5 | ||
|
|
95549a3832 | ||
|
|
ed6db656dc | ||
|
|
f3501afcbe | ||
|
|
efd0b45bf6 | ||
|
|
1e58a084c0 | ||
|
|
d862293ed5 | ||
|
|
f06312365a | ||
|
|
4a142dabfb | ||
|
|
7f7aa023e5 | ||
|
|
87af952b70 | ||
|
|
bf5a91876f | ||
|
|
57bfbbc653 | ||
|
|
93a916da3d | ||
|
|
55aa98b46e | ||
|
|
5aa9444145 | ||
|
|
1fdd4cd311 | ||
|
|
58cd07727c | ||
|
|
0db19997f8 | ||
|
|
61be50777d | ||
|
|
765565da05 | ||
|
|
6b752b326b | ||
|
|
aa7ea2f4b9 | ||
|
|
525ec9dce5 | ||
|
|
234b25c729 | ||
|
|
51df13f1aa | ||
|
|
08e201aa90 | ||
|
|
0d0e1dd31e | ||
|
|
f0d0d96875 | ||
|
|
8c01c536be | ||
|
|
a405e92ab1 | ||
|
|
8972b88921 | ||
|
|
a0b152b5df | ||
|
|
d3026307a0 | ||
|
|
1d777b53ee | ||
|
|
225afc4e17 | ||
|
|
b69ccc5640 | ||
|
|
eed2545295 | ||
|
|
8b59f414e1 | ||
|
|
66d3914cff | ||
|
|
e9f70b5b88 | ||
|
|
ced4e07081 | ||
|
|
97112244d3 | ||
|
|
8feba2b913 | ||
|
|
4a9d2ae03e | ||
|
|
abbee59a42 | ||
|
|
3f2da7835b | ||
|
|
beec8186ce | ||
|
|
4756a5b786 | ||
|
|
51b495f6a8 | ||
|
|
e7ad2a5a68 |
47 changed files with 68872 additions and 26551 deletions
169
.changes/2.0.3.md
Normal file
169
.changes/2.0.3.md
Normal file
|
|
@ -0,0 +1,169 @@
|
||||||
|
# [2.0.3] (2022-11-01)
|
||||||
|
|
||||||
|
### NOTES
|
||||||
|
|
||||||
|
* Reduced occurrences of GitHub Actions warnings for setting output [#247](https://github.com/hashicorp/setup-terraform/pull/247)
|
||||||
|
|
||||||
|
# [2.0.2] (2022-10-12)
|
||||||
|
|
||||||
|
### BUG FIXES
|
||||||
|
|
||||||
|
* Update 2.0.1 release metadata by @jpogran in https://github.com/hashicorp/setup-terraform/pull/253
|
||||||
|
* `README.md` updates - direct links to license and code of conduct, updated GitHub documents link by @magnetikonline in https://github.com/hashicorp/setup-terraform/pull/244
|
||||||
|
|
||||||
|
### INTERNAL
|
||||||
|
|
||||||
|
* Bump jest from 29.0.3 to 29.1.2 by @dependabot in https://github.com/hashicorp/setup-terraform/pull/248
|
||||||
|
|
||||||
|
# [2.0.1] (2022-10-12)
|
||||||
|
|
||||||
|
### ENHANCEMENTS
|
||||||
|
|
||||||
|
* Do not fail when theres an exit-code 2 by @dannyibishev in https://github.com/hashicorp/setup-terraform/pull/125
|
||||||
|
* Updated README to reflect GitHub limitations by @rnsc in https://github.com/hashicorp/setup-terraform/pull/205
|
||||||
|
|
||||||
|
### BUG FIXES
|
||||||
|
|
||||||
|
* Fix terraform extract by @cpc-camarj in https://github.com/hashicorp/setup-terraform/pull/187
|
||||||
|
* Add new-style readme build badges, bump `actions/checkout` in `README.md` examples by @magnetikonline in https://github.com/hashicorp/setup-terraform/pull/188
|
||||||
|
* Fixed `master` to `main` workflow branch triggers by @magnetikonline in https://github.com/hashicorp/setup-terraform/pull/216
|
||||||
|
* Fix the example of how to comment on pull request. by @acarmel in https://github.com/hashicorp/setup-terraform/pull/220
|
||||||
|
|
||||||
|
### INTERNAL
|
||||||
|
|
||||||
|
* Bump @actions/core from 1.6.0 to 1.7.0 by @dependabot in https://github.com/hashicorp/setup-terraform/pull/185
|
||||||
|
* Bump @vercel/ncc from 0.33.3 to 0.33.4 by @dependabot in https://github.com/hashicorp/setup-terraform/pull/182
|
||||||
|
* Bump jest from 27.5.1 to 28.0.0 by @dependabot in https://github.com/hashicorp/setup-terraform/pull/184
|
||||||
|
* Bump jest from 28.0.0 to 28.0.3 by @dependabot in https://github.com/hashicorp/setup-terraform/pull/190
|
||||||
|
* Bump husky from 7.0.4 to 8.0.1 by @dependabot in https://github.com/hashicorp/setup-terraform/pull/193
|
||||||
|
* Bump jest from 28.0.3 to 28.1.0 by @dependabot in https://github.com/hashicorp/setup-terraform/pull/194
|
||||||
|
* Bump @actions/github from 5.0.1 to 5.0.3 by @dependabot in https://github.com/hashicorp/setup-terraform/pull/201
|
||||||
|
* Bump @actions/core from 1.7.0 to 1.8.2 by @dependabot in https://github.com/hashicorp/setup-terraform/pull/200
|
||||||
|
* Bump @actions/tool-cache from 1.7.2 to 2.0.1 by @dependabot in https://github.com/hashicorp/setup-terraform/pull/199
|
||||||
|
* TF DevEx: repo adoption by @detro in https://github.com/hashicorp/setup-terraform/pull/204
|
||||||
|
* Bump nock from 13.2.4 to 13.2.6 by @dependabot in https://github.com/hashicorp/setup-terraform/pull/212
|
||||||
|
* Bump @vercel/ncc from 0.33.4 to 0.34.0 by @dependabot in https://github.com/hashicorp/setup-terraform/pull/210
|
||||||
|
* Bump jest from 28.1.0 to 28.1.1 by @dependabot in https://github.com/hashicorp/setup-terraform/pull/215
|
||||||
|
* Bump nock from 13.2.6 to 13.2.7 by @dependabot in https://github.com/hashicorp/setup-terraform/pull/217
|
||||||
|
* Bump jest from 28.1.1 to 28.1.2 by @dependabot in https://github.com/hashicorp/setup-terraform/pull/221
|
||||||
|
* Bump jest from 28.1.2 to 28.1.3 by @dependabot in https://github.com/hashicorp/setup-terraform/pull/224
|
||||||
|
* Bump nock from 13.2.7 to 13.2.9 by @dependabot in https://github.com/hashicorp/setup-terraform/pull/225
|
||||||
|
* Bump leonsteinhaeuser/project-beta-automations from 1.2.1 to 1.3.0 by @dependabot in https://github.com/hashicorp/setup-terraform/pull/233
|
||||||
|
* Bump leonsteinhaeuser/project-beta-automations from 1.3.0 to 2.0.0 by @dependabot in https://github.com/hashicorp/setup-terraform/pull/243
|
||||||
|
* Bump jest from 28.1.3 to 29.0.3 by @dependabot in https://github.com/hashicorp/setup-terraform/pull/242
|
||||||
|
* Bump @hashicorp/js-releases from 1.5.1 to 1.6.1 by @dependabot in https://github.com/hashicorp/setup-terraform/pull/226
|
||||||
|
* Bump @actions/core from 1.8.2 to 1.9.1 by @dependabot in https://github.com/hashicorp/setup-terraform/pull/235
|
||||||
|
* Bump @actions/core from 1.6.0 to 1.9.1 in /wrapper by @dependabot in https://github.com/hashicorp/setup-terraform/pull/236
|
||||||
|
* Bump @actions/github from 5.0.3 to 5.1.1 by @dependabot in https://github.com/hashicorp/setup-terraform/pull/249
|
||||||
|
* Bump leonsteinhaeuser/project-beta-automations from 2.0.0 to 2.0.1 by @dependabot in https://github.com/hashicorp/setup-terraform/pull/250
|
||||||
|
|
||||||
|
# [2.0.0] (2022-04-18)
|
||||||
|
|
||||||
|
BREAKING CHANGES:
|
||||||
|
|
||||||
|
* Support Actions Runners v2.285.0 or later by upgrading to Nodejs v16 runtime by @chenrui333 in https://github.com/hashicorp/setup-terraform/pull/170
|
||||||
|
|
||||||
|
NOTES:
|
||||||
|
|
||||||
|
* docs: Update existing PR comments example by @tobiasbueschel in https://github.com/hashicorp/setup-terraform/pull/178
|
||||||
|
* Update Terraform versions and usage in README examples by @ksatirli in https://github.com/hashicorp/setup-terraform/pull/176
|
||||||
|
* Update grammar in README.md by @dustindortch in https://github.com/hashicorp/setup-terraform/pull/180
|
||||||
|
|
||||||
|
INTERNAL:
|
||||||
|
|
||||||
|
* Bump @actions/github from 5.0.0 to 5.0.1 by @dependabot in https://github.com/hashicorp/setup-terraform/pull/177
|
||||||
|
* dependabot: track github-actions dependency changes by @chenrui333 in https://github.com/hashicorp/setup-terraform/pull/179
|
||||||
|
|
||||||
|
# [1.4.0] (2022-04-04)
|
||||||
|
|
||||||
|
NOTES:
|
||||||
|
|
||||||
|
- Update readme using github-script@v5 by @krrrr38 in ([#135](https://github.com/hashicorp/setup-terraform/pull/135))
|
||||||
|
- Update actions/github-script to v6 in README by @shouichi in ([#148](https://github.com/hashicorp/setup-terraform/pull/148))
|
||||||
|
|
||||||
|
ENHANCEMENTS:
|
||||||
|
|
||||||
|
- Improve output for PR comment by @skpy in ([#129](https://github.com/hashicorp/setup-terraform/pull/129))
|
||||||
|
- Allow proxy values to be set by @rabun788 in ([#147](https://github.com/hashicorp/setup-terraform/pull/147))
|
||||||
|
|
||||||
|
INTERNAL:
|
||||||
|
|
||||||
|
- Allow dependabot to check node modules by @jlosito in ([#87](https://github.com/hashicorp/setup-terraform/pull/87))
|
||||||
|
- Update js-releases to v1.4.0 by @aeschright in ([#111](https://github.com/hashicorp/setup-terraform/pull/111))
|
||||||
|
- Updates Readme by @ndrone-kr in ([#86](https://github.com/hashicorp/setup-terraform/pull/86))
|
||||||
|
- Update husky to v6.0 by @aeschright in ([#113](https://github.com/hashicorp/setup-terraform/pull/113))
|
||||||
|
- Bump development dependencies by @jpogran in ([#153](https://github.com/hashicorp/setup-terraform/pull/153))
|
||||||
|
- Bump node-fetch from 2.6.1 to 2.6.7 by @dependabot in ([#154](https://github.com/hashicorp/setup-terraform/pull/154))
|
||||||
|
- Bump @actions/github from 4.0.0 to 5.0.0 by @dependabot in ([#114](https://github.com/hashicorp/setup-terraform/pull/114))
|
||||||
|
- Bump @actions/io from 1.1.0 to 1.1.1 by @dependabot in ([#156](https://github.com/hashicorp/setup-terraform/pull/156))
|
||||||
|
- Bump @actions/core from 1.2.7 to 1.6.0 by @dependabot in ([#158](https://github.com/hashicorp/setup-terraform/pull/158))
|
||||||
|
- Bump @actions/tool-cache from 1.6.1 to 1.7.1 by @dependabot in ([#159](https://github.com/hashicorp/setup-terraform/pull/159))
|
||||||
|
- Bump @actions/core from 1.2.7 to 1.6.0 by @jpogran in ([#160](https://github.com/hashicorp/setup-terraform/pull/160))
|
||||||
|
- Bump @actions/exec from 1.0.4 to 1.1.0 by @jpogran in ([#161](https://github.com/hashicorp/setup-terraform/pull/161))
|
||||||
|
- Bump @actions/io from 1.1.0 to 1.1.1 by @jpogran in ([#162](https://github.com/hashicorp/setup-terraform/pull/162))
|
||||||
|
- Bump @hashicorp/js-releases from 1.5.0 to 1.5.1 by @dependabot in ([#166](https://github.com/hashicorp/setup-terraform/pull/166))
|
||||||
|
- Bump minimist from 1.2.5 to 1.2.6 by @dependabot in ([#168](https://github.com/hashicorp/setup-terraform/pull/168))
|
||||||
|
- Bump @actions/tool-cache from 1.7.1 to 1.7.2 by @dependabot in ([#164](https://github.com/hashicorp/setup-terraform/pull/164))
|
||||||
|
- Bump @actions/io from 1.1.1 to 1.1.2 by @dependabot in ([#165](https://github.com/hashicorp/setup-terraform/pull/165))
|
||||||
|
- Bump minimist from 1.2.5 to 1.2.6 in /wrapper by @dependabot in ([#169](https://github.com/hashicorp/setup-terraform/pull/169))
|
||||||
|
- Add GitHub automatic release by @jpogran in ([#173](https://github.com/hashicorp/setup-terraform/pull/173))
|
||||||
|
|
||||||
|
# [1.3.2] (2020-12-09)
|
||||||
|
|
||||||
|
ENHANCEMENTS:
|
||||||
|
|
||||||
|
- Update js-releases to fix missing dep in bundle ([#78](https://github.com/hashicorp/setup-terraform/pull/78))
|
||||||
|
|
||||||
|
# [1.3.1] (2020-12-08)
|
||||||
|
|
||||||
|
BUG FIXES:
|
||||||
|
|
||||||
|
- Fix build dependency ([#76](https://github.com/hashicorp/setup-terraform/pull/76))
|
||||||
|
|
||||||
|
# [1.3.0] (2020-12-08)
|
||||||
|
|
||||||
|
ENHANCEMENTS:
|
||||||
|
|
||||||
|
- Use `@hashicorp/js-releases` package to identify and download the specified version of Terraform. This will ensure that our tooling is consistent in how it works with the releases API, especially when handling pre-releases. ([#70](https://github.com/hashicorp/setup-terraform/pull/70), [#73](https://github.com/hashicorp/setup-terraform/pull/73))
|
||||||
|
|
||||||
|
# [1.2.1] (2020-10-30)
|
||||||
|
|
||||||
|
INTERNAL:
|
||||||
|
|
||||||
|
- Update dependencies to resolve CVE-2020-15228 ([#63](https://github.com/hashicorp/setup-terraform/pull/63))
|
||||||
|
|
||||||
|
# [1.2.0]
|
||||||
|
|
||||||
|
ENHANCEMENTS:
|
||||||
|
|
||||||
|
- Allow `terraform_version` to take a version constraint. ([#38](https://github.com/hashicorp/setup-terraform/pull/38))
|
||||||
|
|
||||||
|
# [1.1.0]
|
||||||
|
|
||||||
|
ENHANCEMENTS:
|
||||||
|
|
||||||
|
- Ignore pre-release versions when `terraform_version` is set to `latest`. ([#19](https://github.com/hashicorp/setup-terraform/pull/19))
|
||||||
|
|
||||||
|
# [1.0.1]
|
||||||
|
|
||||||
|
INTERNAL:
|
||||||
|
|
||||||
|
- Bump @actions/http-client from 1.0.6 to 1.0.8. ([#1](https://github.com/hashicorp/setup-terraform/pull/1))
|
||||||
|
|
||||||
|
# [1.0.0]
|
||||||
|
|
||||||
|
- Initial release.
|
||||||
|
|
||||||
|
<!-- Links to tag comparisons -->
|
||||||
|
[Unreleased]: https://github.com/hashicorp/setup-terraform/compare/v2.0.2...main
|
||||||
|
[2.0.2]: https://github.com/hashicorp/setup-terraform/compare/v2.0.1...v2.0.2
|
||||||
|
[2.0.1]: https://github.com/hashicorp/setup-terraform/compare/v2.0.0...v2.0.1
|
||||||
|
[2.0.0]: https://github.com/hashicorp/setup-terraform/compare/v1.4.0...v2.0.0
|
||||||
|
[1.4.0]: https://github.com/hashicorp/setup-terraform/compare/v1.3.2...v1.4.0
|
||||||
|
[1.3.2]: https://github.com/hashicorp/setup-terraform/compare/v1.3.1...v1.3.2
|
||||||
|
[1.3.1]: https://github.com/hashicorp/setup-terraform/compare/v1.3.0...v1.3.1
|
||||||
|
[1.3.0]: https://github.com/hashicorp/setup-terraform/compare/v1.2.1...v1.3.0
|
||||||
|
[1.2.1]: https://github.com/hashicorp/setup-terraform/compare/v1.2.0...v1.2.1
|
||||||
|
[1.2.0]: https://github.com/hashicorp/setup-terraform/compare/v1.1.0...v1.2.0
|
||||||
|
[1.1.0]: https://github.com/hashicorp/setup-terraform/compare/v1.0.1...v1.1.0
|
||||||
|
[1.0.1]: https://github.com/hashicorp/setup-terraform/compare/v1.0.0...v1.0.1
|
||||||
11
.changes/3.0.0.md
Normal file
11
.changes/3.0.0.md
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
## 3.0.0 (2023-10-30)
|
||||||
|
|
||||||
|
NOTES:
|
||||||
|
|
||||||
|
* Updated default runtime to node20 ([#346](https://github.com/hashicorp/setup-terraform/issues/346))
|
||||||
|
* The wrapper around the installed Terraform binary has been fixed to return the exact STDOUT and STDERR from Terraform when executing commands. Previous versions of setup-terraform may have required workarounds to process the STDOUT in bash, such as filtering out the first line or selectively parsing STDOUT with jq. These workarounds may need to be adjusted with `v3.0.0`, which will now return just the STDOUT/STDERR from Terraform with no errant characters/statements. ([#367](https://github.com/hashicorp/setup-terraform/issues/367))
|
||||||
|
|
||||||
|
BUG FIXES:
|
||||||
|
|
||||||
|
* Fixed malformed stdout when wrapper is enabled ([#367](https://github.com/hashicorp/setup-terraform/issues/367))
|
||||||
|
|
||||||
6
.changes/3.1.0.md
Normal file
6
.changes/3.1.0.md
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
## 3.1.0 (2024-04-23)
|
||||||
|
|
||||||
|
ENHANCEMENTS:
|
||||||
|
|
||||||
|
* Automatically fallback to darwin/amd64 for Terraform versions before 1.0.2 as releases for darwin/arm64 are not available ([#409](https://github.com/hashicorp/setup-terraform/issues/409))
|
||||||
|
|
||||||
6
.changes/3.1.1.md
Normal file
6
.changes/3.1.1.md
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
## 3.1.1 (2024-05-07)
|
||||||
|
|
||||||
|
BUG FIXES:
|
||||||
|
|
||||||
|
* wrapper: Fix wrapper to output to stdout and stderr immediately when data is received ([#395](https://github.com/hashicorp/setup-terraform/issues/395))
|
||||||
|
|
||||||
6
.changes/3.1.2.md
Normal file
6
.changes/3.1.2.md
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
## 3.1.2 (2024-08-19)
|
||||||
|
|
||||||
|
NOTES:
|
||||||
|
|
||||||
|
* This release introduces no functional changes. It does however include dependency updates which address upstream CVEs. ([#430](https://github.com/hashicorp/setup-terraform/issues/430))
|
||||||
|
|
||||||
0
.changes/unreleased/.gitkeep
Normal file
0
.changes/unreleased/.gitkeep
Normal file
22
.changie.yaml
Normal file
22
.changie.yaml
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
changesDir: .changes
|
||||||
|
unreleasedDir: unreleased
|
||||||
|
changelogPath: CHANGELOG.md
|
||||||
|
versionExt: md
|
||||||
|
versionFormat: '## {{.Version}} ({{.Time.Format "2006-01-02"}})'
|
||||||
|
kindFormat: '{{.Kind}}:'
|
||||||
|
changeFormat: '* {{.Body}} ([#{{.Custom.Issue}}](https://github.com/hashicorp/setup-terraform/issues/{{.Custom.Issue}}))'
|
||||||
|
custom:
|
||||||
|
- key: Issue
|
||||||
|
label: Issue/PR Number
|
||||||
|
type: int
|
||||||
|
minInt: 1
|
||||||
|
kinds:
|
||||||
|
- label: BREAKING CHANGES
|
||||||
|
- label: NOTES
|
||||||
|
- label: FEATURES
|
||||||
|
- label: ENHANCEMENTS
|
||||||
|
- label: BUG FIXES
|
||||||
|
newlines:
|
||||||
|
afterKind: 1
|
||||||
|
beforeKind: 1
|
||||||
|
endOfVersion: 2
|
||||||
33
.copywrite.hcl
Normal file
33
.copywrite.hcl
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
schema_version = 1
|
||||||
|
|
||||||
|
project {
|
||||||
|
license = "MPL-2.0"
|
||||||
|
copyright_year = 2020
|
||||||
|
|
||||||
|
header_ignore = [
|
||||||
|
# internal catalog metadata (prose)
|
||||||
|
"META.d/**/*.yaml",
|
||||||
|
|
||||||
|
# changie tooling configuration and CHANGELOG entries (prose)
|
||||||
|
".changes/unreleased/*.yaml",
|
||||||
|
".changie.yaml",
|
||||||
|
|
||||||
|
# GitHub issue template configuration
|
||||||
|
".github/ISSUE_TEMPLATE/*.yml",
|
||||||
|
|
||||||
|
# GitHub Actions workflow-specific configurations
|
||||||
|
".github/labeler-*.yml",
|
||||||
|
|
||||||
|
# Github Action linting configuration
|
||||||
|
".github/actionlint.yaml",
|
||||||
|
|
||||||
|
# Release Engineering tooling configuration
|
||||||
|
".release/*.hcl",
|
||||||
|
|
||||||
|
# Auto-generated /dist
|
||||||
|
"dist/**",
|
||||||
|
|
||||||
|
# GitHub Action metadata file
|
||||||
|
"action.yml",
|
||||||
|
]
|
||||||
|
}
|
||||||
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
|
|
@ -1 +1 @@
|
||||||
* @hashicorp/terraform-devex
|
* @hashicorp/terraform-core-plugins
|
||||||
|
|
|
||||||
11
.github/dependabot.yml
vendored
11
.github/dependabot.yml
vendored
|
|
@ -4,11 +4,14 @@ updates:
|
||||||
directory: "/"
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
interval: "weekly"
|
interval: "weekly"
|
||||||
- package-ecosystem: "npm"
|
|
||||||
directory: "/wrapper"
|
|
||||||
schedule:
|
|
||||||
interval: "weekly"
|
|
||||||
- package-ecosystem: "github-actions"
|
- package-ecosystem: "github-actions"
|
||||||
directory: "/"
|
directory: "/"
|
||||||
|
groups:
|
||||||
|
"github-actions":
|
||||||
|
patterns:
|
||||||
|
- "*" # Group all GitHub Actions dependencies together
|
||||||
schedule:
|
schedule:
|
||||||
interval: "weekly"
|
interval: "weekly"
|
||||||
|
day: "monday"
|
||||||
|
time: "09:00"
|
||||||
|
timezone: "Etc/UTC"
|
||||||
|
|
|
||||||
16
.github/pull_request_template.md
vendored
Normal file
16
.github/pull_request_template.md
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
## Related Issue
|
||||||
|
|
||||||
|
Fixes # <!-- INSERT ISSUE NUMBER -->
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
In plain English, describe your approach to addressing the issue linked above. For example, if you made a particular design decision, let us know why you chose this path instead of another solution.
|
||||||
|
|
||||||
|
<!-- heimdall_github_prtemplate:grc-pci_dss-2024-01-05 -->
|
||||||
|
## Rollback Plan
|
||||||
|
|
||||||
|
- [ ] If a change needs to be reverted, we will roll out an update to the code within 7 days.
|
||||||
|
|
||||||
|
## Changes to Security Controls
|
||||||
|
|
||||||
|
Are there any changes to security controls (access controls, encryption, logging) in this pull request? If so, explain.
|
||||||
26
.github/release.yml
vendored
26
.github/release.yml
vendored
|
|
@ -1,26 +0,0 @@
|
||||||
changelog:
|
|
||||||
categories:
|
|
||||||
- title: NOTES
|
|
||||||
labels:
|
|
||||||
- note
|
|
||||||
- documentation
|
|
||||||
- title: FEATURES
|
|
||||||
labels:
|
|
||||||
- feature
|
|
||||||
- title: ENHANCEMENTS
|
|
||||||
labels:
|
|
||||||
- enhancement
|
|
||||||
- documentation
|
|
||||||
- title: BUG FIXES
|
|
||||||
labels:
|
|
||||||
- bug
|
|
||||||
- title: INTERNAL
|
|
||||||
labels:
|
|
||||||
- dependencies
|
|
||||||
- "*"
|
|
||||||
exclude:
|
|
||||||
labels:
|
|
||||||
- duplicate
|
|
||||||
- wontfix
|
|
||||||
- question
|
|
||||||
- invalid
|
|
||||||
40
.github/workflows/add-content-to-project.yml
vendored
40
.github/workflows/add-content-to-project.yml
vendored
|
|
@ -1,40 +0,0 @@
|
||||||
# Based on https://github.com/leonsteinhaeuser/project-beta-automations
|
|
||||||
|
|
||||||
name: "Add Issues/PRs to TF Provider DevEx team board"
|
|
||||||
|
|
||||||
on:
|
|
||||||
issues:
|
|
||||||
types: [opened, reopened]
|
|
||||||
pull_request_target:
|
|
||||||
# NOTE: The way content is added to project board is equivalent to an "upsert".
|
|
||||||
# Calling it multiple times will be idempotent.
|
|
||||||
#
|
|
||||||
# See https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
|
|
||||||
# to see the reasoning behind using `pull_request_target` instead of `pull_request`
|
|
||||||
types: [opened, reopened, ready_for_review]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
add-content-to-project:
|
|
||||||
name: "Add Content to project"
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: "Set Issue to 'Priority = Triage Next'"
|
|
||||||
uses: leonsteinhaeuser/project-beta-automations@v2.0.1
|
|
||||||
if: github.event_name == 'issues'
|
|
||||||
with:
|
|
||||||
gh_token: ${{ secrets.TF_DEVEX_PROJECT_GITHUB_TOKEN }}
|
|
||||||
organization: "hashicorp"
|
|
||||||
project_id: 99 #< https://github.com/orgs/hashicorp/projects/99
|
|
||||||
resource_node_id: ${{ github.event.issue.node_id }}
|
|
||||||
operation_mode: custom_field
|
|
||||||
custom_field_values: '[{\"name\":\"Priority\",\"type\":\"single_select\",\"value\":\"Triage Next\"}]'
|
|
||||||
- name: "Set Pull Request to 'Priority = Triage Next'"
|
|
||||||
uses: leonsteinhaeuser/project-beta-automations@v2.0.1
|
|
||||||
if: github.event_name == 'pull_request'
|
|
||||||
with:
|
|
||||||
gh_token: ${{ secrets.TF_DEVEX_PROJECT_GITHUB_TOKEN }}
|
|
||||||
organization: "hashicorp"
|
|
||||||
project_id: 99 #< https://github.com/orgs/hashicorp/projects/99
|
|
||||||
resource_node_id: ${{ github.event.pull_request.node_id }}
|
|
||||||
operation_mode: custom_field
|
|
||||||
custom_field_values: '[{\"name\":\"Priority\",\"type\":\"single_select\",\"value\":\"Triage Next\"}]'
|
|
||||||
23
.github/workflows/ci-changie.yml
vendored
Normal file
23
.github/workflows/ci-changie.yml
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Continuous integration handling for changie
|
||||||
|
name: ci-changie
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- .changes/unreleased/*.yaml
|
||||||
|
- .changie.yaml
|
||||||
|
- .github/workflows/ci-changie.yml
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||||
|
- uses: miniscruff/changie-action@5036dffa79ffc007110dc7f75eca7ef72780e147 # v2.1.0
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
args: batch patch --dry-run
|
||||||
|
|
||||||
17
.github/workflows/compliance.yml
vendored
Normal file
17
.github/workflows/compliance.yml
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
name: compliance
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# Reference: ENGSRV-059
|
||||||
|
copywrite:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||||
|
- uses: hashicorp/setup-copywrite@32638da2d4e81d56a0764aa1547882fc4d209636 # v1.1.3
|
||||||
|
- run: copywrite headers --plan
|
||||||
|
- run: copywrite license --plan
|
||||||
34
.github/workflows/continuous-integration.yml
vendored
34
.github/workflows/continuous-integration.yml
vendored
|
|
@ -7,30 +7,16 @@ on:
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
check-dist:
|
||||||
|
name: Check dist/ directory
|
||||||
|
uses: actions/reusable-workflows/.github/workflows/check-dist.yml@95d9656793415e47f574f7967f3850ea3bf5a7ed
|
||||||
|
with:
|
||||||
|
node-version: 20.x
|
||||||
|
node-caching: npm
|
||||||
|
|
||||||
test:
|
test:
|
||||||
name: Test
|
name: Test
|
||||||
runs-on: ${{ matrix.os }}
|
uses: actions/reusable-workflows/.github/workflows/basic-validation.yml@95d9656793415e47f574f7967f3850ea3bf5a7ed
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Setup Node.js 16.x
|
|
||||||
uses: actions/setup-node@v3
|
|
||||||
with:
|
with:
|
||||||
node-version: '16.x'
|
node-version: 20.x
|
||||||
|
node-caching: npm
|
||||||
- name: Install
|
|
||||||
run: npm clean-install
|
|
||||||
|
|
||||||
- name: Verify
|
|
||||||
if: runner.os == 'Linux'
|
|
||||||
run: |
|
|
||||||
npm run build
|
|
||||||
# Fail if "npm run build" generated new changes in dist
|
|
||||||
git update-index --refresh dist/* && git diff-index --quiet HEAD dist
|
|
||||||
|
|
||||||
- name: Test
|
|
||||||
run: npm test
|
|
||||||
|
|
|
||||||
11
.github/workflows/data/delay/main.tf
vendored
Normal file
11
.github/workflows/data/delay/main.tf
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
resource "null_resource" "previous" {}
|
||||||
|
|
||||||
|
resource "time_sleep" "wait_30_seconds" {
|
||||||
|
depends_on = [null_resource.previous]
|
||||||
|
|
||||||
|
create_duration = "30s"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "null_resource" "next" {
|
||||||
|
depends_on = [time_sleep.wait_30_seconds]
|
||||||
|
}
|
||||||
8
.github/workflows/data/local/main.tf
vendored
8
.github/workflows/data/local/main.tf
vendored
|
|
@ -1,5 +1,5 @@
|
||||||
resource "null_resource" "null" {
|
resource "random_pet" "pet" {}
|
||||||
triggers = {
|
|
||||||
value = timestamp()
|
output "pet" {
|
||||||
}
|
value = random_pet.pet.id
|
||||||
}
|
}
|
||||||
|
|
|
||||||
21
.github/workflows/issue-comment-triage.yml
vendored
Normal file
21
.github/workflows/issue-comment-triage.yml
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
# DO NOT EDIT - This GitHub Workflow is managed by automation
|
||||||
|
# https://github.com/hashicorp/terraform-devex-repos
|
||||||
|
name: Issue Comment Triage
|
||||||
|
|
||||||
|
on:
|
||||||
|
issue_comment:
|
||||||
|
types: [created]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
issue_comment_triage:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
# issue_comment events are triggered by comments on issues and pull requests. Checking the
|
||||||
|
# value of github.event.issue.pull_request tells us whether the issue is an issue or is
|
||||||
|
# actually a pull request, allowing us to dynamically set the gh subcommand:
|
||||||
|
# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#issue_comment-on-issues-only-or-pull-requests-only
|
||||||
|
COMMAND: ${{ github.event.issue.pull_request && 'pr' || 'issue' }}
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
steps:
|
||||||
|
- name: 'Remove waiting-response on comment'
|
||||||
|
run: gh ${{ env.COMMAND }} edit ${{ github.event.issue.html_url }} --remove-label waiting-response
|
||||||
22
.github/workflows/lock.yml
vendored
Normal file
22
.github/workflows/lock.yml
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
# DO NOT EDIT - This GitHub Workflow is managed by automation
|
||||||
|
# https://github.com/hashicorp/terraform-devex-repos
|
||||||
|
name: 'Lock Threads'
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 10 * * *'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lock:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
# NOTE: When TSCCR updates the GitHub action version, update the template workflow file to avoid drift:
|
||||||
|
# https://github.com/hashicorp/terraform-devex-repos/blob/main/modules/repo/workflows/lock.tftpl
|
||||||
|
- uses: dessant/lock-threads@7266a7ce5c1df01b1c6db85bf8cd86c737dadbe7 # v6.0.0
|
||||||
|
with:
|
||||||
|
process-only: 'issues, prs'
|
||||||
|
github-token: ${{ github.token }}
|
||||||
|
issue-inactive-days: '30'
|
||||||
|
issue-lock-reason: resolved
|
||||||
|
pr-inactive-days: '30'
|
||||||
|
pr-lock-reason: resolved
|
||||||
138
.github/workflows/release.yml
vendored
138
.github/workflows/release.yml
vendored
|
|
@ -1,20 +1,134 @@
|
||||||
name: Publish GitHub Release
|
name: release
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write # for creating a release and uploading release artifacts
|
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
workflow_dispatch:
|
||||||
tags:
|
inputs:
|
||||||
- 'v[0-9]+.[0-9]+.[0-9]+*'
|
versionNumber:
|
||||||
|
description: 'Release version number (v#.#.#)'
|
||||||
|
type: string
|
||||||
|
required: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read # Changelog commit operations use service account PAT
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
major-version:
|
||||||
runs-on: "ubuntu-latest"
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
version: ${{ steps.major-version.outputs.version }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- id: major-version
|
||||||
|
run: echo "version=$(echo "${{ inputs.versionNumber }}" | cut -d. -f1)" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
changelog-version:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
version: ${{ steps.changelog-version.outputs.version }}
|
||||||
|
steps:
|
||||||
|
- id: changelog-version
|
||||||
|
run: echo "version=$(echo "${{ inputs.versionNumber }}" | cut -c 2-)" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
changelog:
|
||||||
|
needs: changelog-version
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
# Avoid persisting GITHUB_TOKEN credentials as they take priority over our service account PAT for `git push` operations
|
||||||
|
# More details: https://github.com/actions/checkout/blob/b4626ce19ce1106186ddf9bb20e706842f11a7c3/adrs/0153-checkout-v2.md#persist-credentials
|
||||||
|
persist-credentials: false
|
||||||
|
- name: Batch changes
|
||||||
|
uses: miniscruff/changie-action@5036dffa79ffc007110dc7f75eca7ef72780e147 # v2.1.0
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
args: batch ${{ needs.changelog-version.outputs.version }}
|
||||||
|
- name: Merge changes
|
||||||
|
uses: miniscruff/changie-action@5036dffa79ffc007110dc7f75eca7ef72780e147 # v2.1.0
|
||||||
|
with:
|
||||||
|
version: latest
|
||||||
|
args: merge
|
||||||
|
- name: Git push changelog
|
||||||
|
run: |
|
||||||
|
git config --global user.name "${{ vars.TF_DEVEX_CI_COMMIT_AUTHOR }}"
|
||||||
|
git config --global user.email "${{ vars.TF_DEVEX_CI_COMMIT_EMAIL }}"
|
||||||
|
git add .
|
||||||
|
git commit -a -m "Update changelog"
|
||||||
|
git push "https://${{ vars.TF_DEVEX_CI_COMMIT_AUTHOR }}:${{ secrets.TF_DEVEX_COMMIT_GITHUB_TOKEN }}@github.com/${{ github.repository }}.git"
|
||||||
|
|
||||||
|
update-package-version:
|
||||||
|
needs: changelog
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
# Default input is the SHA that initially triggered the workflow. As we created a new commit in the previous job,
|
||||||
|
# to ensure we get the latest commit we use the ref for checkout: 'refs/heads/<branch_name>'
|
||||||
|
ref: ${{ github.ref }}
|
||||||
|
# Avoid persisting GITHUB_TOKEN credentials as they take priority over our service account PAT for `git push` operations
|
||||||
|
# More details: https://github.com/actions/checkout/blob/b4626ce19ce1106186ddf9bb20e706842f11a7c3/adrs/0153-checkout-v2.md#persist-credentials
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: Set up Node.js
|
||||||
|
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
- name: Update package version
|
||||||
|
run: npm version "${{ inputs.versionNumber }}" --git-tag-version false
|
||||||
|
- name: Git push
|
||||||
|
run: |
|
||||||
|
git config --global user.name "${{ vars.TF_DEVEX_CI_COMMIT_AUTHOR }}"
|
||||||
|
git config --global user.email "${{ vars.TF_DEVEX_CI_COMMIT_EMAIL }}"
|
||||||
|
git add .
|
||||||
|
git commit -a -m "Update package version"
|
||||||
|
git push "https://${{ vars.TF_DEVEX_CI_COMMIT_AUTHOR }}:${{ secrets.TF_DEVEX_COMMIT_GITHUB_TOKEN }}@github.com/${{ github.repository }}.git"
|
||||||
|
|
||||||
|
release-tag:
|
||||||
|
needs: [ update-package-version, major-version ]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
# Default input is the SHA that initially triggered the workflow. As we created a new commit in the previous job,
|
||||||
|
# to ensure we get the latest commit we use the ref for checkout: 'refs/heads/<branch_name>'
|
||||||
|
ref: ${{ github.ref }}
|
||||||
|
# Avoid persisting GITHUB_TOKEN credentials as they take priority over our service account PAT for `git push` operations
|
||||||
|
# More details: https://github.com/actions/checkout/blob/b4626ce19ce1106186ddf9bb20e706842f11a7c3/adrs/0153-checkout-v2.md#persist-credentials
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: Git push release tag
|
||||||
|
run: |
|
||||||
|
git config --global user.name "${{ vars.TF_DEVEX_CI_COMMIT_AUTHOR }}"
|
||||||
|
git config --global user.email "${{ vars.TF_DEVEX_CI_COMMIT_EMAIL }}"
|
||||||
|
|
||||||
|
git tag "${{ inputs.versionNumber }}"
|
||||||
|
git tag -f "${{ needs.major-version.outputs.version }}"
|
||||||
|
git push "https://${{ vars.TF_DEVEX_CI_COMMIT_AUTHOR }}:${{ secrets.TF_DEVEX_COMMIT_GITHUB_TOKEN }}@github.com/${{ github.repository }}.git" "${{ inputs.versionNumber }}"
|
||||||
|
git push "https://${{ vars.TF_DEVEX_CI_COMMIT_AUTHOR }}:${{ secrets.TF_DEVEX_COMMIT_GITHUB_TOKEN }}@github.com/${{ github.repository }}.git" -f "${{ needs.major-version.outputs.version }}"
|
||||||
|
|
||||||
|
release:
|
||||||
|
needs: [ changelog-version, release-tag ]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write # Needed to create GitHub release
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||||
|
with:
|
||||||
|
ref: ${{ inputs.versionNumber }}
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Generate Release Notes
|
||||||
|
run: |
|
||||||
|
cd .changes
|
||||||
|
sed -e "1{/# /d;}" -e "2{/^$/d;}" ${{ needs.changelog-version.outputs.version }}.md > /tmp/release-notes.txt
|
||||||
|
|
||||||
- name: GH Release
|
- name: GH Release
|
||||||
run: |
|
run: |
|
||||||
gh release create "${GITHUB_REF#refs/tags/}" --generate-notes
|
gh release create "${{ inputs.versionNumber }}" --notes-file /tmp/release-notes.txt --title "${{ inputs.versionNumber }}"
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
|
||||||
131
.github/workflows/setup-terraform.yml
vendored
131
.github/workflows/setup-terraform.yml
vendored
|
|
@ -1,4 +1,4 @@
|
||||||
name: 'Setup Terraform'
|
name: 'setup-terraform tests'
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
|
@ -20,7 +20,7 @@ jobs:
|
||||||
terraform-versions: [0.11.14, latest]
|
terraform-versions: [0.11.14, latest]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||||
|
|
||||||
- name: Setup Terraform - ${{ matrix['terraform-versions'] }}
|
- name: Setup Terraform - ${{ matrix['terraform-versions'] }}
|
||||||
uses: ./
|
uses: ./
|
||||||
|
|
@ -44,7 +44,7 @@ jobs:
|
||||||
terraform-versions: [0.11.14, latest]
|
terraform-versions: [0.11.14, latest]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||||
|
|
||||||
- name: Setup Terraform (no wrapper) - ${{ matrix['terraform-versions'] }}
|
- name: Setup Terraform (no wrapper) - ${{ matrix['terraform-versions'] }}
|
||||||
uses: ./
|
uses: ./
|
||||||
|
|
@ -69,7 +69,7 @@ jobs:
|
||||||
terraform-versions: [~0.12, 0.12.x, <0.13.0]
|
terraform-versions: [~0.12, 0.12.x, <0.13.0]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||||
|
|
||||||
- name: Setup Terraform - ${{ matrix['terraform-versions'] }}
|
- name: Setup Terraform - ${{ matrix['terraform-versions'] }}
|
||||||
uses: ./
|
uses: ./
|
||||||
|
|
@ -88,7 +88,7 @@ jobs:
|
||||||
terraform-versions: [~0.12, 0.12.x, <0.13.0]
|
terraform-versions: [~0.12, 0.12.x, <0.13.0]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||||
|
|
||||||
- name: Setup Terraform (no wrapper) - ${{ matrix['terraform-versions'] }}
|
- name: Setup Terraform (no wrapper) - ${{ matrix['terraform-versions'] }}
|
||||||
uses: ./
|
uses: ./
|
||||||
|
|
@ -100,7 +100,7 @@ jobs:
|
||||||
run: terraform version | grep 'Terraform v0\.12'
|
run: terraform version | grep 'Terraform v0\.12'
|
||||||
|
|
||||||
terraform-credentials-cloud:
|
terraform-credentials-cloud:
|
||||||
name: 'Terraform Cloud Credentials'
|
name: 'HCP Terraform Credentials'
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
|
|
@ -109,7 +109,7 @@ jobs:
|
||||||
TF_CLOUD_API_TOKEN: 'XXXXXXXXXXXXXX.atlasv1.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
|
TF_CLOUD_API_TOKEN: 'XXXXXXXXXXXXXX.atlasv1.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||||
|
|
||||||
- name: Setup Terraform
|
- name: Setup Terraform
|
||||||
uses: ./
|
uses: ./
|
||||||
|
|
@ -138,7 +138,7 @@ jobs:
|
||||||
TF_CLOUD_API_TOKEN: 'XXXXXXXXXXXXXX.atlasv1.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
|
TF_CLOUD_API_TOKEN: 'XXXXXXXXXXXXXX.atlasv1.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||||
|
|
||||||
- name: Setup Terraform
|
- name: Setup Terraform
|
||||||
uses: ./
|
uses: ./
|
||||||
|
|
@ -166,7 +166,7 @@ jobs:
|
||||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||||
|
|
||||||
- name: Setup Terraform
|
- name: Setup Terraform
|
||||||
uses: ./
|
uses: ./
|
||||||
|
|
@ -189,7 +189,7 @@ jobs:
|
||||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||||
|
|
||||||
- name: Setup Terraform
|
- name: Setup Terraform
|
||||||
uses: ./
|
uses: ./
|
||||||
|
|
@ -220,7 +220,7 @@ jobs:
|
||||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||||
|
|
||||||
- name: Setup Terraform
|
- name: Setup Terraform
|
||||||
uses: ./
|
uses: ./
|
||||||
|
|
@ -253,29 +253,26 @@ jobs:
|
||||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
|
shell: bash
|
||||||
working-directory: ./.github/workflows/data/local
|
working-directory: ./.github/workflows/data/local
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||||
|
|
||||||
- name: Setup Terraform
|
- name: Setup Terraform
|
||||||
uses: ./
|
uses: ./
|
||||||
|
|
||||||
- name: Terraform Init
|
- name: Terraform Init
|
||||||
shell: bash
|
|
||||||
run: terraform init
|
run: terraform init
|
||||||
|
|
||||||
- name: Terraform Format
|
- name: Terraform Format
|
||||||
shell: bash
|
|
||||||
run: terraform fmt -check
|
run: terraform fmt -check
|
||||||
|
|
||||||
- name: Terraform Plan
|
- name: Terraform Plan
|
||||||
id: plan
|
id: plan
|
||||||
shell: bash
|
|
||||||
run: terraform plan
|
run: terraform plan
|
||||||
|
|
||||||
- name: Print Terraform Plan
|
- name: Print Terraform Plan
|
||||||
shell: bash
|
|
||||||
run: echo "${{ steps.plan.outputs.stdout }}"
|
run: echo "${{ steps.plan.outputs.stdout }}"
|
||||||
|
|
||||||
terraform-run-local-no-wrapper:
|
terraform-run-local-no-wrapper:
|
||||||
|
|
@ -286,10 +283,11 @@ jobs:
|
||||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
|
shell: bash
|
||||||
working-directory: ./.github/workflows/data/local
|
working-directory: ./.github/workflows/data/local
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||||
|
|
||||||
- name: Setup Terraform
|
- name: Setup Terraform
|
||||||
uses: ./
|
uses: ./
|
||||||
|
|
@ -297,14 +295,107 @@ jobs:
|
||||||
terraform_wrapper: false
|
terraform_wrapper: false
|
||||||
|
|
||||||
- name: Terraform Init
|
- name: Terraform Init
|
||||||
shell: bash
|
|
||||||
run: terraform init
|
run: terraform init
|
||||||
|
|
||||||
- name: Terraform Format
|
- name: Terraform Format
|
||||||
shell: bash
|
|
||||||
run: terraform fmt -check
|
run: terraform fmt -check
|
||||||
|
|
||||||
- name: Terraform Plan
|
- name: Terraform Plan
|
||||||
id: plan
|
id: plan
|
||||||
shell: bash
|
|
||||||
run: terraform plan
|
run: terraform plan
|
||||||
|
|
||||||
|
terraform-stdout-wrapper:
|
||||||
|
name: 'Terraform STDOUT'
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash
|
||||||
|
working-directory: ./.github/workflows/data/local
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||||
|
|
||||||
|
- name: Setup Terraform
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
terraform_wrapper: true
|
||||||
|
|
||||||
|
- name: Terraform Init
|
||||||
|
run: terraform init
|
||||||
|
|
||||||
|
- name: Terraform Format
|
||||||
|
run: terraform fmt -check
|
||||||
|
|
||||||
|
- name: Terraform Apply
|
||||||
|
id: apply
|
||||||
|
run: terraform apply -auto-approve
|
||||||
|
|
||||||
|
- name: Terraform Output to JQ
|
||||||
|
id: output
|
||||||
|
run: terraform output -json | jq '.pet.value'
|
||||||
|
|
||||||
|
terraform-stdout-no-wrapper:
|
||||||
|
name: 'Terraform STDOUT No Wrapper'
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash
|
||||||
|
working-directory: ./.github/workflows/data/local
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||||
|
|
||||||
|
- name: Setup Terraform
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
terraform_wrapper: false
|
||||||
|
|
||||||
|
- name: Terraform Init
|
||||||
|
run: terraform init
|
||||||
|
|
||||||
|
- name: Terraform Format
|
||||||
|
run: terraform fmt -check
|
||||||
|
|
||||||
|
- name: Terraform Apply
|
||||||
|
id: apply
|
||||||
|
run: terraform apply -auto-approve
|
||||||
|
|
||||||
|
- name: Terraform Output to JQ
|
||||||
|
id: output
|
||||||
|
run: terraform output -json | jq '.pet.value'
|
||||||
|
|
||||||
|
# This test has an artificial delay for testing the streaming of STDOUT
|
||||||
|
terraform-wrapper-delayed-apply:
|
||||||
|
name: 'Terraform Delayed Apply'
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash
|
||||||
|
working-directory: ./.github/workflows/data/delay
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||||
|
|
||||||
|
- name: Setup Terraform
|
||||||
|
uses: ./
|
||||||
|
with:
|
||||||
|
terraform_wrapper: true
|
||||||
|
|
||||||
|
- name: Terraform Init
|
||||||
|
run: terraform init
|
||||||
|
|
||||||
|
- name: Terraform Format
|
||||||
|
run: terraform fmt -check
|
||||||
|
|
||||||
|
- name: Terraform Apply
|
||||||
|
id: apply
|
||||||
|
run: terraform apply -auto-approve
|
||||||
|
|
|
||||||
1
.husky/.gitignore
vendored
1
.husky/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
||||||
_
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
|
||||||
|
|
||||||
npm run build && git add dist/
|
|
||||||
37
CHANGELOG.md
37
CHANGELOG.md
|
|
@ -1,4 +1,39 @@
|
||||||
# [2.0.1] (2022-10-12)
|
## 3.1.2 (2024-08-19)
|
||||||
|
|
||||||
|
NOTES:
|
||||||
|
|
||||||
|
* This release introduces no functional changes. It does however include dependency updates which address upstream CVEs. ([#430](https://github.com/hashicorp/setup-terraform/issues/430))
|
||||||
|
|
||||||
|
## 3.1.1 (2024-05-07)
|
||||||
|
|
||||||
|
BUG FIXES:
|
||||||
|
|
||||||
|
* wrapper: Fix wrapper to output to stdout and stderr immediately when data is received ([#395](https://github.com/hashicorp/setup-terraform/issues/395))
|
||||||
|
|
||||||
|
## 3.1.0 (2024-04-23)
|
||||||
|
|
||||||
|
ENHANCEMENTS:
|
||||||
|
|
||||||
|
* Automatically fallback to darwin/amd64 for Terraform versions before 1.0.2 as releases for darwin/arm64 are not available ([#409](https://github.com/hashicorp/setup-terraform/issues/409))
|
||||||
|
|
||||||
|
## 3.0.0 (2023-10-30)
|
||||||
|
|
||||||
|
NOTES:
|
||||||
|
|
||||||
|
* Updated default runtime to node20 ([#346](https://github.com/hashicorp/setup-terraform/issues/346))
|
||||||
|
* The wrapper around the installed Terraform binary has been fixed to return the exact STDOUT and STDERR from Terraform when executing commands. Previous versions of setup-terraform may have required workarounds to process the STDOUT in bash, such as filtering out the first line or selectively parsing STDOUT with jq. These workarounds may need to be adjusted with `v3.0.0`, which will now return just the STDOUT/STDERR from Terraform with no errant characters/statements. ([#367](https://github.com/hashicorp/setup-terraform/issues/367))
|
||||||
|
|
||||||
|
BUG FIXES:
|
||||||
|
|
||||||
|
* Fixed malformed stdout when wrapper is enabled ([#367](https://github.com/hashicorp/setup-terraform/issues/367))
|
||||||
|
|
||||||
|
# [2.0.3] (2022-11-01)
|
||||||
|
|
||||||
|
### NOTES
|
||||||
|
|
||||||
|
* Reduced occurrences of GitHub Actions warnings for setting output [#247](https://github.com/hashicorp/setup-terraform/pull/247)
|
||||||
|
|
||||||
|
# [2.0.2] (2022-10-12)
|
||||||
|
|
||||||
### BUG FIXES
|
### BUG FIXES
|
||||||
|
|
||||||
|
|
|
||||||
11
META.d/_summary.yaml
Normal file
11
META.d/_summary.yaml
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
schema: 1.1
|
||||||
|
|
||||||
|
partition: tf-ecosystem
|
||||||
|
category: github-action
|
||||||
|
|
||||||
|
summary:
|
||||||
|
owner: team-tf-core-plugins
|
||||||
|
description: |
|
||||||
|
Sets up Terraform CLI in your GitHub Actions workflow.
|
||||||
|
visibility: public
|
||||||
6
META.d/data.yml
Normal file
6
META.d/data.yml
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
# Copyright (c) HashiCorp, Inc.
|
||||||
|
# SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
data_summary:
|
||||||
|
gdpr:
|
||||||
|
exempt: true
|
||||||
28
NOTICE
28
NOTICE
|
|
@ -1,28 +0,0 @@
|
||||||
# Notice
|
|
||||||
|
|
||||||
This project includes code under the following license(s):
|
|
||||||
|
|
||||||
```
|
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2020 GitHub, Inc.
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
||||||
```
|
|
||||||
56
README.md
56
README.md
|
|
@ -6,36 +6,36 @@
|
||||||
The `hashicorp/setup-terraform` action is a JavaScript action that sets up Terraform CLI in your GitHub Actions workflow by:
|
The `hashicorp/setup-terraform` action is a JavaScript action that sets up Terraform CLI in your GitHub Actions workflow by:
|
||||||
|
|
||||||
- Downloading a specific version of Terraform CLI and adding it to the `PATH`.
|
- Downloading a specific version of Terraform CLI and adding it to the `PATH`.
|
||||||
- Configuring the [Terraform CLI configuration file](https://www.terraform.io/docs/commands/cli-config.html) with a Terraform Cloud/Enterprise hostname and API token.
|
- Configuring the [Terraform CLI configuration file](https://www.terraform.io/docs/commands/cli-config.html) with a HCP Terraform/Terraform Enterprise hostname and API token.
|
||||||
- Installing a wrapper script to wrap subsequent calls of the `terraform` binary and expose its STDOUT, STDERR, and exit code as outputs named `stdout`, `stderr`, and `exitcode` respectively. (This can be optionally skipped if subsequent steps in the same job do not need to access the results of Terraform commands.)
|
- Installing a wrapper script to wrap subsequent calls of the `terraform` binary and expose its STDOUT, STDERR, and exit code as outputs named `stdout`, `stderr`, and `exitcode` respectively. (This can be optionally skipped if subsequent steps in the same job do not need to access the results of Terraform commands.)
|
||||||
|
|
||||||
After you've used the action, subsequent steps in the same job can run arbitrary Terraform commands using [the GitHub Actions `run` syntax](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun). This allows most Terraform commands to work exactly like they do on your local command line.
|
After you've used the action, subsequent steps in the same job can run arbitrary Terraform commands using [the GitHub Actions `run` syntax](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun). This allows most Terraform commands to work exactly like they do on your local command line.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
This action can be run on `ubuntu-latest`, `windows-latest`, and `macos-latest` GitHub Actions runners. When running on `windows-latest` the shell should be set to Bash.
|
This action can be run on `ubuntu-latest`, `windows-latest`, and `macos-latest` GitHub Actions runners. When running on `windows-latest` the shell should be set to Bash. When running on self-hosted GitHub Actions runners, NodeJS must be previously installed with the version specified in the [`action.yml`](https://github.com/hashicorp/setup-terraform/blob/main/action.yml).
|
||||||
|
|
||||||
The default configuration installs the latest version of Terraform CLI and installs the wrapper script to wrap subsequent calls to the `terraform` binary:
|
The default configuration installs the latest version of Terraform CLI and installs the wrapper script to wrap subsequent calls to the `terraform` binary:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: hashicorp/setup-terraform@v2
|
- uses: hashicorp/setup-terraform@v3
|
||||||
```
|
```
|
||||||
|
|
||||||
A specific version of Terraform CLI can be installed:
|
A specific version of Terraform CLI can be installed:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: hashicorp/setup-terraform@v2
|
- uses: hashicorp/setup-terraform@v3
|
||||||
with:
|
with:
|
||||||
terraform_version: 1.1.7
|
terraform_version: "1.1.7"
|
||||||
```
|
```
|
||||||
|
|
||||||
Credentials for Terraform Cloud ([app.terraform.io](https://app.terraform.io/)) can be configured:
|
Credentials for HCP Terraform ([app.terraform.io](https://app.terraform.io/)) can be configured:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: hashicorp/setup-terraform@v2
|
- uses: hashicorp/setup-terraform@v3
|
||||||
with:
|
with:
|
||||||
cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}
|
cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}
|
||||||
```
|
```
|
||||||
|
|
@ -44,7 +44,7 @@ Credentials for Terraform Enterprise (TFE) can be configured:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: hashicorp/setup-terraform@v2
|
- uses: hashicorp/setup-terraform@v3
|
||||||
with:
|
with:
|
||||||
cli_config_credentials_hostname: 'terraform.example.com'
|
cli_config_credentials_hostname: 'terraform.example.com'
|
||||||
cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}
|
cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}
|
||||||
|
|
@ -54,7 +54,7 @@ The wrapper script installation can be skipped by setting the `terraform_wrapper
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: hashicorp/setup-terraform@v2
|
- uses: hashicorp/setup-terraform@v3
|
||||||
with:
|
with:
|
||||||
terraform_wrapper: false
|
terraform_wrapper: false
|
||||||
```
|
```
|
||||||
|
|
@ -63,7 +63,7 @@ Subsequent steps can access outputs when the wrapper script is installed:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: hashicorp/setup-terraform@v2
|
- uses: hashicorp/setup-terraform@v3
|
||||||
|
|
||||||
- run: terraform init
|
- run: terraform init
|
||||||
|
|
||||||
|
|
@ -81,7 +81,7 @@ Outputs can be used in subsequent steps to comment on the pull request:
|
||||||
>
|
>
|
||||||
> Due to that limitation, you might end up with a failed workflow run even if the plan succeeded.
|
> Due to that limitation, you might end up with a failed workflow run even if the plan succeeded.
|
||||||
>
|
>
|
||||||
> Another approach is to append your plan into the $GITHUB_JOB_SUMMARY environment variable which supports markdown.
|
> Another approach is to append your plan into the $GITHUB_STEP_SUMMARY environment variable which supports markdown.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
defaults:
|
defaults:
|
||||||
|
|
@ -90,8 +90,8 @@ defaults:
|
||||||
permissions:
|
permissions:
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: hashicorp/setup-terraform@v2
|
- uses: hashicorp/setup-terraform@v3
|
||||||
|
|
||||||
- name: Terraform fmt
|
- name: Terraform fmt
|
||||||
id: fmt
|
id: fmt
|
||||||
|
|
@ -100,7 +100,7 @@ steps:
|
||||||
|
|
||||||
- name: Terraform Init
|
- name: Terraform Init
|
||||||
id: init
|
id: init
|
||||||
run: terraform init
|
run: terraform init -input=false
|
||||||
|
|
||||||
- name: Terraform Validate
|
- name: Terraform Validate
|
||||||
id: validate
|
id: validate
|
||||||
|
|
@ -108,10 +108,10 @@ steps:
|
||||||
|
|
||||||
- name: Terraform Plan
|
- name: Terraform Plan
|
||||||
id: plan
|
id: plan
|
||||||
run: terraform plan -no-color
|
run: terraform plan -no-color -input=false
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|
||||||
- uses: actions/github-script@v6
|
- uses: actions/github-script@v7
|
||||||
if: github.event_name == 'pull_request'
|
if: github.event_name == 'pull_request'
|
||||||
env:
|
env:
|
||||||
PLAN: "terraform\n${{ steps.plan.outputs.stdout }}"
|
PLAN: "terraform\n${{ steps.plan.outputs.stdout }}"
|
||||||
|
|
@ -158,8 +158,8 @@ defaults:
|
||||||
permissions:
|
permissions:
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- uses: hashicorp/setup-terraform@v2
|
- uses: hashicorp/setup-terraform@v3
|
||||||
|
|
||||||
- name: Terraform fmt
|
- name: Terraform fmt
|
||||||
id: fmt
|
id: fmt
|
||||||
|
|
@ -168,7 +168,7 @@ steps:
|
||||||
|
|
||||||
- name: Terraform Init
|
- name: Terraform Init
|
||||||
id: init
|
id: init
|
||||||
run: terraform init
|
run: terraform init -input=false
|
||||||
|
|
||||||
- name: Terraform Validate
|
- name: Terraform Validate
|
||||||
id: validate
|
id: validate
|
||||||
|
|
@ -176,10 +176,10 @@ steps:
|
||||||
|
|
||||||
- name: Terraform Plan
|
- name: Terraform Plan
|
||||||
id: plan
|
id: plan
|
||||||
run: terraform plan -no-color
|
run: terraform plan -no-color -input=false
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|
||||||
- uses: actions/github-script@v6
|
- uses: actions/github-script@v7
|
||||||
if: github.event_name == 'pull_request'
|
if: github.event_name == 'pull_request'
|
||||||
env:
|
env:
|
||||||
PLAN: "terraform\n${{ steps.plan.outputs.stdout }}"
|
PLAN: "terraform\n${{ steps.plan.outputs.stdout }}"
|
||||||
|
|
@ -242,13 +242,13 @@ steps:
|
||||||
|
|
||||||
The action supports the following inputs:
|
The action supports the following inputs:
|
||||||
|
|
||||||
- `cli_config_credentials_hostname` - (optional) The hostname of a Terraform Cloud/Enterprise instance to
|
- `cli_config_credentials_hostname` - (optional) The hostname of a HCP Terraform/Terraform Enterprise instance to
|
||||||
place within the credentials block of the Terraform CLI configuration file. Defaults to `app.terraform.io`.
|
place within the credentials block of the Terraform CLI configuration file. Defaults to `app.terraform.io`.
|
||||||
- `cli_config_credentials_token` - (optional) The API token for a Terraform Cloud/Enterprise instance to
|
- `cli_config_credentials_token` - (optional) The API token for a HCP Terraform/Terraform Enterprise instance to
|
||||||
place within the credentials block of the Terraform CLI configuration file.
|
place within the credentials block of the Terraform CLI configuration file.
|
||||||
- `terraform_version` - (optional) The version of Terraform CLI to install. Instead of a full version string,
|
- `terraform_version` - (optional) The version of Terraform CLI to install. Instead of a full version string,
|
||||||
you can also specify a constraint string (see [Semver Ranges](https://www.npmjs.com/package/semver#ranges)
|
you can also specify a constraint string (see [Semver Ranges](https://www.npmjs.com/package/semver#ranges)
|
||||||
for available range specifications). Examples are: `<1.2.0`, `~1.1.0`, `1.1.7` (all three installing
|
for available range specifications). Examples are: `"<1.2.0"`, `"~1.1.0"`, `"1.1.7"` (all three installing
|
||||||
the latest available `1.1` version). Prerelease versions can be specified and a range will stay within the
|
the latest available `1.1` version). Prerelease versions can be specified and a range will stay within the
|
||||||
given tag such as `beta` or `rc`. If no version is given, it will default to `latest`.
|
given tag such as `beta` or `rc`. If no version is given, it will default to `latest`.
|
||||||
- `terraform_wrapper` - (optional) Whether to install a wrapper to wrap subsequent calls of
|
- `terraform_wrapper` - (optional) Whether to install a wrapper to wrap subsequent calls of
|
||||||
|
|
@ -275,3 +275,11 @@ to `true`, the following outputs are available for subsequent steps that call th
|
||||||
## Experimental Status
|
## Experimental Status
|
||||||
|
|
||||||
By using the software in this repository (the "Software"), you acknowledge that: (1) the Software is still in development, may change, and has not been released as a commercial product by HashiCorp and is not currently supported in any way by HashiCorp; (2) the Software is provided on an "as-is" basis, and may include bugs, errors, or other issues; (3) the Software is NOT INTENDED FOR PRODUCTION USE, use of the Software may result in unexpected results, loss of data, or other unexpected results, and HashiCorp disclaims any and all liability resulting from use of the Software; and (4) HashiCorp reserves all rights to make all decisions about the features, functionality and commercial release (or non-release) of the Software, at any time and without any obligation or liability whatsoever.
|
By using the software in this repository (the "Software"), you acknowledge that: (1) the Software is still in development, may change, and has not been released as a commercial product by HashiCorp and is not currently supported in any way by HashiCorp; (2) the Software is provided on an "as-is" basis, and may include bugs, errors, or other issues; (3) the Software is NOT INTENDED FOR PRODUCTION USE, use of the Software may result in unexpected results, loss of data, or other unexpected results, and HashiCorp disclaims any and all liability resulting from use of the Software; and (4) HashiCorp reserves all rights to make all decisions about the features, functionality and commercial release (or non-release) of the Software, at any time and without any obligation or liability whatsoever.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
### License Headers
|
||||||
|
|
||||||
|
All source code files (excluding autogenerated files like `package.json`, prose, and files excluded in [.copywrite.hcl](.copywrite.hcl)) must have a license header at the top.
|
||||||
|
|
||||||
|
This can be autogenerated by installing the HashiCorp [`copywrite`](https://github.com/hashicorp/copywrite#getting-started) tool and running `copywrite headers` in the root of the repository.
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,11 @@ description: 'Sets up Terraform CLI in your GitHub Actions workflow.'
|
||||||
author: 'HashiCorp, Inc.'
|
author: 'HashiCorp, Inc.'
|
||||||
inputs:
|
inputs:
|
||||||
cli_config_credentials_hostname:
|
cli_config_credentials_hostname:
|
||||||
description: 'The hostname of a Terraform Cloud/Enterprise instance to place within the credentials block of the Terraform CLI configuration file. Defaults to `app.terraform.io`.'
|
description: 'The hostname of a HCP Terraform/Terraform Enterprise instance to place within the credentials block of the Terraform CLI configuration file. Defaults to `app.terraform.io`.'
|
||||||
default: 'app.terraform.io'
|
default: 'app.terraform.io'
|
||||||
required: false
|
required: false
|
||||||
cli_config_credentials_token:
|
cli_config_credentials_token:
|
||||||
description: 'The API token for a Terraform Cloud/Enterprise instance to place within the credentials block of the Terraform CLI configuration file.'
|
description: 'The API token for a HCP Terraform/Terraform Enterprise instance to place within the credentials block of the Terraform CLI configuration file.'
|
||||||
required: false
|
required: false
|
||||||
terraform_version:
|
terraform_version:
|
||||||
description: 'The version of Terraform CLI to install. Instead of full version string you can also specify constraint string starting with "<" (for example `<1.13.0`) to install the latest version satisfying the constraint. A value of `latest` will install the latest version of Terraform CLI. Defaults to `latest`.'
|
description: 'The version of Terraform CLI to install. Instead of full version string you can also specify constraint string starting with "<" (for example `<1.13.0`) to install the latest version satisfying the constraint. A value of `latest` will install the latest version of Terraform CLI. Defaults to `latest`.'
|
||||||
|
|
@ -18,7 +18,7 @@ inputs:
|
||||||
default: 'true'
|
default: 'true'
|
||||||
required: false
|
required: false
|
||||||
runs:
|
runs:
|
||||||
using: 'node16'
|
using: 'node20'
|
||||||
main: 'dist/index.js'
|
main: 'dist/index.js'
|
||||||
branding:
|
branding:
|
||||||
icon: 'terminal'
|
icon: 'terminal'
|
||||||
|
|
|
||||||
1000
dist/bridge.js
vendored
1000
dist/bridge.js
vendored
File diff suppressed because it is too large
Load diff
977
dist/events.js
vendored
977
dist/events.js
vendored
|
|
@ -1,977 +0,0 @@
|
||||||
// Copyright Joyent, Inc. and other Node contributors.
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
// copy of this software and associated documentation files (the
|
|
||||||
// "Software"), to deal in the Software without restriction, including
|
|
||||||
// without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
|
||||||
// persons to whom the Software is furnished to do so, subject to the
|
|
||||||
// following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included
|
|
||||||
// in all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
||||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
|
||||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
||||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
||||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
||||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
// Modified by the vm2 team to make this a standalone module to be loaded into the sandbox.
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const host = fromhost;
|
|
||||||
|
|
||||||
const {
|
|
||||||
Boolean,
|
|
||||||
Error,
|
|
||||||
String,
|
|
||||||
Symbol
|
|
||||||
} = globalThis;
|
|
||||||
|
|
||||||
const ReflectApply = Reflect.apply;
|
|
||||||
const ReflectOwnKeys = Reflect.ownKeys;
|
|
||||||
|
|
||||||
const ErrorCaptureStackTrace = Error.captureStackTrace;
|
|
||||||
|
|
||||||
const NumberIsNaN = Number.isNaN;
|
|
||||||
|
|
||||||
const ObjectCreate = Object.create;
|
|
||||||
const ObjectDefineProperty = Object.defineProperty;
|
|
||||||
const ObjectDefineProperties = Object.defineProperties;
|
|
||||||
const ObjectGetPrototypeOf = Object.getPrototypeOf;
|
|
||||||
|
|
||||||
const SymbolFor = Symbol.for;
|
|
||||||
|
|
||||||
function uncurryThis(func) {
|
|
||||||
return (thiz, ...args) => ReflectApply(func, thiz, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
const ArrayPrototypeIndexOf = uncurryThis(Array.prototype.indexOf);
|
|
||||||
const ArrayPrototypeJoin = uncurryThis(Array.prototype.join);
|
|
||||||
const ArrayPrototypeSlice = uncurryThis(Array.prototype.slice);
|
|
||||||
const ArrayPrototypeSplice = uncurryThis(Array.prototype.splice);
|
|
||||||
const ArrayPrototypeUnshift = uncurryThis(Array.prototype.unshift);
|
|
||||||
|
|
||||||
const kRejection = SymbolFor('nodejs.rejection');
|
|
||||||
|
|
||||||
function inspect(obj) {
|
|
||||||
return typeof obj === 'symbol' ? obj.toString() : `${obj}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function spliceOne(list, index) {
|
|
||||||
for (; index + 1 < list.length; index++)
|
|
||||||
list[index] = list[index + 1];
|
|
||||||
list.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
function assert(what, message) {
|
|
||||||
if (!what) throw new Error(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
function E(key, msg, Base) {
|
|
||||||
return function NodeError(...args) {
|
|
||||||
const error = new Base();
|
|
||||||
const message = ReflectApply(msg, error, args);
|
|
||||||
ObjectDefineProperties(error, {
|
|
||||||
message: {
|
|
||||||
value: message,
|
|
||||||
enumerable: false,
|
|
||||||
writable: true,
|
|
||||||
configurable: true,
|
|
||||||
},
|
|
||||||
toString: {
|
|
||||||
value() {
|
|
||||||
return `${this.name} [${key}]: ${this.message}`;
|
|
||||||
},
|
|
||||||
enumerable: false,
|
|
||||||
writable: true,
|
|
||||||
configurable: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
error.code = key;
|
|
||||||
return error;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const ERR_INVALID_ARG_TYPE = E('ERR_INVALID_ARG_TYPE',
|
|
||||||
(name, expected, actual) => {
|
|
||||||
assert(typeof name === 'string', "'name' must be a string");
|
|
||||||
if (!ArrayIsArray(expected)) {
|
|
||||||
expected = [expected];
|
|
||||||
}
|
|
||||||
|
|
||||||
let msg = 'The ';
|
|
||||||
if (StringPrototypeEndsWith(name, ' argument')) {
|
|
||||||
// For cases like 'first argument'
|
|
||||||
msg += `${name} `;
|
|
||||||
} else {
|
|
||||||
const type = StringPrototypeIncludes(name, '.') ? 'property' : 'argument';
|
|
||||||
msg += `"${name}" ${type} `;
|
|
||||||
}
|
|
||||||
msg += 'must be ';
|
|
||||||
|
|
||||||
const types = [];
|
|
||||||
const instances = [];
|
|
||||||
const other = [];
|
|
||||||
|
|
||||||
for (const value of expected) {
|
|
||||||
assert(typeof value === 'string',
|
|
||||||
'All expected entries have to be of type string');
|
|
||||||
if (ArrayPrototypeIncludes(kTypes, value)) {
|
|
||||||
ArrayPrototypePush(types, StringPrototypeToLowerCase(value));
|
|
||||||
} else if (RegExpPrototypeTest(classRegExp, value)) {
|
|
||||||
ArrayPrototypePush(instances, value);
|
|
||||||
} else {
|
|
||||||
assert(value !== 'object',
|
|
||||||
'The value "object" should be written as "Object"');
|
|
||||||
ArrayPrototypePush(other, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special handle `object` in case other instances are allowed to outline
|
|
||||||
// the differences between each other.
|
|
||||||
if (instances.length > 0) {
|
|
||||||
const pos = ArrayPrototypeIndexOf(types, 'object');
|
|
||||||
if (pos !== -1) {
|
|
||||||
ArrayPrototypeSplice(types, pos, 1);
|
|
||||||
ArrayPrototypePush(instances, 'Object');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (types.length > 0) {
|
|
||||||
if (types.length > 2) {
|
|
||||||
const last = ArrayPrototypePop(types);
|
|
||||||
msg += `one of type ${ArrayPrototypeJoin(types, ', ')}, or ${last}`;
|
|
||||||
} else if (types.length === 2) {
|
|
||||||
msg += `one of type ${types[0]} or ${types[1]}`;
|
|
||||||
} else {
|
|
||||||
msg += `of type ${types[0]}`;
|
|
||||||
}
|
|
||||||
if (instances.length > 0 || other.length > 0)
|
|
||||||
msg += ' or ';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (instances.length > 0) {
|
|
||||||
if (instances.length > 2) {
|
|
||||||
const last = ArrayPrototypePop(instances);
|
|
||||||
msg +=
|
|
||||||
`an instance of ${ArrayPrototypeJoin(instances, ', ')}, or ${last}`;
|
|
||||||
} else {
|
|
||||||
msg += `an instance of ${instances[0]}`;
|
|
||||||
if (instances.length === 2) {
|
|
||||||
msg += ` or ${instances[1]}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (other.length > 0)
|
|
||||||
msg += ' or ';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (other.length > 0) {
|
|
||||||
if (other.length > 2) {
|
|
||||||
const last = ArrayPrototypePop(other);
|
|
||||||
msg += `one of ${ArrayPrototypeJoin(other, ', ')}, or ${last}`;
|
|
||||||
} else if (other.length === 2) {
|
|
||||||
msg += `one of ${other[0]} or ${other[1]}`;
|
|
||||||
} else {
|
|
||||||
if (StringPrototypeToLowerCase(other[0]) !== other[0])
|
|
||||||
msg += 'an ';
|
|
||||||
msg += `${other[0]}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (actual == null) {
|
|
||||||
msg += `. Received ${actual}`;
|
|
||||||
} else if (typeof actual === 'function' && actual.name) {
|
|
||||||
msg += `. Received function ${actual.name}`;
|
|
||||||
} else if (typeof actual === 'object') {
|
|
||||||
if (actual.constructor && actual.constructor.name) {
|
|
||||||
msg += `. Received an instance of ${actual.constructor.name}`;
|
|
||||||
} else {
|
|
||||||
const inspected = inspect(actual, { depth: -1 });
|
|
||||||
msg += `. Received ${inspected}`;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let inspected = inspect(actual, { colors: false });
|
|
||||||
if (inspected.length > 25)
|
|
||||||
inspected = `${StringPrototypeSlice(inspected, 0, 25)}...`;
|
|
||||||
msg += `. Received type ${typeof actual} (${inspected})`;
|
|
||||||
}
|
|
||||||
return msg;
|
|
||||||
}, TypeError);
|
|
||||||
|
|
||||||
const ERR_INVALID_THIS = E('ERR_INVALID_THIS', s => `Value of "this" must be of type ${s}`, TypeError);
|
|
||||||
|
|
||||||
const ERR_OUT_OF_RANGE = E('ERR_OUT_OF_RANGE',
|
|
||||||
(str, range, input, replaceDefaultBoolean = false) => {
|
|
||||||
assert(range, 'Missing "range" argument');
|
|
||||||
let msg = replaceDefaultBoolean ? str :
|
|
||||||
`The value of "${str}" is out of range.`;
|
|
||||||
const received = inspect(input);
|
|
||||||
msg += ` It must be ${range}. Received ${received}`;
|
|
||||||
return msg;
|
|
||||||
}, RangeError);
|
|
||||||
|
|
||||||
const ERR_UNHANDLED_ERROR = E('ERR_UNHANDLED_ERROR',
|
|
||||||
err => {
|
|
||||||
const msg = 'Unhandled error.';
|
|
||||||
if (err === undefined) return msg;
|
|
||||||
return `${msg} (${err})`;
|
|
||||||
}, Error);
|
|
||||||
|
|
||||||
function validateBoolean(value, name) {
|
|
||||||
if (typeof value !== 'boolean')
|
|
||||||
throw new ERR_INVALID_ARG_TYPE(name, 'boolean', value);
|
|
||||||
}
|
|
||||||
|
|
||||||
function validateFunction(value, name) {
|
|
||||||
if (typeof value !== 'function')
|
|
||||||
throw new ERR_INVALID_ARG_TYPE(name, 'Function', value);
|
|
||||||
}
|
|
||||||
|
|
||||||
function validateString(value, name) {
|
|
||||||
if (typeof value !== 'string')
|
|
||||||
throw new ERR_INVALID_ARG_TYPE(name, 'string', value);
|
|
||||||
}
|
|
||||||
|
|
||||||
function nc(cond, e) {
|
|
||||||
return cond === undefined || cond === null ? e : cond;
|
|
||||||
}
|
|
||||||
|
|
||||||
function oc(base, key) {
|
|
||||||
return base === undefined || base === null ? undefined : base[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
const kCapture = Symbol('kCapture');
|
|
||||||
const kErrorMonitor = host.kErrorMonitor || Symbol('events.errorMonitor');
|
|
||||||
const kMaxEventTargetListeners = Symbol('events.maxEventTargetListeners');
|
|
||||||
const kMaxEventTargetListenersWarned =
|
|
||||||
Symbol('events.maxEventTargetListenersWarned');
|
|
||||||
|
|
||||||
const kIsEventTarget = SymbolFor('nodejs.event_target');
|
|
||||||
|
|
||||||
function isEventTarget(obj) {
|
|
||||||
return oc(oc(obj, 'constructor'), kIsEventTarget);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new `EventEmitter` instance.
|
|
||||||
* @param {{ captureRejections?: boolean; }} [opts]
|
|
||||||
* @constructs {EventEmitter}
|
|
||||||
*/
|
|
||||||
function EventEmitter(opts) {
|
|
||||||
EventEmitter.init.call(this, opts);
|
|
||||||
}
|
|
||||||
module.exports = EventEmitter;
|
|
||||||
if (host.once) module.exports.once = host.once;
|
|
||||||
if (host.on) module.exports.on = host.on;
|
|
||||||
if (host.getEventListeners) module.exports.getEventListeners = host.getEventListeners;
|
|
||||||
// Backwards-compat with node 0.10.x
|
|
||||||
EventEmitter.EventEmitter = EventEmitter;
|
|
||||||
|
|
||||||
EventEmitter.usingDomains = false;
|
|
||||||
|
|
||||||
EventEmitter.captureRejectionSymbol = kRejection;
|
|
||||||
ObjectDefineProperty(EventEmitter, 'captureRejections', {
|
|
||||||
get() {
|
|
||||||
return EventEmitter.prototype[kCapture];
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
validateBoolean(value, 'EventEmitter.captureRejections');
|
|
||||||
|
|
||||||
EventEmitter.prototype[kCapture] = value;
|
|
||||||
},
|
|
||||||
enumerable: true
|
|
||||||
});
|
|
||||||
|
|
||||||
if (host.EventEmitterReferencingAsyncResource) {
|
|
||||||
const kAsyncResource = Symbol('kAsyncResource');
|
|
||||||
const EventEmitterReferencingAsyncResource = host.EventEmitterReferencingAsyncResource;
|
|
||||||
|
|
||||||
class EventEmitterAsyncResource extends EventEmitter {
|
|
||||||
/**
|
|
||||||
* @param {{
|
|
||||||
* name?: string,
|
|
||||||
* triggerAsyncId?: number,
|
|
||||||
* requireManualDestroy?: boolean,
|
|
||||||
* }} [options]
|
|
||||||
*/
|
|
||||||
constructor(options = undefined) {
|
|
||||||
let name;
|
|
||||||
if (typeof options === 'string') {
|
|
||||||
name = options;
|
|
||||||
options = undefined;
|
|
||||||
} else {
|
|
||||||
if (new.target === EventEmitterAsyncResource) {
|
|
||||||
validateString(oc(options, 'name'), 'options.name');
|
|
||||||
}
|
|
||||||
name = oc(options, 'name') || new.target.name;
|
|
||||||
}
|
|
||||||
super(options);
|
|
||||||
|
|
||||||
this[kAsyncResource] =
|
|
||||||
new EventEmitterReferencingAsyncResource(this, name, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {symbol,string} event
|
|
||||||
* @param {...any} args
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
emit(event, ...args) {
|
|
||||||
if (this[kAsyncResource] === undefined)
|
|
||||||
throw new ERR_INVALID_THIS('EventEmitterAsyncResource');
|
|
||||||
const { asyncResource } = this;
|
|
||||||
ArrayPrototypeUnshift(args, super.emit, this, event);
|
|
||||||
return ReflectApply(asyncResource.runInAsyncScope, asyncResource,
|
|
||||||
args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
emitDestroy() {
|
|
||||||
if (this[kAsyncResource] === undefined)
|
|
||||||
throw new ERR_INVALID_THIS('EventEmitterAsyncResource');
|
|
||||||
this.asyncResource.emitDestroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
get asyncId() {
|
|
||||||
if (this[kAsyncResource] === undefined)
|
|
||||||
throw new ERR_INVALID_THIS('EventEmitterAsyncResource');
|
|
||||||
return this.asyncResource.asyncId();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
get triggerAsyncId() {
|
|
||||||
if (this[kAsyncResource] === undefined)
|
|
||||||
throw new ERR_INVALID_THIS('EventEmitterAsyncResource');
|
|
||||||
return this.asyncResource.triggerAsyncId();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {EventEmitterReferencingAsyncResource}
|
|
||||||
*/
|
|
||||||
get asyncResource() {
|
|
||||||
if (this[kAsyncResource] === undefined)
|
|
||||||
throw new ERR_INVALID_THIS('EventEmitterAsyncResource');
|
|
||||||
return this[kAsyncResource];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EventEmitter.EventEmitterAsyncResource = EventEmitterAsyncResource;
|
|
||||||
}
|
|
||||||
|
|
||||||
EventEmitter.errorMonitor = kErrorMonitor;
|
|
||||||
|
|
||||||
// The default for captureRejections is false
|
|
||||||
ObjectDefineProperty(EventEmitter.prototype, kCapture, {
|
|
||||||
value: false,
|
|
||||||
writable: true,
|
|
||||||
enumerable: false
|
|
||||||
});
|
|
||||||
|
|
||||||
EventEmitter.prototype._events = undefined;
|
|
||||||
EventEmitter.prototype._eventsCount = 0;
|
|
||||||
EventEmitter.prototype._maxListeners = undefined;
|
|
||||||
|
|
||||||
// By default EventEmitters will print a warning if more than 10 listeners are
|
|
||||||
// added to it. This is a useful default which helps finding memory leaks.
|
|
||||||
let defaultMaxListeners = 10;
|
|
||||||
|
|
||||||
function checkListener(listener) {
|
|
||||||
validateFunction(listener, 'listener');
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectDefineProperty(EventEmitter, 'defaultMaxListeners', {
|
|
||||||
enumerable: true,
|
|
||||||
get: function() {
|
|
||||||
return defaultMaxListeners;
|
|
||||||
},
|
|
||||||
set: function(arg) {
|
|
||||||
if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {
|
|
||||||
throw new ERR_OUT_OF_RANGE('defaultMaxListeners',
|
|
||||||
'a non-negative number',
|
|
||||||
arg);
|
|
||||||
}
|
|
||||||
defaultMaxListeners = arg;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ObjectDefineProperties(EventEmitter, {
|
|
||||||
kMaxEventTargetListeners: {
|
|
||||||
value: kMaxEventTargetListeners,
|
|
||||||
enumerable: false,
|
|
||||||
configurable: false,
|
|
||||||
writable: false,
|
|
||||||
},
|
|
||||||
kMaxEventTargetListenersWarned: {
|
|
||||||
value: kMaxEventTargetListenersWarned,
|
|
||||||
enumerable: false,
|
|
||||||
configurable: false,
|
|
||||||
writable: false,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the max listeners.
|
|
||||||
* @param {number} n
|
|
||||||
* @param {EventTarget[] | EventEmitter[]} [eventTargets]
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
EventEmitter.setMaxListeners =
|
|
||||||
function(n = defaultMaxListeners, ...eventTargets) {
|
|
||||||
if (typeof n !== 'number' || n < 0 || NumberIsNaN(n))
|
|
||||||
throw new ERR_OUT_OF_RANGE('n', 'a non-negative number', n);
|
|
||||||
if (eventTargets.length === 0) {
|
|
||||||
defaultMaxListeners = n;
|
|
||||||
} else {
|
|
||||||
for (let i = 0; i < eventTargets.length; i++) {
|
|
||||||
const target = eventTargets[i];
|
|
||||||
if (isEventTarget(target)) {
|
|
||||||
target[kMaxEventTargetListeners] = n;
|
|
||||||
target[kMaxEventTargetListenersWarned] = false;
|
|
||||||
} else if (typeof target.setMaxListeners === 'function') {
|
|
||||||
target.setMaxListeners(n);
|
|
||||||
} else {
|
|
||||||
throw new ERR_INVALID_ARG_TYPE(
|
|
||||||
'eventTargets',
|
|
||||||
['EventEmitter', 'EventTarget'],
|
|
||||||
target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// If you're updating this function definition, please also update any
|
|
||||||
// re-definitions, such as the one in the Domain module (lib/domain.js).
|
|
||||||
EventEmitter.init = function(opts) {
|
|
||||||
|
|
||||||
if (this._events === undefined ||
|
|
||||||
this._events === ObjectGetPrototypeOf(this)._events) {
|
|
||||||
this._events = ObjectCreate(null);
|
|
||||||
this._eventsCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._maxListeners = this._maxListeners || undefined;
|
|
||||||
|
|
||||||
|
|
||||||
if (oc(opts, 'captureRejections')) {
|
|
||||||
validateBoolean(opts.captureRejections, 'options.captureRejections');
|
|
||||||
this[kCapture] = Boolean(opts.captureRejections);
|
|
||||||
} else {
|
|
||||||
// Assigning the kCapture property directly saves an expensive
|
|
||||||
// prototype lookup in a very sensitive hot path.
|
|
||||||
this[kCapture] = EventEmitter.prototype[kCapture];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function addCatch(that, promise, type, args) {
|
|
||||||
if (!that[kCapture]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle Promises/A+ spec, then could be a getter
|
|
||||||
// that throws on second use.
|
|
||||||
try {
|
|
||||||
const then = promise.then;
|
|
||||||
|
|
||||||
if (typeof then === 'function') {
|
|
||||||
then.call(promise, undefined, function(err) {
|
|
||||||
// The callback is called with nextTick to avoid a follow-up
|
|
||||||
// rejection from this promise.
|
|
||||||
process.nextTick(emitUnhandledRejectionOrErr, that, err, type, args);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
that.emit('error', err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function emitUnhandledRejectionOrErr(ee, err, type, args) {
|
|
||||||
if (typeof ee[kRejection] === 'function') {
|
|
||||||
ee[kRejection](err, type, ...args);
|
|
||||||
} else {
|
|
||||||
// We have to disable the capture rejections mechanism, otherwise
|
|
||||||
// we might end up in an infinite loop.
|
|
||||||
const prev = ee[kCapture];
|
|
||||||
|
|
||||||
// If the error handler throws, it is not catchable and it
|
|
||||||
// will end up in 'uncaughtException'. We restore the previous
|
|
||||||
// value of kCapture in case the uncaughtException is present
|
|
||||||
// and the exception is handled.
|
|
||||||
try {
|
|
||||||
ee[kCapture] = false;
|
|
||||||
ee.emit('error', err);
|
|
||||||
} finally {
|
|
||||||
ee[kCapture] = prev;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Increases the max listeners of the event emitter.
|
|
||||||
* @param {number} n
|
|
||||||
* @returns {EventEmitter}
|
|
||||||
*/
|
|
||||||
EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
|
|
||||||
if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {
|
|
||||||
throw new ERR_OUT_OF_RANGE('n', 'a non-negative number', n);
|
|
||||||
}
|
|
||||||
this._maxListeners = n;
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
function _getMaxListeners(that) {
|
|
||||||
if (that._maxListeners === undefined)
|
|
||||||
return EventEmitter.defaultMaxListeners;
|
|
||||||
return that._maxListeners;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current max listener value for the event emitter.
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
|
|
||||||
return _getMaxListeners(this);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Synchronously calls each of the listeners registered
|
|
||||||
* for the event.
|
|
||||||
* @param {string | symbol} type
|
|
||||||
* @param {...any} [args]
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
EventEmitter.prototype.emit = function emit(type, ...args) {
|
|
||||||
let doError = (type === 'error');
|
|
||||||
|
|
||||||
const events = this._events;
|
|
||||||
if (events !== undefined) {
|
|
||||||
if (doError && events[kErrorMonitor] !== undefined)
|
|
||||||
this.emit(kErrorMonitor, ...args);
|
|
||||||
doError = (doError && events.error === undefined);
|
|
||||||
} else if (!doError)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// If there is no 'error' event listener then throw.
|
|
||||||
if (doError) {
|
|
||||||
let er;
|
|
||||||
if (args.length > 0)
|
|
||||||
er = args[0];
|
|
||||||
if (er instanceof Error) {
|
|
||||||
try {
|
|
||||||
const capture = {};
|
|
||||||
ErrorCaptureStackTrace(capture, EventEmitter.prototype.emit);
|
|
||||||
} catch (e) {}
|
|
||||||
|
|
||||||
// Note: The comments on the `throw` lines are intentional, they show
|
|
||||||
// up in Node's output if this results in an unhandled exception.
|
|
||||||
throw er; // Unhandled 'error' event
|
|
||||||
}
|
|
||||||
|
|
||||||
let stringifiedEr;
|
|
||||||
try {
|
|
||||||
stringifiedEr = inspect(er);
|
|
||||||
} catch (e) {
|
|
||||||
stringifiedEr = er;
|
|
||||||
}
|
|
||||||
|
|
||||||
// At least give some kind of context to the user
|
|
||||||
const err = new ERR_UNHANDLED_ERROR(stringifiedEr);
|
|
||||||
err.context = er;
|
|
||||||
throw err; // Unhandled 'error' event
|
|
||||||
}
|
|
||||||
|
|
||||||
const handler = events[type];
|
|
||||||
|
|
||||||
if (handler === undefined)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (typeof handler === 'function') {
|
|
||||||
const result = handler.apply(this, args);
|
|
||||||
|
|
||||||
// We check if result is undefined first because that
|
|
||||||
// is the most common case so we do not pay any perf
|
|
||||||
// penalty
|
|
||||||
if (result !== undefined && result !== null) {
|
|
||||||
addCatch(this, result, type, args);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const len = handler.length;
|
|
||||||
const listeners = arrayClone(handler);
|
|
||||||
for (let i = 0; i < len; ++i) {
|
|
||||||
const result = listeners[i].apply(this, args);
|
|
||||||
|
|
||||||
// We check if result is undefined first because that
|
|
||||||
// is the most common case so we do not pay any perf
|
|
||||||
// penalty.
|
|
||||||
// This code is duplicated because extracting it away
|
|
||||||
// would make it non-inlineable.
|
|
||||||
if (result !== undefined && result !== null) {
|
|
||||||
addCatch(this, result, type, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
function _addListener(target, type, listener, prepend) {
|
|
||||||
let m;
|
|
||||||
let events;
|
|
||||||
let existing;
|
|
||||||
|
|
||||||
checkListener(listener);
|
|
||||||
|
|
||||||
events = target._events;
|
|
||||||
if (events === undefined) {
|
|
||||||
events = target._events = ObjectCreate(null);
|
|
||||||
target._eventsCount = 0;
|
|
||||||
} else {
|
|
||||||
// To avoid recursion in the case that type === "newListener"! Before
|
|
||||||
// adding it to the listeners, first emit "newListener".
|
|
||||||
if (events.newListener !== undefined) {
|
|
||||||
target.emit('newListener', type,
|
|
||||||
nc(listener.listener, listener));
|
|
||||||
|
|
||||||
// Re-assign `events` because a newListener handler could have caused the
|
|
||||||
// this._events to be assigned to a new object
|
|
||||||
events = target._events;
|
|
||||||
}
|
|
||||||
existing = events[type];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (existing === undefined) {
|
|
||||||
// Optimize the case of one listener. Don't need the extra array object.
|
|
||||||
events[type] = listener;
|
|
||||||
++target._eventsCount;
|
|
||||||
} else {
|
|
||||||
if (typeof existing === 'function') {
|
|
||||||
// Adding the second element, need to change to array.
|
|
||||||
existing = events[type] =
|
|
||||||
prepend ? [listener, existing] : [existing, listener];
|
|
||||||
// If we've already got an array, just append.
|
|
||||||
} else if (prepend) {
|
|
||||||
existing.unshift(listener);
|
|
||||||
} else {
|
|
||||||
existing.push(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for listener leak
|
|
||||||
m = _getMaxListeners(target);
|
|
||||||
if (m > 0 && existing.length > m && !existing.warned) {
|
|
||||||
existing.warned = true;
|
|
||||||
// No error code for this since it is a Warning
|
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
|
||||||
const w = new Error('Possible EventEmitter memory leak detected. ' +
|
|
||||||
`${existing.length} ${String(type)} listeners ` +
|
|
||||||
`added to ${inspect(target, { depth: -1 })}. Use ` +
|
|
||||||
'emitter.setMaxListeners() to increase limit');
|
|
||||||
w.name = 'MaxListenersExceededWarning';
|
|
||||||
w.emitter = target;
|
|
||||||
w.type = type;
|
|
||||||
w.count = existing.length;
|
|
||||||
process.emitWarning(w);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a listener to the event emitter.
|
|
||||||
* @param {string | symbol} type
|
|
||||||
* @param {Function} listener
|
|
||||||
* @returns {EventEmitter}
|
|
||||||
*/
|
|
||||||
EventEmitter.prototype.addListener = function addListener(type, listener) {
|
|
||||||
return _addListener(this, type, listener, false);
|
|
||||||
};
|
|
||||||
|
|
||||||
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the `listener` function to the beginning of
|
|
||||||
* the listeners array.
|
|
||||||
* @param {string | symbol} type
|
|
||||||
* @param {Function} listener
|
|
||||||
* @returns {EventEmitter}
|
|
||||||
*/
|
|
||||||
EventEmitter.prototype.prependListener =
|
|
||||||
function prependListener(type, listener) {
|
|
||||||
return _addListener(this, type, listener, true);
|
|
||||||
};
|
|
||||||
|
|
||||||
function onceWrapper() {
|
|
||||||
if (!this.fired) {
|
|
||||||
this.target.removeListener(this.type, this.wrapFn);
|
|
||||||
this.fired = true;
|
|
||||||
if (arguments.length === 0)
|
|
||||||
return this.listener.call(this.target);
|
|
||||||
return this.listener.apply(this.target, arguments);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function _onceWrap(target, type, listener) {
|
|
||||||
const state = { fired: false, wrapFn: undefined, target, type, listener };
|
|
||||||
const wrapped = onceWrapper.bind(state);
|
|
||||||
wrapped.listener = listener;
|
|
||||||
state.wrapFn = wrapped;
|
|
||||||
return wrapped;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a one-time `listener` function to the event emitter.
|
|
||||||
* @param {string | symbol} type
|
|
||||||
* @param {Function} listener
|
|
||||||
* @returns {EventEmitter}
|
|
||||||
*/
|
|
||||||
EventEmitter.prototype.once = function once(type, listener) {
|
|
||||||
checkListener(listener);
|
|
||||||
|
|
||||||
this.on(type, _onceWrap(this, type, listener));
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a one-time `listener` function to the beginning of
|
|
||||||
* the listeners array.
|
|
||||||
* @param {string | symbol} type
|
|
||||||
* @param {Function} listener
|
|
||||||
* @returns {EventEmitter}
|
|
||||||
*/
|
|
||||||
EventEmitter.prototype.prependOnceListener =
|
|
||||||
function prependOnceListener(type, listener) {
|
|
||||||
checkListener(listener);
|
|
||||||
|
|
||||||
this.prependListener(type, _onceWrap(this, type, listener));
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the specified `listener` from the listeners array.
|
|
||||||
* @param {string | symbol} type
|
|
||||||
* @param {Function} listener
|
|
||||||
* @returns {EventEmitter}
|
|
||||||
*/
|
|
||||||
EventEmitter.prototype.removeListener =
|
|
||||||
function removeListener(type, listener) {
|
|
||||||
checkListener(listener);
|
|
||||||
|
|
||||||
const events = this._events;
|
|
||||||
if (events === undefined)
|
|
||||||
return this;
|
|
||||||
|
|
||||||
const list = events[type];
|
|
||||||
if (list === undefined)
|
|
||||||
return this;
|
|
||||||
|
|
||||||
if (list === listener || list.listener === listener) {
|
|
||||||
if (--this._eventsCount === 0)
|
|
||||||
this._events = ObjectCreate(null);
|
|
||||||
else {
|
|
||||||
delete events[type];
|
|
||||||
if (events.removeListener)
|
|
||||||
this.emit('removeListener', type, list.listener || listener);
|
|
||||||
}
|
|
||||||
} else if (typeof list !== 'function') {
|
|
||||||
let position = -1;
|
|
||||||
|
|
||||||
for (let i = list.length - 1; i >= 0; i--) {
|
|
||||||
if (list[i] === listener || list[i].listener === listener) {
|
|
||||||
position = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (position < 0)
|
|
||||||
return this;
|
|
||||||
|
|
||||||
if (position === 0)
|
|
||||||
list.shift();
|
|
||||||
else {
|
|
||||||
spliceOne(list, position);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (list.length === 1)
|
|
||||||
events[type] = list[0];
|
|
||||||
|
|
||||||
if (events.removeListener !== undefined)
|
|
||||||
this.emit('removeListener', type, listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes all listeners from the event emitter. (Only
|
|
||||||
* removes listeners for a specific event name if specified
|
|
||||||
* as `type`).
|
|
||||||
* @param {string | symbol} [type]
|
|
||||||
* @returns {EventEmitter}
|
|
||||||
*/
|
|
||||||
EventEmitter.prototype.removeAllListeners =
|
|
||||||
function removeAllListeners(type) {
|
|
||||||
const events = this._events;
|
|
||||||
if (events === undefined)
|
|
||||||
return this;
|
|
||||||
|
|
||||||
// Not listening for removeListener, no need to emit
|
|
||||||
if (events.removeListener === undefined) {
|
|
||||||
if (arguments.length === 0) {
|
|
||||||
this._events = ObjectCreate(null);
|
|
||||||
this._eventsCount = 0;
|
|
||||||
} else if (events[type] !== undefined) {
|
|
||||||
if (--this._eventsCount === 0)
|
|
||||||
this._events = ObjectCreate(null);
|
|
||||||
else
|
|
||||||
delete events[type];
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emit removeListener for all listeners on all events
|
|
||||||
if (arguments.length === 0) {
|
|
||||||
for (const key of ReflectOwnKeys(events)) {
|
|
||||||
if (key === 'removeListener') continue;
|
|
||||||
this.removeAllListeners(key);
|
|
||||||
}
|
|
||||||
this.removeAllListeners('removeListener');
|
|
||||||
this._events = ObjectCreate(null);
|
|
||||||
this._eventsCount = 0;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
const listeners = events[type];
|
|
||||||
|
|
||||||
if (typeof listeners === 'function') {
|
|
||||||
this.removeListener(type, listeners);
|
|
||||||
} else if (listeners !== undefined) {
|
|
||||||
// LIFO order
|
|
||||||
for (let i = listeners.length - 1; i >= 0; i--) {
|
|
||||||
this.removeListener(type, listeners[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
function _listeners(target, type, unwrap) {
|
|
||||||
const events = target._events;
|
|
||||||
|
|
||||||
if (events === undefined)
|
|
||||||
return [];
|
|
||||||
|
|
||||||
const evlistener = events[type];
|
|
||||||
if (evlistener === undefined)
|
|
||||||
return [];
|
|
||||||
|
|
||||||
if (typeof evlistener === 'function')
|
|
||||||
return unwrap ? [evlistener.listener || evlistener] : [evlistener];
|
|
||||||
|
|
||||||
return unwrap ?
|
|
||||||
unwrapListeners(evlistener) : arrayClone(evlistener);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a copy of the array of listeners for the event name
|
|
||||||
* specified as `type`.
|
|
||||||
* @param {string | symbol} type
|
|
||||||
* @returns {Function[]}
|
|
||||||
*/
|
|
||||||
EventEmitter.prototype.listeners = function listeners(type) {
|
|
||||||
return _listeners(this, type, true);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a copy of the array of listeners and wrappers for
|
|
||||||
* the event name specified as `type`.
|
|
||||||
* @param {string | symbol} type
|
|
||||||
* @returns {Function[]}
|
|
||||||
*/
|
|
||||||
EventEmitter.prototype.rawListeners = function rawListeners(type) {
|
|
||||||
return _listeners(this, type, false);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of listeners listening to the event name
|
|
||||||
* specified as `type`.
|
|
||||||
* @deprecated since v3.2.0
|
|
||||||
* @param {EventEmitter} emitter
|
|
||||||
* @param {string | symbol} type
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
EventEmitter.listenerCount = function(emitter, type) {
|
|
||||||
if (typeof emitter.listenerCount === 'function') {
|
|
||||||
return emitter.listenerCount(type);
|
|
||||||
}
|
|
||||||
return emitter.listenerCount(type);
|
|
||||||
};
|
|
||||||
|
|
||||||
EventEmitter.prototype.listenerCount = listenerCount;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the number of listeners listening to event name
|
|
||||||
* specified as `type`.
|
|
||||||
* @param {string | symbol} type
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
function listenerCount(type) {
|
|
||||||
const events = this._events;
|
|
||||||
|
|
||||||
if (events !== undefined) {
|
|
||||||
const evlistener = events[type];
|
|
||||||
|
|
||||||
if (typeof evlistener === 'function') {
|
|
||||||
return 1;
|
|
||||||
} else if (evlistener !== undefined) {
|
|
||||||
return evlistener.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an array listing the events for which
|
|
||||||
* the emitter has registered listeners.
|
|
||||||
* @returns {any[]}
|
|
||||||
*/
|
|
||||||
EventEmitter.prototype.eventNames = function eventNames() {
|
|
||||||
return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];
|
|
||||||
};
|
|
||||||
|
|
||||||
function arrayClone(arr) {
|
|
||||||
// At least since V8 8.3, this implementation is faster than the previous
|
|
||||||
// which always used a simple for-loop
|
|
||||||
switch (arr.length) {
|
|
||||||
case 2: return [arr[0], arr[1]];
|
|
||||||
case 3: return [arr[0], arr[1], arr[2]];
|
|
||||||
case 4: return [arr[0], arr[1], arr[2], arr[3]];
|
|
||||||
case 5: return [arr[0], arr[1], arr[2], arr[3], arr[4]];
|
|
||||||
case 6: return [arr[0], arr[1], arr[2], arr[3], arr[4], arr[5]];
|
|
||||||
}
|
|
||||||
return ArrayPrototypeSlice(arr);
|
|
||||||
}
|
|
||||||
|
|
||||||
function unwrapListeners(arr) {
|
|
||||||
const ret = arrayClone(arr);
|
|
||||||
for (let i = 0; i < ret.length; ++i) {
|
|
||||||
const orig = ret[i].listener;
|
|
||||||
if (typeof orig === 'function')
|
|
||||||
ret[i] = orig;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
44135
dist/index.js
vendored
44135
dist/index.js
vendored
File diff suppressed because one or more lines are too long
25582
dist/index1.js
vendored
25582
dist/index1.js
vendored
File diff suppressed because one or more lines are too long
464
dist/setup-node-sandbox.js
vendored
464
dist/setup-node-sandbox.js
vendored
|
|
@ -1,464 +0,0 @@
|
||||||
/* global host, data, VMError */
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const LocalError = Error;
|
|
||||||
const LocalTypeError = TypeError;
|
|
||||||
const LocalWeakMap = WeakMap;
|
|
||||||
|
|
||||||
const {
|
|
||||||
apply: localReflectApply,
|
|
||||||
defineProperty: localReflectDefineProperty
|
|
||||||
} = Reflect;
|
|
||||||
|
|
||||||
const {
|
|
||||||
set: localWeakMapSet,
|
|
||||||
get: localWeakMapGet
|
|
||||||
} = LocalWeakMap.prototype;
|
|
||||||
|
|
||||||
const {
|
|
||||||
isArray: localArrayIsArray
|
|
||||||
} = Array;
|
|
||||||
|
|
||||||
function uncurryThis(func) {
|
|
||||||
return (thiz, ...args) => localReflectApply(func, thiz, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
const localArrayPrototypeSlice = uncurryThis(Array.prototype.slice);
|
|
||||||
const localArrayPrototypeIncludes = uncurryThis(Array.prototype.includes);
|
|
||||||
const localArrayPrototypePush = uncurryThis(Array.prototype.push);
|
|
||||||
const localArrayPrototypeIndexOf = uncurryThis(Array.prototype.indexOf);
|
|
||||||
const localArrayPrototypeSplice = uncurryThis(Array.prototype.splice);
|
|
||||||
const localStringPrototypeStartsWith = uncurryThis(String.prototype.startsWith);
|
|
||||||
const localStringPrototypeSlice = uncurryThis(String.prototype.slice);
|
|
||||||
const localStringPrototypeIndexOf = uncurryThis(String.prototype.indexOf);
|
|
||||||
|
|
||||||
const {
|
|
||||||
argv: optionArgv,
|
|
||||||
env: optionEnv,
|
|
||||||
console: optionConsole,
|
|
||||||
vm,
|
|
||||||
resolver,
|
|
||||||
extensions
|
|
||||||
} = data;
|
|
||||||
|
|
||||||
function ensureSandboxArray(a) {
|
|
||||||
return localArrayPrototypeSlice(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
const globalPaths = ensureSandboxArray(resolver.globalPaths);
|
|
||||||
|
|
||||||
class Module {
|
|
||||||
|
|
||||||
constructor(id, path, parent) {
|
|
||||||
this.id = id;
|
|
||||||
this.filename = id;
|
|
||||||
this.path = path;
|
|
||||||
this.parent = parent;
|
|
||||||
this.loaded = false;
|
|
||||||
this.paths = path ? ensureSandboxArray(resolver.genLookupPaths(path)) : [];
|
|
||||||
this.children = [];
|
|
||||||
this.exports = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
_updateChildren(child, isNew) {
|
|
||||||
const children = this.children;
|
|
||||||
if (children && (isNew || !localArrayPrototypeIncludes(children, child))) {
|
|
||||||
localArrayPrototypePush(children, child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
require(id) {
|
|
||||||
return requireImpl(this, id, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const originalRequire = Module.prototype.require;
|
|
||||||
const cacheBuiltins = {__proto__: null};
|
|
||||||
|
|
||||||
function requireImpl(mod, id, direct) {
|
|
||||||
if (direct && mod.require !== originalRequire) {
|
|
||||||
return mod.require(id);
|
|
||||||
}
|
|
||||||
const filename = resolver.resolve(mod, id, undefined, Module._extensions, direct);
|
|
||||||
if (localStringPrototypeStartsWith(filename, 'node:')) {
|
|
||||||
id = localStringPrototypeSlice(filename, 5);
|
|
||||||
let nmod = cacheBuiltins[id];
|
|
||||||
if (!nmod) {
|
|
||||||
nmod = resolver.loadBuiltinModule(vm, id);
|
|
||||||
if (!nmod) throw new VMError(`Cannot find module '${filename}'`, 'ENOTFOUND');
|
|
||||||
cacheBuiltins[id] = nmod;
|
|
||||||
}
|
|
||||||
return nmod;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cachedModule = Module._cache[filename];
|
|
||||||
if (cachedModule !== undefined) {
|
|
||||||
mod._updateChildren(cachedModule, false);
|
|
||||||
return cachedModule.exports;
|
|
||||||
}
|
|
||||||
|
|
||||||
let nmod = cacheBuiltins[id];
|
|
||||||
if (nmod) return nmod;
|
|
||||||
nmod = resolver.loadBuiltinModule(vm, id);
|
|
||||||
if (nmod) {
|
|
||||||
cacheBuiltins[id] = nmod;
|
|
||||||
return nmod;
|
|
||||||
}
|
|
||||||
|
|
||||||
const path = resolver.pathDirname(filename);
|
|
||||||
const module = new Module(filename, path, mod);
|
|
||||||
resolver.registerModule(module, filename, path, mod, direct);
|
|
||||||
mod._updateChildren(module, true);
|
|
||||||
try {
|
|
||||||
Module._cache[filename] = module;
|
|
||||||
const handler = findBestExtensionHandler(filename);
|
|
||||||
handler(module, filename);
|
|
||||||
module.loaded = true;
|
|
||||||
} catch (e) {
|
|
||||||
delete Module._cache[filename];
|
|
||||||
const children = mod.children;
|
|
||||||
if (localArrayIsArray(children)) {
|
|
||||||
const index = localArrayPrototypeIndexOf(children, module);
|
|
||||||
if (index !== -1) {
|
|
||||||
localArrayPrototypeSplice(children, index, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
return module.exports;
|
|
||||||
}
|
|
||||||
|
|
||||||
Module.builtinModules = ensureSandboxArray(resolver.getBuiltinModulesList());
|
|
||||||
Module.globalPaths = globalPaths;
|
|
||||||
Module._extensions = {__proto__: null};
|
|
||||||
Module._cache = {__proto__: null};
|
|
||||||
|
|
||||||
{
|
|
||||||
const keys = Object.getOwnPropertyNames(extensions);
|
|
||||||
for (let i = 0; i < keys.length; i++) {
|
|
||||||
const key = keys[i];
|
|
||||||
const handler = extensions[key];
|
|
||||||
Module._extensions[key] = (mod, filename) => handler(mod, filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function findBestExtensionHandler(filename) {
|
|
||||||
const name = resolver.pathBasename(filename);
|
|
||||||
for (let i = 0; (i = localStringPrototypeIndexOf(name, '.', i + 1)) !== -1;) {
|
|
||||||
const ext = localStringPrototypeSlice(name, i);
|
|
||||||
const handler = Module._extensions[ext];
|
|
||||||
if (handler) return handler;
|
|
||||||
}
|
|
||||||
const js = Module._extensions['.js'];
|
|
||||||
if (js) return js;
|
|
||||||
const keys = Object.getOwnPropertyNames(Module._extensions);
|
|
||||||
if (keys.length === 0) throw new VMError(`Failed to load '${filename}': Unknown type.`, 'ELOADFAIL');
|
|
||||||
return Module._extensions[keys[0]];
|
|
||||||
}
|
|
||||||
|
|
||||||
function createRequireForModule(mod) {
|
|
||||||
// eslint-disable-next-line no-shadow
|
|
||||||
function require(id) {
|
|
||||||
return requireImpl(mod, id, true);
|
|
||||||
}
|
|
||||||
function resolve(id, options) {
|
|
||||||
return resolver.resolve(mod, id, options, Module._extensions, true);
|
|
||||||
}
|
|
||||||
require.resolve = resolve;
|
|
||||||
function paths(id) {
|
|
||||||
return ensureSandboxArray(resolver.lookupPaths(mod, id));
|
|
||||||
}
|
|
||||||
resolve.paths = paths;
|
|
||||||
|
|
||||||
require.extensions = Module._extensions;
|
|
||||||
|
|
||||||
require.cache = Module._cache;
|
|
||||||
|
|
||||||
return require;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepare sandbox.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const TIMERS = new LocalWeakMap();
|
|
||||||
|
|
||||||
class Timeout {
|
|
||||||
}
|
|
||||||
|
|
||||||
class Interval {
|
|
||||||
}
|
|
||||||
|
|
||||||
class Immediate {
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearTimer(timer) {
|
|
||||||
const obj = localReflectApply(localWeakMapGet, TIMERS, [timer]);
|
|
||||||
if (obj) {
|
|
||||||
obj.clear(obj.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a function and not an arrow function, since the original is also a function
|
|
||||||
// eslint-disable-next-line no-shadow
|
|
||||||
global.setTimeout = function setTimeout(callback, delay, ...args) {
|
|
||||||
if (typeof callback !== 'function') throw new LocalTypeError('"callback" argument must be a function');
|
|
||||||
const obj = new Timeout(callback, args);
|
|
||||||
const cb = () => {
|
|
||||||
localReflectApply(callback, null, args);
|
|
||||||
};
|
|
||||||
const tmr = host.setTimeout(cb, delay);
|
|
||||||
|
|
||||||
const ref = {
|
|
||||||
__proto__: null,
|
|
||||||
clear: host.clearTimeout,
|
|
||||||
value: tmr
|
|
||||||
};
|
|
||||||
|
|
||||||
localReflectApply(localWeakMapSet, TIMERS, [obj, ref]);
|
|
||||||
return obj;
|
|
||||||
};
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-shadow
|
|
||||||
global.setInterval = function setInterval(callback, interval, ...args) {
|
|
||||||
if (typeof callback !== 'function') throw new LocalTypeError('"callback" argument must be a function');
|
|
||||||
const obj = new Interval();
|
|
||||||
const cb = () => {
|
|
||||||
localReflectApply(callback, null, args);
|
|
||||||
};
|
|
||||||
const tmr = host.setInterval(cb, interval);
|
|
||||||
|
|
||||||
const ref = {
|
|
||||||
__proto__: null,
|
|
||||||
clear: host.clearInterval,
|
|
||||||
value: tmr
|
|
||||||
};
|
|
||||||
|
|
||||||
localReflectApply(localWeakMapSet, TIMERS, [obj, ref]);
|
|
||||||
return obj;
|
|
||||||
};
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-shadow
|
|
||||||
global.setImmediate = function setImmediate(callback, ...args) {
|
|
||||||
if (typeof callback !== 'function') throw new LocalTypeError('"callback" argument must be a function');
|
|
||||||
const obj = new Immediate();
|
|
||||||
const cb = () => {
|
|
||||||
localReflectApply(callback, null, args);
|
|
||||||
};
|
|
||||||
const tmr = host.setImmediate(cb);
|
|
||||||
|
|
||||||
const ref = {
|
|
||||||
__proto__: null,
|
|
||||||
clear: host.clearImmediate,
|
|
||||||
value: tmr
|
|
||||||
};
|
|
||||||
|
|
||||||
localReflectApply(localWeakMapSet, TIMERS, [obj, ref]);
|
|
||||||
return obj;
|
|
||||||
};
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-shadow
|
|
||||||
global.clearTimeout = function clearTimeout(timeout) {
|
|
||||||
clearTimer(timeout);
|
|
||||||
};
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-shadow
|
|
||||||
global.clearInterval = function clearInterval(interval) {
|
|
||||||
clearTimer(interval);
|
|
||||||
};
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-shadow
|
|
||||||
global.clearImmediate = function clearImmediate(immediate) {
|
|
||||||
clearTimer(immediate);
|
|
||||||
};
|
|
||||||
|
|
||||||
const localProcess = host.process;
|
|
||||||
|
|
||||||
function vmEmitArgs(event, args) {
|
|
||||||
const allargs = [event];
|
|
||||||
for (let i = 0; i < args.length; i++) {
|
|
||||||
if (!localReflectDefineProperty(allargs, i + 1, {
|
|
||||||
__proto__: null,
|
|
||||||
value: args[i],
|
|
||||||
writable: true,
|
|
||||||
enumerable: true,
|
|
||||||
configurable: true
|
|
||||||
})) throw new LocalError('Unexpected');
|
|
||||||
}
|
|
||||||
return localReflectApply(vm.emit, vm, allargs);
|
|
||||||
}
|
|
||||||
|
|
||||||
const LISTENERS = new LocalWeakMap();
|
|
||||||
const LISTENER_HANDLER = new LocalWeakMap();
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {*} name
|
|
||||||
* @param {*} handler
|
|
||||||
* @this process
|
|
||||||
* @return {this}
|
|
||||||
*/
|
|
||||||
function addListener(name, handler) {
|
|
||||||
if (name !== 'beforeExit' && name !== 'exit') {
|
|
||||||
throw new LocalError(`Access denied to listen for '${name}' event.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
let cb = localReflectApply(localWeakMapGet, LISTENERS, [handler]);
|
|
||||||
if (!cb) {
|
|
||||||
cb = () => {
|
|
||||||
handler();
|
|
||||||
};
|
|
||||||
localReflectApply(localWeakMapSet, LISTENER_HANDLER, [cb, handler]);
|
|
||||||
localReflectApply(localWeakMapSet, LISTENERS, [handler, cb]);
|
|
||||||
}
|
|
||||||
|
|
||||||
localProcess.on(name, cb);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @this process
|
|
||||||
* @return {this}
|
|
||||||
*/
|
|
||||||
// eslint-disable-next-line no-shadow
|
|
||||||
function process() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME wrong class structure
|
|
||||||
global.process = {
|
|
||||||
__proto__: process.prototype,
|
|
||||||
argv: optionArgv !== undefined ? optionArgv : [],
|
|
||||||
title: localProcess.title,
|
|
||||||
version: localProcess.version,
|
|
||||||
versions: localProcess.versions,
|
|
||||||
arch: localProcess.arch,
|
|
||||||
platform: localProcess.platform,
|
|
||||||
env: optionEnv !== undefined ? optionEnv : {},
|
|
||||||
pid: localProcess.pid,
|
|
||||||
features: localProcess.features,
|
|
||||||
nextTick: function nextTick(callback, ...args) {
|
|
||||||
if (typeof callback !== 'function') {
|
|
||||||
throw new LocalError('Callback must be a function.');
|
|
||||||
}
|
|
||||||
|
|
||||||
localProcess.nextTick(()=>{
|
|
||||||
localReflectApply(callback, null, args);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
hrtime: function hrtime(time) {
|
|
||||||
return localProcess.hrtime(time);
|
|
||||||
},
|
|
||||||
cwd: function cwd() {
|
|
||||||
return localProcess.cwd();
|
|
||||||
},
|
|
||||||
addListener,
|
|
||||||
on: addListener,
|
|
||||||
|
|
||||||
once: function once(name, handler) {
|
|
||||||
if (name !== 'beforeExit' && name !== 'exit') {
|
|
||||||
throw new LocalError(`Access denied to listen for '${name}' event.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
let triggered = false;
|
|
||||||
const cb = () => {
|
|
||||||
if (triggered) return;
|
|
||||||
triggered = true;
|
|
||||||
localProcess.removeListener(name, cb);
|
|
||||||
handler();
|
|
||||||
};
|
|
||||||
localReflectApply(localWeakMapSet, LISTENER_HANDLER, [cb, handler]);
|
|
||||||
|
|
||||||
localProcess.on(name, cb);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
|
|
||||||
listeners: function listeners(name) {
|
|
||||||
if (name !== 'beforeExit' && name !== 'exit') {
|
|
||||||
// Maybe add ({__proto__:null})[name] to throw when name fails in https://tc39.es/ecma262/#sec-topropertykey.
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter out listeners, which were not created in this sandbox
|
|
||||||
const all = localProcess.listeners(name);
|
|
||||||
const filtered = [];
|
|
||||||
let j = 0;
|
|
||||||
for (let i = 0; i < all.length; i++) {
|
|
||||||
const h = localReflectApply(localWeakMapGet, LISTENER_HANDLER, [all[i]]);
|
|
||||||
if (h) {
|
|
||||||
if (!localReflectDefineProperty(filtered, j, {
|
|
||||||
__proto__: null,
|
|
||||||
value: h,
|
|
||||||
writable: true,
|
|
||||||
enumerable: true,
|
|
||||||
configurable: true
|
|
||||||
})) throw new LocalError('Unexpected');
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return filtered;
|
|
||||||
},
|
|
||||||
|
|
||||||
removeListener: function removeListener(name, handler) {
|
|
||||||
if (name !== 'beforeExit' && name !== 'exit') {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cb = localReflectApply(localWeakMapGet, LISTENERS, [handler]);
|
|
||||||
if (cb) localProcess.removeListener(name, cb);
|
|
||||||
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
|
|
||||||
umask: function umask() {
|
|
||||||
if (arguments.length) {
|
|
||||||
throw new LocalError('Access denied to set umask.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return localProcess.umask();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (optionConsole === 'inherit') {
|
|
||||||
global.console = host.console;
|
|
||||||
} else if (optionConsole === 'redirect') {
|
|
||||||
global.console = {
|
|
||||||
debug(...args) {
|
|
||||||
vmEmitArgs('console.debug', args);
|
|
||||||
},
|
|
||||||
log(...args) {
|
|
||||||
vmEmitArgs('console.log', args);
|
|
||||||
},
|
|
||||||
info(...args) {
|
|
||||||
vmEmitArgs('console.info', args);
|
|
||||||
},
|
|
||||||
warn(...args) {
|
|
||||||
vmEmitArgs('console.warn', args);
|
|
||||||
},
|
|
||||||
error(...args) {
|
|
||||||
vmEmitArgs('console.error', args);
|
|
||||||
},
|
|
||||||
dir(...args) {
|
|
||||||
vmEmitArgs('console.dir', args);
|
|
||||||
},
|
|
||||||
time() {},
|
|
||||||
timeEnd() {},
|
|
||||||
trace(...args) {
|
|
||||||
vmEmitArgs('console.trace', args);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
__proto__: null,
|
|
||||||
Module,
|
|
||||||
jsonParse: JSON.parse,
|
|
||||||
createRequireForModule,
|
|
||||||
requireImpl
|
|
||||||
};
|
|
||||||
453
dist/setup-sandbox.js
vendored
453
dist/setup-sandbox.js
vendored
|
|
@ -1,453 +0,0 @@
|
||||||
/* global host, bridge, data, context */
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const {
|
|
||||||
Object: localObject,
|
|
||||||
Array: localArray,
|
|
||||||
Error: LocalError,
|
|
||||||
Reflect: localReflect,
|
|
||||||
Proxy: LocalProxy,
|
|
||||||
WeakMap: LocalWeakMap,
|
|
||||||
Function: localFunction,
|
|
||||||
Promise: localPromise,
|
|
||||||
eval: localEval
|
|
||||||
} = global;
|
|
||||||
|
|
||||||
const {
|
|
||||||
freeze: localObjectFreeze
|
|
||||||
} = localObject;
|
|
||||||
|
|
||||||
const {
|
|
||||||
getPrototypeOf: localReflectGetPrototypeOf,
|
|
||||||
apply: localReflectApply,
|
|
||||||
deleteProperty: localReflectDeleteProperty,
|
|
||||||
has: localReflectHas,
|
|
||||||
defineProperty: localReflectDefineProperty,
|
|
||||||
setPrototypeOf: localReflectSetPrototypeOf,
|
|
||||||
getOwnPropertyDescriptor: localReflectGetOwnPropertyDescriptor
|
|
||||||
} = localReflect;
|
|
||||||
|
|
||||||
const {
|
|
||||||
isArray: localArrayIsArray
|
|
||||||
} = localArray;
|
|
||||||
|
|
||||||
const {
|
|
||||||
ensureThis,
|
|
||||||
ReadOnlyHandler,
|
|
||||||
from,
|
|
||||||
fromWithFactory,
|
|
||||||
readonlyFactory,
|
|
||||||
connect,
|
|
||||||
addProtoMapping,
|
|
||||||
VMError,
|
|
||||||
ReadOnlyMockHandler
|
|
||||||
} = bridge;
|
|
||||||
|
|
||||||
const {
|
|
||||||
allowAsync,
|
|
||||||
GeneratorFunction,
|
|
||||||
AsyncFunction,
|
|
||||||
AsyncGeneratorFunction
|
|
||||||
} = data;
|
|
||||||
|
|
||||||
const localWeakMapGet = LocalWeakMap.prototype.get;
|
|
||||||
|
|
||||||
function localUnexpected() {
|
|
||||||
return new VMError('Should not happen');
|
|
||||||
}
|
|
||||||
|
|
||||||
// global is originally prototype of host.Object so it can be used to climb up from the sandbox.
|
|
||||||
if (!localReflectSetPrototypeOf(context, localObject.prototype)) throw localUnexpected();
|
|
||||||
|
|
||||||
Object.defineProperties(global, {
|
|
||||||
global: {value: global, writable: true, configurable: true, enumerable: true},
|
|
||||||
globalThis: {value: global, writable: true, configurable: true},
|
|
||||||
GLOBAL: {value: global, writable: true, configurable: true},
|
|
||||||
root: {value: global, writable: true, configurable: true}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!localReflectDefineProperty(global, 'VMError', {
|
|
||||||
__proto__: null,
|
|
||||||
value: VMError,
|
|
||||||
writable: true,
|
|
||||||
enumerable: false,
|
|
||||||
configurable: true
|
|
||||||
})) throw localUnexpected();
|
|
||||||
|
|
||||||
// Fixes buffer unsafe allocation
|
|
||||||
/* eslint-disable no-use-before-define */
|
|
||||||
class BufferHandler extends ReadOnlyHandler {
|
|
||||||
|
|
||||||
apply(target, thiz, args) {
|
|
||||||
if (args.length > 0 && typeof args[0] === 'number') {
|
|
||||||
return LocalBuffer.alloc(args[0]);
|
|
||||||
}
|
|
||||||
return localReflectApply(LocalBuffer.from, LocalBuffer, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
construct(target, args, newTarget) {
|
|
||||||
if (args.length > 0 && typeof args[0] === 'number') {
|
|
||||||
return LocalBuffer.alloc(args[0]);
|
|
||||||
}
|
|
||||||
return localReflectApply(LocalBuffer.from, LocalBuffer, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
/* eslint-enable no-use-before-define */
|
|
||||||
|
|
||||||
const LocalBuffer = fromWithFactory(obj => new BufferHandler(obj), host.Buffer);
|
|
||||||
|
|
||||||
|
|
||||||
if (!localReflectDefineProperty(global, 'Buffer', {
|
|
||||||
__proto__: null,
|
|
||||||
value: LocalBuffer,
|
|
||||||
writable: true,
|
|
||||||
enumerable: false,
|
|
||||||
configurable: true
|
|
||||||
})) throw localUnexpected();
|
|
||||||
|
|
||||||
addProtoMapping(LocalBuffer.prototype, host.Buffer.prototype, 'Uint8Array');
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {*} size Size of new buffer
|
|
||||||
* @this LocalBuffer
|
|
||||||
* @return {LocalBuffer}
|
|
||||||
*/
|
|
||||||
function allocUnsafe(size) {
|
|
||||||
return LocalBuffer.alloc(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(allocUnsafe, host.Buffer.allocUnsafe);
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {*} size Size of new buffer
|
|
||||||
* @this LocalBuffer
|
|
||||||
* @return {LocalBuffer}
|
|
||||||
*/
|
|
||||||
function allocUnsafeSlow(size) {
|
|
||||||
return LocalBuffer.alloc(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(allocUnsafeSlow, host.Buffer.allocUnsafeSlow);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replacement for Buffer inspect
|
|
||||||
*
|
|
||||||
* @param {*} recurseTimes
|
|
||||||
* @param {*} ctx
|
|
||||||
* @this LocalBuffer
|
|
||||||
* @return {string}
|
|
||||||
*/
|
|
||||||
function inspect(recurseTimes, ctx) {
|
|
||||||
// Mimic old behavior, could throw but didn't pass a test.
|
|
||||||
const max = host.INSPECT_MAX_BYTES;
|
|
||||||
const actualMax = Math.min(max, this.length);
|
|
||||||
const remaining = this.length - max;
|
|
||||||
let str = this.hexSlice(0, actualMax).replace(/(.{2})/g, '$1 ').trim();
|
|
||||||
if (remaining > 0) str += ` ... ${remaining} more byte${remaining > 1 ? 's' : ''}`;
|
|
||||||
return `<${this.constructor.name} ${str}>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(inspect, host.Buffer.prototype.inspect);
|
|
||||||
|
|
||||||
connect(localFunction.prototype.bind, host.Function.prototype.bind);
|
|
||||||
|
|
||||||
connect(localObject.prototype.__defineGetter__, host.Object.prototype.__defineGetter__);
|
|
||||||
connect(localObject.prototype.__defineSetter__, host.Object.prototype.__defineSetter__);
|
|
||||||
connect(localObject.prototype.__lookupGetter__, host.Object.prototype.__lookupGetter__);
|
|
||||||
connect(localObject.prototype.__lookupSetter__, host.Object.prototype.__lookupSetter__);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* PrepareStackTrace sanitization
|
|
||||||
*/
|
|
||||||
|
|
||||||
const oldPrepareStackTraceDesc = localReflectGetOwnPropertyDescriptor(LocalError, 'prepareStackTrace');
|
|
||||||
|
|
||||||
let currentPrepareStackTrace = LocalError.prepareStackTrace;
|
|
||||||
const wrappedPrepareStackTrace = new LocalWeakMap();
|
|
||||||
if (typeof currentPrepareStackTrace === 'function') {
|
|
||||||
wrappedPrepareStackTrace.set(currentPrepareStackTrace, currentPrepareStackTrace);
|
|
||||||
}
|
|
||||||
|
|
||||||
let OriginalCallSite;
|
|
||||||
LocalError.prepareStackTrace = (e, sst) => {
|
|
||||||
OriginalCallSite = sst[0].constructor;
|
|
||||||
};
|
|
||||||
new LocalError().stack;
|
|
||||||
if (typeof OriginalCallSite === 'function') {
|
|
||||||
LocalError.prepareStackTrace = undefined;
|
|
||||||
|
|
||||||
function makeCallSiteGetters(list) {
|
|
||||||
const callSiteGetters = [];
|
|
||||||
for (let i=0; i<list.length; i++) {
|
|
||||||
const name = list[i];
|
|
||||||
const func = OriginalCallSite.prototype[name];
|
|
||||||
callSiteGetters[i] = {__proto__: null,
|
|
||||||
name,
|
|
||||||
propName: '_' + name,
|
|
||||||
func: (thiz) => {
|
|
||||||
return localReflectApply(func, thiz, []);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return callSiteGetters;
|
|
||||||
}
|
|
||||||
|
|
||||||
function applyCallSiteGetters(thiz, callSite, getters) {
|
|
||||||
for (let i=0; i<getters.length; i++) {
|
|
||||||
const getter = getters[i];
|
|
||||||
localReflectDefineProperty(thiz, getter.propName, {
|
|
||||||
__proto__: null,
|
|
||||||
value: getter.func(callSite)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const callSiteGetters = makeCallSiteGetters([
|
|
||||||
'getTypeName',
|
|
||||||
'getFunctionName',
|
|
||||||
'getMethodName',
|
|
||||||
'getFileName',
|
|
||||||
'getLineNumber',
|
|
||||||
'getColumnNumber',
|
|
||||||
'getEvalOrigin',
|
|
||||||
'isToplevel',
|
|
||||||
'isEval',
|
|
||||||
'isNative',
|
|
||||||
'isConstructor',
|
|
||||||
'isAsync',
|
|
||||||
'isPromiseAll',
|
|
||||||
'getPromiseIndex'
|
|
||||||
]);
|
|
||||||
|
|
||||||
class CallSite {
|
|
||||||
constructor(callSite) {
|
|
||||||
applyCallSiteGetters(this, callSite, callSiteGetters);
|
|
||||||
}
|
|
||||||
getThis() {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
getFunction() {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
toString() {
|
|
||||||
return 'CallSite {}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for (let i=0; i<callSiteGetters.length; i++) {
|
|
||||||
const name = callSiteGetters[i].name;
|
|
||||||
const funcProp = localReflectGetOwnPropertyDescriptor(OriginalCallSite.prototype, name);
|
|
||||||
if (!funcProp) continue;
|
|
||||||
const propertyName = callSiteGetters[i].propName;
|
|
||||||
const func = {func() {
|
|
||||||
return this[propertyName];
|
|
||||||
}}.func;
|
|
||||||
const nameProp = localReflectGetOwnPropertyDescriptor(func, 'name');
|
|
||||||
if (!nameProp) throw localUnexpected();
|
|
||||||
nameProp.value = name;
|
|
||||||
if (!localReflectDefineProperty(func, 'name', nameProp)) throw localUnexpected();
|
|
||||||
funcProp.value = func;
|
|
||||||
if (!localReflectDefineProperty(CallSite.prototype, name, funcProp)) throw localUnexpected();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!localReflectDefineProperty(LocalError, 'prepareStackTrace', {
|
|
||||||
configurable: false,
|
|
||||||
enumerable: false,
|
|
||||||
get() {
|
|
||||||
return currentPrepareStackTrace;
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
if (typeof(value) !== 'function') {
|
|
||||||
currentPrepareStackTrace = value;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const wrapped = localReflectApply(localWeakMapGet, wrappedPrepareStackTrace, [value]);
|
|
||||||
if (wrapped) {
|
|
||||||
currentPrepareStackTrace = wrapped;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const newWrapped = (error, sst) => {
|
|
||||||
if (localArrayIsArray(sst)) {
|
|
||||||
for (let i=0; i < sst.length; i++) {
|
|
||||||
const cs = sst[i];
|
|
||||||
if (typeof cs === 'object' && localReflectGetPrototypeOf(cs) === OriginalCallSite.prototype) {
|
|
||||||
sst[i] = new CallSite(cs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return value(error, sst);
|
|
||||||
};
|
|
||||||
wrappedPrepareStackTrace.set(value, newWrapped);
|
|
||||||
wrappedPrepareStackTrace.set(newWrapped, newWrapped);
|
|
||||||
currentPrepareStackTrace = newWrapped;
|
|
||||||
}
|
|
||||||
})) throw localUnexpected();
|
|
||||||
} else if (oldPrepareStackTraceDesc) {
|
|
||||||
localReflectDefineProperty(LocalError, 'prepareStackTrace', oldPrepareStackTraceDesc);
|
|
||||||
} else {
|
|
||||||
localReflectDeleteProperty(LocalError, 'prepareStackTrace');
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Exception sanitization
|
|
||||||
*/
|
|
||||||
|
|
||||||
const withProxy = localObjectFreeze({
|
|
||||||
__proto__: null,
|
|
||||||
has(target, key) {
|
|
||||||
if (key === host.INTERNAL_STATE_NAME) return false;
|
|
||||||
return localReflectHas(target, key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const interanState = localObjectFreeze({
|
|
||||||
__proto__: null,
|
|
||||||
wrapWith(x) {
|
|
||||||
if (x === null || x === undefined) return x;
|
|
||||||
return new LocalProxy(localObject(x), withProxy);
|
|
||||||
},
|
|
||||||
handleException: ensureThis,
|
|
||||||
import(what) {
|
|
||||||
throw new VMError('Dynamic Import not supported');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!localReflectDefineProperty(global, host.INTERNAL_STATE_NAME, {
|
|
||||||
__proto__: null,
|
|
||||||
configurable: false,
|
|
||||||
enumerable: false,
|
|
||||||
writable: false,
|
|
||||||
value: interanState
|
|
||||||
})) throw localUnexpected();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Eval sanitization
|
|
||||||
*/
|
|
||||||
|
|
||||||
function throwAsync() {
|
|
||||||
return new VMError('Async not available');
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeFunction(inputArgs, isAsync, isGenerator) {
|
|
||||||
const lastArgs = inputArgs.length - 1;
|
|
||||||
let code = lastArgs >= 0 ? `${inputArgs[lastArgs]}` : '';
|
|
||||||
let args = lastArgs > 0 ? `${inputArgs[0]}` : '';
|
|
||||||
for (let i = 1; i < lastArgs; i++) {
|
|
||||||
args += `,${inputArgs[i]}`;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
code = host.transformAndCheck(args, code, isAsync, isGenerator, allowAsync);
|
|
||||||
} catch (e) {
|
|
||||||
throw bridge.from(e);
|
|
||||||
}
|
|
||||||
return localEval(code);
|
|
||||||
}
|
|
||||||
|
|
||||||
const FunctionHandler = {
|
|
||||||
__proto__: null,
|
|
||||||
apply(target, thiz, args) {
|
|
||||||
return makeFunction(args, this.isAsync, this.isGenerator);
|
|
||||||
},
|
|
||||||
construct(target, args, newTarget) {
|
|
||||||
return makeFunction(args, this.isAsync, this.isGenerator);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const EvalHandler = {
|
|
||||||
__proto__: null,
|
|
||||||
apply(target, thiz, args) {
|
|
||||||
if (args.length === 0) return undefined;
|
|
||||||
let code = `${args[0]}`;
|
|
||||||
try {
|
|
||||||
code = host.transformAndCheck(null, code, false, false, allowAsync);
|
|
||||||
} catch (e) {
|
|
||||||
throw bridge.from(e);
|
|
||||||
}
|
|
||||||
return localEval(code);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const AsyncErrorHandler = {
|
|
||||||
__proto__: null,
|
|
||||||
apply(target, thiz, args) {
|
|
||||||
throw throwAsync();
|
|
||||||
},
|
|
||||||
construct(target, args, newTarget) {
|
|
||||||
throw throwAsync();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function makeCheckFunction(isAsync, isGenerator) {
|
|
||||||
if (isAsync && !allowAsync) return AsyncErrorHandler;
|
|
||||||
return {
|
|
||||||
__proto__: FunctionHandler,
|
|
||||||
isAsync,
|
|
||||||
isGenerator
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function overrideWithProxy(obj, prop, value, handler) {
|
|
||||||
const proxy = new LocalProxy(value, handler);
|
|
||||||
if (!localReflectDefineProperty(obj, prop, {__proto__: null, value: proxy})) throw localUnexpected();
|
|
||||||
return proxy;
|
|
||||||
}
|
|
||||||
|
|
||||||
const proxiedFunction = overrideWithProxy(localFunction.prototype, 'constructor', localFunction, makeCheckFunction(false, false));
|
|
||||||
if (GeneratorFunction) {
|
|
||||||
if (!localReflectSetPrototypeOf(GeneratorFunction, proxiedFunction)) throw localUnexpected();
|
|
||||||
overrideWithProxy(GeneratorFunction.prototype, 'constructor', GeneratorFunction, makeCheckFunction(false, true));
|
|
||||||
}
|
|
||||||
if (AsyncFunction) {
|
|
||||||
if (!localReflectSetPrototypeOf(AsyncFunction, proxiedFunction)) throw localUnexpected();
|
|
||||||
overrideWithProxy(AsyncFunction.prototype, 'constructor', AsyncFunction, makeCheckFunction(true, false));
|
|
||||||
}
|
|
||||||
if (AsyncGeneratorFunction) {
|
|
||||||
if (!localReflectSetPrototypeOf(AsyncGeneratorFunction, proxiedFunction)) throw localUnexpected();
|
|
||||||
overrideWithProxy(AsyncGeneratorFunction.prototype, 'constructor', AsyncGeneratorFunction, makeCheckFunction(true, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
global.Function = proxiedFunction;
|
|
||||||
global.eval = new LocalProxy(localEval, EvalHandler);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Promise sanitization
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (localPromise && !allowAsync) {
|
|
||||||
|
|
||||||
const PromisePrototype = localPromise.prototype;
|
|
||||||
|
|
||||||
overrideWithProxy(PromisePrototype, 'then', PromisePrototype.then, AsyncErrorHandler);
|
|
||||||
// This seems not to work, and will produce
|
|
||||||
// UnhandledPromiseRejectionWarning: TypeError: Method Promise.prototype.then called on incompatible receiver [object Object].
|
|
||||||
// This is likely caused since the host.Promise.prototype.then cannot use the VM Proxy object.
|
|
||||||
// Contextify.connect(host.Promise.prototype.then, Promise.prototype.then);
|
|
||||||
|
|
||||||
if (PromisePrototype.finally) {
|
|
||||||
overrideWithProxy(PromisePrototype, 'finally', PromisePrototype.finally, AsyncErrorHandler);
|
|
||||||
// Contextify.connect(host.Promise.prototype.finally, Promise.prototype.finally);
|
|
||||||
}
|
|
||||||
if (Promise.prototype.catch) {
|
|
||||||
overrideWithProxy(PromisePrototype, 'catch', PromisePrototype.catch, AsyncErrorHandler);
|
|
||||||
// Contextify.connect(host.Promise.prototype.catch, Promise.prototype.catch);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function readonly(other, mock) {
|
|
||||||
// Note: other@other(unsafe) mock@other(unsafe) returns@this(unsafe) throws@this(unsafe)
|
|
||||||
if (!mock) return fromWithFactory(readonlyFactory, other);
|
|
||||||
const tmock = from(mock);
|
|
||||||
return fromWithFactory(obj=>new ReadOnlyMockHandler(obj, tmock), other);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
__proto__: null,
|
|
||||||
readonly,
|
|
||||||
global
|
|
||||||
};
|
|
||||||
5
index.js
5
index.js
|
|
@ -1,3 +1,8 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
const core = require('@actions/core');
|
const core = require('@actions/core');
|
||||||
|
|
||||||
const setup = require('./lib/setup-terraform');
|
const setup = require('./lib/setup-terraform');
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,13 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
// Node.js core
|
// Node.js core
|
||||||
const fs = require('fs').promises;
|
const fs = require('fs').promises;
|
||||||
const os = require('os');
|
const os = require('os');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const semver = require('semver');
|
||||||
|
|
||||||
// External
|
// External
|
||||||
const core = require('@actions/core');
|
const core = require('@actions/core');
|
||||||
|
|
@ -130,7 +136,15 @@ async function run () {
|
||||||
core.debug(`Finding releases for Terraform version ${version}`);
|
core.debug(`Finding releases for Terraform version ${version}`);
|
||||||
const release = await releases.getRelease('terraform', version, 'GitHub Action: Setup Terraform');
|
const release = await releases.getRelease('terraform', version, 'GitHub Action: Setup Terraform');
|
||||||
const platform = mapOS(osPlatform);
|
const platform = mapOS(osPlatform);
|
||||||
const arch = mapArch(osArch);
|
let arch = mapArch(osArch);
|
||||||
|
|
||||||
|
// Terraform was not available for darwin/arm64 until 1.0.2, however macOS
|
||||||
|
// runners can emulate darwin/amd64.
|
||||||
|
if (platform === 'darwin' && arch === 'arm64' && semver.valid(release.version) && semver.lt(release.version, '1.0.2')) {
|
||||||
|
core.warning('Terraform is not available for darwin/arm64 until version 1.0.2. Falling back to darwin/amd64.');
|
||||||
|
arch = 'amd64';
|
||||||
|
}
|
||||||
|
|
||||||
core.debug(`Getting build for Terraform version ${release.version}: ${platform} ${arch}`);
|
core.debug(`Getting build for Terraform version ${release.version}: ${platform} ${arch}`);
|
||||||
const build = release.getBuild(platform, arch);
|
const build = release.getBuild(platform, arch);
|
||||||
if (!build) {
|
if (!build) {
|
||||||
|
|
|
||||||
10498
package-lock.json
generated
10498
package-lock.json
generated
File diff suppressed because it is too large
Load diff
42
package.json
42
package.json
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "setup-terraform",
|
"name": "setup-terraform",
|
||||||
"version": "2.0.2",
|
"version": "3.1.2",
|
||||||
"description": "Setup Terraform CLI for GitHub Actions",
|
"description": "Setup Terraform CLI for GitHub Actions",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"publisher": "hashicorp",
|
"publisher": "hashicorp",
|
||||||
|
|
@ -10,39 +10,31 @@
|
||||||
"url": "https://github.com/hashicorp/setup-terraform.git"
|
"url": "https://github.com/hashicorp/setup-terraform.git"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "cd wrapper && npm test && cd .. && semistandard --env jest && jest --coverage",
|
"test": "semistandard --env jest && jest --coverage",
|
||||||
"lint": "cd wrapper && npm run lint && cd .. && semistandard --env jest --fix",
|
"lint": "semistandard --env jest --fix",
|
||||||
"build": "cd wrapper && npm run build && cd .. && ncc build index.js --out dist",
|
"build": "ncc build wrapper/terraform.js --out wrapper/dist && ncc build index.js --out dist",
|
||||||
"postinstall": "cd wrapper && npm install",
|
"format-check": "echo \"unimplemented for actions/reusable-workflows basic-validation\""
|
||||||
"prepare": "husky install"
|
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "^1.10.0",
|
"@actions/core": "^1.11.1",
|
||||||
"@actions/github": "^5.1.1",
|
"@actions/exec": "^1.1.1",
|
||||||
"@actions/io": "^1.1.2",
|
"@actions/github": "^6.0.1",
|
||||||
"@actions/tool-cache": "^2.0.1",
|
"@actions/io": "^2.0.0",
|
||||||
"@hashicorp/js-releases": "^1.6.1"
|
"@actions/tool-cache": "^2.0.2",
|
||||||
|
"@hashicorp/js-releases": "^1.7.5",
|
||||||
|
"semver": "^7.7.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vercel/ncc": "0.34.0",
|
"@vercel/ncc": "^0.38.4",
|
||||||
"husky": "^8.0.1",
|
"jest": "^30.2.0",
|
||||||
"jest": "^29.1.2",
|
"nock": "^14.0.10",
|
||||||
"nock": "^13.2.9",
|
"semistandard": "^17.0.0"
|
||||||
"semistandard": "^16.0.1"
|
|
||||||
},
|
|
||||||
"jest": {
|
|
||||||
"testPathIgnorePatterns": [
|
|
||||||
"<rootDir>/dist/",
|
|
||||||
"<rootDir>/node_modules/",
|
|
||||||
"<rootDir>/wrapper/"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"semistandard": {
|
"semistandard": {
|
||||||
"ignore": [
|
"ignore": [
|
||||||
"dist/**",
|
"**/dist/**"
|
||||||
"wrapper/**"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,8 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
// Mock external modules by default
|
// Mock external modules by default
|
||||||
jest.mock('@actions/core');
|
jest.mock('@actions/core');
|
||||||
jest.mock('@actions/tool-cache');
|
jest.mock('@actions/tool-cache');
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,8 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Acts as a listener for @actions/exec, by capturing STDOUT and STDERR
|
* Acts as a listener for @actions/exec, by capturing STDOUT and STDERR
|
||||||
* streams, and exposing them via a contents attribute.
|
* streams, and exposing them via a contents attribute.
|
||||||
|
|
@ -15,13 +20,18 @@
|
||||||
* console.log(listener.contents);
|
* console.log(listener.contents);
|
||||||
*/
|
*/
|
||||||
class OutputListener {
|
class OutputListener {
|
||||||
constructor () {
|
constructor (streamWriter) {
|
||||||
this._buff = [];
|
this._buff = [];
|
||||||
|
this._streamWriter = streamWriter;
|
||||||
}
|
}
|
||||||
|
|
||||||
get listener () {
|
get listener () {
|
||||||
const listen = function listen (data) {
|
const listen = function listen (data) {
|
||||||
this._buff.push(data);
|
this._buff.push(data);
|
||||||
|
|
||||||
|
if (this._streamWriter) {
|
||||||
|
this._streamWriter.write(data);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
return listen.bind(this);
|
return listen.bind(this);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,8 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
const os = require('os');
|
const os = require('os');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
|
|
|
||||||
10352
wrapper/package-lock.json
generated
10352
wrapper/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,29 +0,0 @@
|
||||||
{
|
|
||||||
"name": "terraform.js",
|
|
||||||
"version": "0.0.1",
|
|
||||||
"description": "JavaScript wrapper for terraform binary",
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"publisher": "hashicorp",
|
|
||||||
"main": "terraform.js",
|
|
||||||
"scripts": {
|
|
||||||
"test": "semistandard --env jest && jest --coverage",
|
|
||||||
"lint": "semistandard --env jest --fix",
|
|
||||||
"build": "ncc build terraform.js --out dist"
|
|
||||||
},
|
|
||||||
"author": "",
|
|
||||||
"dependencies": {
|
|
||||||
"@actions/core": "^1.10.0",
|
|
||||||
"@actions/exec": "^1.1.0",
|
|
||||||
"@actions/io": "^1.1.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@vercel/ncc": "0.33.3",
|
|
||||||
"jest": "^27.5.1",
|
|
||||||
"semistandard": "^16.0.1"
|
|
||||||
},
|
|
||||||
"semistandard": {
|
|
||||||
"ignore": [
|
|
||||||
"dist/**"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
const io = require('@actions/io');
|
const io = require('@actions/io');
|
||||||
const core = require('@actions/core');
|
const core = require('@actions/core');
|
||||||
const { exec } = require('@actions/exec');
|
const { exec } = require('@actions/exec');
|
||||||
|
|
@ -16,9 +21,9 @@ async function checkTerraform () {
|
||||||
// This will fail if Terraform isn't found, which is what we want
|
// This will fail if Terraform isn't found, which is what we want
|
||||||
await checkTerraform();
|
await checkTerraform();
|
||||||
|
|
||||||
// Create listeners to receive output (in memory) as well
|
// Create listeners to receive output (in memory)
|
||||||
const stdout = new OutputListener();
|
const stdout = new OutputListener(process.stdout);
|
||||||
const stderr = new OutputListener();
|
const stderr = new OutputListener(process.stderr);
|
||||||
const listeners = {
|
const listeners = {
|
||||||
stdout: stdout.listener,
|
stdout: stdout.listener,
|
||||||
stderr: stderr.listener
|
stderr: stderr.listener
|
||||||
|
|
@ -28,13 +33,10 @@ async function checkTerraform () {
|
||||||
const args = process.argv.slice(2);
|
const args = process.argv.slice(2);
|
||||||
const options = {
|
const options = {
|
||||||
listeners,
|
listeners,
|
||||||
ignoreReturnCode: true
|
ignoreReturnCode: true,
|
||||||
|
silent: true // avoid printing command in stdout: https://github.com/actions/toolkit/issues/649
|
||||||
};
|
};
|
||||||
const exitCode = await exec(pathToCLI, args, options);
|
const exitCode = await exec(pathToCLI, args, options);
|
||||||
core.debug(`Terraform exited with code ${exitCode}.`);
|
|
||||||
core.debug(`stdout: ${stdout.contents}`);
|
|
||||||
core.debug(`stderr: ${stderr.contents}`);
|
|
||||||
core.debug(`exitcode: ${exitCode}`);
|
|
||||||
|
|
||||||
// Set outputs, result, exitcode, and stderr
|
// Set outputs, result, exitcode, and stderr
|
||||||
core.setOutput('stdout', stdout.contents);
|
core.setOutput('stdout', stdout.contents);
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,36 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) HashiCorp, Inc.
|
||||||
|
* SPDX-License-Identifier: MPL-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
const OutputListener = require('../lib/output-listener');
|
const OutputListener = require('../lib/output-listener');
|
||||||
|
|
||||||
describe('output-listener', () => {
|
describe('output-listener', () => {
|
||||||
it('receives and exposes data', () => {
|
it('receives and buffers data to .contents', () => {
|
||||||
const listener = new OutputListener();
|
const listener = new OutputListener();
|
||||||
const listen = listener.listener;
|
const listen = listener.listener;
|
||||||
|
|
||||||
listen(Buffer.from('foo'));
|
listen(Buffer.from('foo'));
|
||||||
listen(Buffer.from('bar'));
|
listen(Buffer.from('bar'));
|
||||||
listen(Buffer.from('baz'));
|
listen(Buffer.from('baz'));
|
||||||
|
|
||||||
expect(listener.contents).toEqual('foobarbaz');
|
expect(listener.contents).toEqual('foobarbaz');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('receives and writes data to stream immediately', () => {
|
||||||
|
const mockWrite = jest.fn();
|
||||||
|
const listener = new OutputListener({ write: mockWrite });
|
||||||
|
const listen = listener.listener;
|
||||||
|
|
||||||
|
listen(Buffer.from('first write'));
|
||||||
|
expect(mockWrite.mock.lastCall[0]).toStrictEqual(Buffer.from('first write'));
|
||||||
|
|
||||||
|
listen(Buffer.from('second write'));
|
||||||
|
expect(mockWrite.mock.lastCall[0]).toStrictEqual(Buffer.from('second write'));
|
||||||
|
|
||||||
|
listen(Buffer.from('third write'));
|
||||||
|
expect(mockWrite.mock.lastCall[0]).toStrictEqual(Buffer.from('third write'));
|
||||||
|
|
||||||
|
expect(mockWrite).toHaveBeenCalledTimes(3);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue