Compare commits

...

12 Commits

Author SHA1 Message Date
Ferenc Hammerl 91d3933eb5 Prepend http:// to http(s)_proxy env if missing (#1439)
* Prepend http:// to http(s)_proxy env if missing

* Formatting

* Fix linting
2023-06-22 11:03:38 +02:00
Francesco Renzi a6bf8726aa Merge pull request #1430 from actions/add-mask-docs
Update docs for setSecret
2023-05-25 11:17:42 +01:00
Francesco Renzi ae9272d5cb Update docs/commands.md
Co-authored-by: JoannaaKL <joannaakl@github.com>
2023-05-25 11:07:37 +01:00
Francesco Renzi f481b8c8dc Update docs for setSecret 2023-05-25 11:00:25 +01:00
Francesco Renzi 59851786d4 Add tests to ensure secrets are escaped 2023-05-25 10:59:41 +01:00
Francesco Renzi 37e09c586f Merge pull request #1429 from actions/rentziass/postman
Use postman-echo to replace httpbin
2023-05-23 13:22:40 +01:00
Francesco Renzi 12c01ac203 Merge pull request #1428 from actions/rentziass/audit-fix
Update actions/cache dependencies to fix vulnerabilities
2023-05-23 13:20:12 +01:00
Francesco Renzi bbab4bec57 Update packages/http-client/__tests__/proxy.test.ts
Co-authored-by: Bassem Dghaidi <568794+Link-@users.noreply.github.com>
2023-05-23 13:10:40 +01:00
Francesco Renzi 672c88ec4b Use postman-echo to replace httpbin 2023-05-23 12:37:39 +01:00
Francesco Renzi a103f5eefe Update actions/cache dependencies to fix vulnerabilities 2023-05-22 14:32:33 +01:00
Vallie Joseph 457303960f toolkit/io 1.1.3 release (#1374)
* updating version

* adding new minor version to package-lock

* updating release doc

* Update packages/io/RELEASES.md

Co-authored-by: Cory Miller <13227161+cory-miller@users.noreply.github.com>

---------

Co-authored-by: Cory Miller <13227161+cory-miller@users.noreply.github.com>
2023-03-15 15:10:56 -04:00
Vallie Joseph 463b49d872 Removing childprocess for rmRF (#1373)
* try awaiting spawn on windows

* formatting

* updating package-lock

* .

* .

* updating packages

* adding sync rm

* test with sync

* pointing to rmsync

* adding error handling

* testing rmsync

* adding try/catch

* adding windows conditional for locked file

* switch to contians

* fixing formatting

* fixing formatting

* fixing formatting

* adding enonet catch for windows files

* adding enonet catch for windows files

* adding catch for file not found

* updating stat call

* updating stat call

* adding conditonal for symlink

* removing symlink test

* adding ebusy check

* changing error check

* changing error check

* changing error check

* changing error check

* cleanup and comments

* Update packages/io/__tests__/io.test.ts

Co-authored-by: Cory Miller <13227161+cory-miller@users.noreply.github.com>

* Update packages/io/src/io-util.ts

Co-authored-by: Cory Miller <13227161+cory-miller@users.noreply.github.com>

* moving comment placement

* updating eperm

* change back to ebusy

* Update packages/io/__tests__/io.test.ts

Co-authored-by: Cory Miller <13227161+cory-miller@users.noreply.github.com>

* Formatting

* converting to async

---------

Co-authored-by: Cory Miller <13227161+cory-miller@users.noreply.github.com>
2023-03-15 14:51:02 -04:00
16 changed files with 261 additions and 314 deletions
+12 -1
View File
@@ -50,7 +50,18 @@ function setSecret(secret: string): void {}
Now, future logs containing BAR will be masked. E.g. running `echo "Hello FOO BAR World"` will now print `Hello FOO **** World`.
**WARNING** The add-mask and setSecret commands only support single line secrets. To register a multiline secrets you must register each line individually otherwise it will not be masked.
**WARNING** The add-mask and setSecret commands only support single-line
secrets or multi-line secrets that have been escaped. `@actions/core`
`setSecret` will escape the string you provide by default. When an escaped
multi-line string is provided the whole string and each of its lines
individually will be masked. For example you can mask `first\nsecond\r\nthird`
using:
```sh
echo "::add-mask::first%0Asecond%0D%0Athird"
```
This will mask `first%0Asecond%0D%0Athird`, `first`, `second` and `third`.
**WARNING** Do **not** mask short values if you can avoid it, it could render your output unreadable (and future steps' output as well).
For example, if you mask the letter `l`, running `echo "Hello FOO BAR World"` will now print `He*********o FOO BAR Wor****d`
+24 -24
View File
@@ -112,9 +112,9 @@
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
},
"node_modules/@azure/core-http": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@azure/core-http/-/core-http-3.0.0.tgz",
"integrity": "sha512-BxI2SlGFPPz6J1XyZNIVUf0QZLBKFX+ViFjKOkzqD18J1zOINIQ8JSBKKr+i+v8+MB6LacL6Nn/sP/TE13+s2Q==",
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@azure/core-http/-/core-http-3.0.1.tgz",
"integrity": "sha512-A3x+um3cAPgQe42Lu7Iv/x8/fNjhL/nIoEfqFxfn30EyxK6zC13n+OUxzZBRC0IzQqssqIbt4INf5YG7lYYFtw==",
"dependencies": {
"@azure/abort-controller": "^1.0.0",
"@azure/core-auth": "^1.3.0",
@@ -129,7 +129,7 @@
"tslib": "^2.2.0",
"tunnel": "^0.0.6",
"uuid": "^8.3.0",
"xml2js": "^0.4.19"
"xml2js": "^0.5.0"
},
"engines": {
"node": ">=14.0.0"
@@ -248,19 +248,19 @@
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
},
"node_modules/@azure/ms-rest-js": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/@azure/ms-rest-js/-/ms-rest-js-2.6.0.tgz",
"integrity": "sha512-4C5FCtvEzWudblB+h92/TYYPiq7tuElX8icVYToxOdggnYqeec4Se14mjse5miInKtZahiFHdl8lZA/jziEc5g==",
"version": "2.6.6",
"resolved": "https://registry.npmjs.org/@azure/ms-rest-js/-/ms-rest-js-2.6.6.tgz",
"integrity": "sha512-WYIda8VvrkZE68xHgOxUXvjThxNf1nnGPPe0rAljqK5HJHIZ12Pi3YhEDOn3Ge7UnwaaM3eFO0VtAy4nGVI27Q==",
"dependencies": {
"@azure/core-auth": "^1.1.4",
"abort-controller": "^3.0.0",
"form-data": "^2.5.0",
"node-fetch": "^2.6.0",
"node-fetch": "^2.6.7",
"tough-cookie": "^3.0.1",
"tslib": "^1.10.0",
"tunnel": "0.0.6",
"uuid": "^8.3.2",
"xml2js": "^0.4.19"
"xml2js": "^0.5.0"
}
},
"node_modules/@azure/ms-rest-js/node_modules/uuid": {
@@ -591,9 +591,9 @@
}
},
"node_modules/xml2js": {
"version": "0.4.23",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
"integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz",
"integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==",
"dependencies": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
@@ -695,9 +695,9 @@
}
},
"@azure/core-http": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@azure/core-http/-/core-http-3.0.0.tgz",
"integrity": "sha512-BxI2SlGFPPz6J1XyZNIVUf0QZLBKFX+ViFjKOkzqD18J1zOINIQ8JSBKKr+i+v8+MB6LacL6Nn/sP/TE13+s2Q==",
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@azure/core-http/-/core-http-3.0.1.tgz",
"integrity": "sha512-A3x+um3cAPgQe42Lu7Iv/x8/fNjhL/nIoEfqFxfn30EyxK6zC13n+OUxzZBRC0IzQqssqIbt4INf5YG7lYYFtw==",
"requires": {
"@azure/abort-controller": "^1.0.0",
"@azure/core-auth": "^1.3.0",
@@ -712,7 +712,7 @@
"tslib": "^2.2.0",
"tunnel": "^0.0.6",
"uuid": "^8.3.0",
"xml2js": "^0.4.19"
"xml2js": "^0.5.0"
},
"dependencies": {
"form-data": {
@@ -819,19 +819,19 @@
}
},
"@azure/ms-rest-js": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/@azure/ms-rest-js/-/ms-rest-js-2.6.0.tgz",
"integrity": "sha512-4C5FCtvEzWudblB+h92/TYYPiq7tuElX8icVYToxOdggnYqeec4Se14mjse5miInKtZahiFHdl8lZA/jziEc5g==",
"version": "2.6.6",
"resolved": "https://registry.npmjs.org/@azure/ms-rest-js/-/ms-rest-js-2.6.6.tgz",
"integrity": "sha512-WYIda8VvrkZE68xHgOxUXvjThxNf1nnGPPe0rAljqK5HJHIZ12Pi3YhEDOn3Ge7UnwaaM3eFO0VtAy4nGVI27Q==",
"requires": {
"@azure/core-auth": "^1.1.4",
"abort-controller": "^3.0.0",
"form-data": "^2.5.0",
"node-fetch": "^2.6.0",
"node-fetch": "^2.6.7",
"tough-cookie": "^3.0.1",
"tslib": "^1.10.0",
"tunnel": "0.0.6",
"uuid": "^8.3.2",
"xml2js": "^0.4.19"
"xml2js": "^0.5.0"
},
"dependencies": {
"uuid": {
@@ -1089,9 +1089,9 @@
}
},
"xml2js": {
"version": "0.4.23",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
"integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz",
"integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==",
"requires": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
+5 -1
View File
@@ -161,7 +161,11 @@ describe('@actions/core', () => {
it('setSecret produces the correct command', () => {
core.setSecret('secret val')
assertWriteCalls([`::add-mask::secret val${os.EOL}`])
core.setSecret('multi\nline\r\nsecret')
assertWriteCalls([
`::add-mask::secret val${os.EOL}`,
`::add-mask::multi%0Aline%0D%0Asecret${os.EOL}`
])
})
it('prependPath produces the correct commands and sets the env', () => {
+42 -88
View File
@@ -1,12 +1,27 @@
{
"name": "@actions/glob",
"version": "0.4.0",
"lockfileVersion": 2,
"lockfileVersion": 3,
"requires": true,
"description": "Actions glob lib",
"files": [
"lib",
"!.DS_Store"
],
"homepage": "https://github.com/actions/toolkit/tree/main/packages/glob",
"keywords": [
"github",
"actions",
"glob"
],
"license": "MIT",
"main": "lib/glob.js",
"preview": true,
"types": "lib/glob.d.ts",
"packages": {
"": {
"name": "@actions/glob",
"version": "0.3.0",
"version": "0.4.0",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.9.1",
@@ -14,26 +29,17 @@
}
},
"node_modules/@actions/core": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz",
"integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==",
"version": "1.10.0",
"integrity": "sha512-2aZDDa3zrrZbP5ZYg159sNoLRb61nQ7awl5pSvIq5Qpj81vwDzdMRKzkWJGJuwVvWpvZKx7vspJALyvaaIQyug==",
"dependencies": {
"@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"
}
},
"node_modules/@actions/http-client": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"dependencies": {
"tunnel": "^0.0.6"
}
},
"node_modules/balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
"node_modules/brace-expansion": {
"version": "1.1.11",
@@ -47,7 +53,7 @@
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
},
"node_modules/minimatch": {
"version": "3.1.2",
@@ -59,78 +65,26 @@
"engines": {
"node": "*"
}
},
"node_modules/tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
"engines": {
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
}
},
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"bin": {
"uuid": "dist/bin/uuid"
}
}
},
"dependencies": {
"@actions/core": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz",
"integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==",
"requires": {
"@actions/http-client": "^2.0.1",
"uuid": "^8.3.2"
}
},
"@actions/http-client": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
"integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
"requires": {
"tunnel": "^0.0.6"
}
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
},
"uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
}
"bugs": {
"url": "https://github.com/actions/toolkit/issues"
},
"directories": {
"lib": "lib",
"test": "__tests__"
},
"publishConfig": {
"access": "public"
},
"repository": {
"directory": "packages/glob",
"type": "git",
"url": "git+https://github.com/actions/toolkit.git"
},
"scripts": {
"audit-moderate": "npm install && npm audit --json --audit-level=moderate > audit.json",
"test": "echo \"Error: run tests from root\" && exit 1",
"tsc": "tsc"
}
}
+9 -9
View File
@@ -15,18 +15,18 @@ describe('auth', () => {
bh
])
const res: httpm.HttpClientResponse = await http.get(
'http://httpbin.org/get'
'http://postman-echo.com/get'
)
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
const obj = JSON.parse(body)
const auth: string = obj.headers.Authorization
const auth: string = obj.headers.authorization
const creds: string = Buffer.from(
auth.substring('Basic '.length),
'base64'
).toString()
expect(creds).toBe('johndoe:password')
expect(obj.url).toBe('http://httpbin.org/get')
expect(obj.url).toBe('http://postman-echo.com/get')
})
it('does basic http get request with pat token auth', async () => {
@@ -39,18 +39,18 @@ describe('auth', () => {
ph
])
const res: httpm.HttpClientResponse = await http.get(
'http://httpbin.org/get'
'http://postman-echo.com/get'
)
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
const obj = JSON.parse(body)
const auth: string = obj.headers.Authorization
const auth: string = obj.headers.authorization
const creds: string = Buffer.from(
auth.substring('Basic '.length),
'base64'
).toString()
expect(creds).toBe(`PAT:${token}`)
expect(obj.url).toBe('http://httpbin.org/get')
expect(obj.url).toBe('http://postman-echo.com/get')
})
it('does basic http get request with pat token auth', async () => {
@@ -61,13 +61,13 @@ describe('auth', () => {
ph
])
const res: httpm.HttpClientResponse = await http.get(
'http://httpbin.org/get'
'http://postman-echo.com/get'
)
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
const obj = JSON.parse(body)
const auth: string = obj.headers.Authorization
const auth: string = obj.headers.authorization
expect(auth).toBe(`Bearer ${token}`)
expect(obj.url).toBe('http://httpbin.org/get')
expect(obj.url).toBe('http://postman-echo.com/get')
})
})
+69 -67
View File
@@ -33,44 +33,44 @@ describe('basics', () => {
// "args": {},
// "headers": {
// "Connection": "close",
// "Host": "httpbin.org",
// "User-Agent": "typed-test-client-tests"
// "Host": "postman-echo.com",
// "user-agent": "typed-test-client-tests"
// },
// "origin": "173.95.152.44",
// "url": "https://httpbin.org/get"
// "url": "https://postman-echo.com/get"
// }
it('does basic http get request', async () => {
const res: httpm.HttpClientResponse = await _http.get(
'http://httpbin.org/get'
'http://postman-echo.com/get'
)
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
const obj = JSON.parse(body)
expect(obj.url).toBe('http://httpbin.org/get')
expect(obj.headers['User-Agent']).toBeTruthy()
expect(obj.url).toBe('http://postman-echo.com/get')
expect(obj.headers['user-agent']).toBeTruthy()
})
it('does basic http get request with no user agent', async () => {
const http: httpm.HttpClient = new httpm.HttpClient()
const res: httpm.HttpClientResponse = await http.get(
'http://httpbin.org/get'
'http://postman-echo.com/get'
)
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
const obj = JSON.parse(body)
expect(obj.url).toBe('http://httpbin.org/get')
expect(obj.headers['User-Agent']).toBeFalsy()
expect(obj.url).toBe('http://postman-echo.com/get')
expect(obj.headers['user-agent']).toBeFalsy()
})
it('does basic https get request', async () => {
const res: httpm.HttpClientResponse = await _http.get(
'https://httpbin.org/get'
'https://postman-echo.com/get'
)
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
const obj = JSON.parse(body)
expect(obj.url).toBe('https://httpbin.org/get')
expect(obj.url).toBe('https://postman-echo.com/get')
})
it('does basic http get request with default headers', async () => {
@@ -85,14 +85,14 @@ describe('basics', () => {
}
)
const res: httpm.HttpClientResponse = await http.get(
'http://httpbin.org/get'
'http://postman-echo.com/get'
)
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
const obj = JSON.parse(body)
expect(obj.headers.Accept).toBe('application/json')
expect(obj.headers['Content-Type']).toBe('application/json')
expect(obj.url).toBe('http://httpbin.org/get')
expect(obj.headers.accept).toBe('application/json')
expect(obj.headers['content-type']).toBe('application/json')
expect(obj.url).toBe('http://postman-echo.com/get')
})
it('does basic http get request with merged headers', async () => {
@@ -107,7 +107,7 @@ describe('basics', () => {
}
)
const res: httpm.HttpClientResponse = await http.get(
'http://httpbin.org/get',
'http://postman-echo.com/get',
{
'content-type': 'application/x-www-form-urlencoded'
}
@@ -115,22 +115,22 @@ describe('basics', () => {
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
const obj = JSON.parse(body)
expect(obj.headers.Accept).toBe('application/json')
expect(obj.headers['Content-Type']).toBe(
expect(obj.headers.accept).toBe('application/json')
expect(obj.headers['content-type']).toBe(
'application/x-www-form-urlencoded'
)
expect(obj.url).toBe('http://httpbin.org/get')
expect(obj.url).toBe('http://postman-echo.com/get')
})
it('pipes a get request', async () => {
return new Promise<void>(async resolve => {
const file = fs.createWriteStream(sampleFilePath)
;(await _http.get('https://httpbin.org/get')).message
;(await _http.get('https://postman-echo.com/get')).message
.pipe(file)
.on('close', () => {
const body: string = fs.readFileSync(sampleFilePath).toString()
const obj = JSON.parse(body)
expect(obj.url).toBe('https://httpbin.org/get')
expect(obj.url).toBe('https://postman-echo.com/get')
resolve()
})
})
@@ -138,32 +138,32 @@ describe('basics', () => {
it('does basic get request with redirects', async () => {
const res: httpm.HttpClientResponse = await _http.get(
`https://httpbin.org/redirect-to?url=${encodeURIComponent(
'https://httpbin.org/get'
`https://postman-echo.com/redirect-to?url=${encodeURIComponent(
'https://postman-echo.com/get'
)}`
)
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
const obj = JSON.parse(body)
expect(obj.url).toBe('https://httpbin.org/get')
expect(obj.url).toBe('https://postman-echo.com/get')
})
it('does basic get request with redirects (303)', async () => {
const res: httpm.HttpClientResponse = await _http.get(
`https://httpbin.org/redirect-to?url=${encodeURIComponent(
'https://httpbin.org/get'
`https://postman-echo.com/redirect-to?url=${encodeURIComponent(
'https://postman-echo.com/get'
)}&status_code=303`
)
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
const obj = JSON.parse(body)
expect(obj.url).toBe('https://httpbin.org/get')
expect(obj.url).toBe('https://postman-echo.com/get')
})
it('returns 404 for not found get request on redirect', async () => {
const res: httpm.HttpClientResponse = await _http.get(
`https://httpbin.org/redirect-to?url=${encodeURIComponent(
'https://httpbin.org/status/404'
`https://postman-echo.com/redirect-to?url=${encodeURIComponent(
'https://postman-echo.com/status/404'
)}&status_code=303`
)
expect(res.message.statusCode).toBe(404)
@@ -177,8 +177,8 @@ describe('basics', () => {
{allowRedirects: false}
)
const res: httpm.HttpClientResponse = await http.get(
`https://httpbin.org/redirect-to?url=${encodeURIComponent(
'https://httpbin.org/get'
`https://postman-echo.com/redirect-to?url=${encodeURIComponent(
'https://postman-echo.com/get'
)}`
)
expect(res.message.statusCode).toBe(302)
@@ -191,8 +191,8 @@ describe('basics', () => {
authorization: 'shhh'
}
const res: httpm.HttpClientResponse = await _http.get(
`https://httpbin.org/redirect-to?url=${encodeURIComponent(
'https://www.httpbin.org/get'
`https://postman-echo.com/redirect-to?url=${encodeURIComponent(
'https://www.postman-echo.com/get'
)}`,
headers
)
@@ -201,10 +201,10 @@ describe('basics', () => {
const body: string = await res.readBody()
const obj = JSON.parse(body)
// httpbin "fixes" the casing
expect(obj.headers['Accept']).toBe('application/json')
expect(obj.headers[httpm.Headers.Accept]).toBe('application/json')
expect(obj.headers['Authorization']).toBeUndefined()
expect(obj.headers['authorization']).toBeUndefined()
expect(obj.url).toBe('https://www.httpbin.org/get')
expect(obj.url).toBe('https://www.postman-echo.com/get')
})
it('does not pass Auth with diff hostname redirects', async () => {
@@ -213,8 +213,8 @@ describe('basics', () => {
Authorization: 'shhh'
}
const res: httpm.HttpClientResponse = await _http.get(
`https://httpbin.org/redirect-to?url=${encodeURIComponent(
'https://www.httpbin.org/get'
`https://postman-echo.com/redirect-to?url=${encodeURIComponent(
'https://www.postman-echo.com/get'
)}`,
headers
)
@@ -223,22 +223,22 @@ describe('basics', () => {
const body: string = await res.readBody()
const obj = JSON.parse(body)
// httpbin "fixes" the casing
expect(obj.headers['Accept']).toBe('application/json')
expect(obj.headers[httpm.Headers.Accept]).toBe('application/json')
expect(obj.headers['Authorization']).toBeUndefined()
expect(obj.headers['authorization']).toBeUndefined()
expect(obj.url).toBe('https://www.httpbin.org/get')
expect(obj.url).toBe('https://www.postman-echo.com/get')
})
it('does basic head request', async () => {
const res: httpm.HttpClientResponse = await _http.head(
'http://httpbin.org/get'
'http://postman-echo.com/get'
)
expect(res.message.statusCode).toBe(200)
})
it('does basic http delete request', async () => {
const res: httpm.HttpClientResponse = await _http.del(
'http://httpbin.org/delete'
'http://postman-echo.com/delete'
)
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
@@ -248,32 +248,32 @@ describe('basics', () => {
it('does basic http post request', async () => {
const b = 'Hello World!'
const res: httpm.HttpClientResponse = await _http.post(
'http://httpbin.org/post',
'http://postman-echo.com/post',
b
)
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
const obj = JSON.parse(body)
expect(obj.data).toBe(b)
expect(obj.url).toBe('http://httpbin.org/post')
expect(obj.url).toBe('http://postman-echo.com/post')
})
it('does basic http patch request', async () => {
const b = 'Hello World!'
const res: httpm.HttpClientResponse = await _http.patch(
'http://httpbin.org/patch',
'http://postman-echo.com/patch',
b
)
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
const obj = JSON.parse(body)
expect(obj.data).toBe(b)
expect(obj.url).toBe('http://httpbin.org/patch')
expect(obj.url).toBe('http://postman-echo.com/patch')
})
it('does basic http options request', async () => {
const res: httpm.HttpClientResponse = await _http.options(
'http://httpbin.org'
'http://postman-echo.com'
)
expect(res.message.statusCode).toBe(200)
await res.readBody()
@@ -281,28 +281,30 @@ describe('basics', () => {
it('returns 404 for not found get request', async () => {
const res: httpm.HttpClientResponse = await _http.get(
'http://httpbin.org/status/404'
'http://postman-echo.com/status/404'
)
expect(res.message.statusCode).toBe(404)
await res.readBody()
})
it('gets a json object', async () => {
const jsonObj = await _http.getJson<HttpBinData>('https://httpbin.org/get')
const jsonObj = await _http.getJson<HttpBinData>(
'https://postman-echo.com/get'
)
expect(jsonObj.statusCode).toBe(200)
expect(jsonObj.result).toBeDefined()
expect(jsonObj.result?.url).toBe('https://httpbin.org/get')
expect(jsonObj.result?.headers['Accept']).toBe(
expect(jsonObj.result?.url).toBe('https://postman-echo.com/get')
expect(jsonObj.result?.headers[httpm.Headers.Accept]).toBe(
httpm.MediaTypes.ApplicationJson
)
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(
expect(jsonObj.headers['content-type']).toContain(
httpm.MediaTypes.ApplicationJson
)
})
it('getting a non existent json object returns null', async () => {
const jsonObj = await _http.getJson<HttpBinData>(
'https://httpbin.org/status/404'
'https://postman-echo.com/status/404'
)
expect(jsonObj.statusCode).toBe(404)
expect(jsonObj.result).toBeNull()
@@ -311,20 +313,20 @@ describe('basics', () => {
it('posts a json object', async () => {
const res = {name: 'foo'}
const restRes = await _http.postJson<HttpBinData>(
'https://httpbin.org/post',
'https://postman-echo.com/post',
res
)
expect(restRes.statusCode).toBe(200)
expect(restRes.result).toBeDefined()
expect(restRes.result?.url).toBe('https://httpbin.org/post')
expect(restRes.result?.url).toBe('https://postman-echo.com/post')
expect(restRes.result?.json.name).toBe('foo')
expect(restRes.result?.headers['Accept']).toBe(
expect(restRes.result?.headers[httpm.Headers.Accept]).toBe(
httpm.MediaTypes.ApplicationJson
)
expect(restRes.result?.headers['Content-Type']).toBe(
expect(restRes.result?.headers['content-type']).toBe(
httpm.MediaTypes.ApplicationJson
)
expect(restRes.headers[httpm.Headers.ContentType]).toBe(
expect(restRes.headers['content-type']).toContain(
httpm.MediaTypes.ApplicationJson
)
})
@@ -332,21 +334,21 @@ describe('basics', () => {
it('puts a json object', async () => {
const res = {name: 'foo'}
const restRes = await _http.putJson<HttpBinData>(
'https://httpbin.org/put',
'https://postman-echo.com/put',
res
)
expect(restRes.statusCode).toBe(200)
expect(restRes.result).toBeDefined()
expect(restRes.result?.url).toBe('https://httpbin.org/put')
expect(restRes.result?.url).toBe('https://postman-echo.com/put')
expect(restRes.result?.json.name).toBe('foo')
expect(restRes.result?.headers['Accept']).toBe(
expect(restRes.result?.headers[httpm.Headers.Accept]).toBe(
httpm.MediaTypes.ApplicationJson
)
expect(restRes.result?.headers['Content-Type']).toBe(
expect(restRes.result?.headers['content-type']).toBe(
httpm.MediaTypes.ApplicationJson
)
expect(restRes.headers[httpm.Headers.ContentType]).toBe(
expect(restRes.headers['content-type']).toContain(
httpm.MediaTypes.ApplicationJson
)
})
@@ -354,20 +356,20 @@ describe('basics', () => {
it('patch a json object', async () => {
const res = {name: 'foo'}
const restRes = await _http.patchJson<HttpBinData>(
'https://httpbin.org/patch',
'https://postman-echo.com/patch',
res
)
expect(restRes.statusCode).toBe(200)
expect(restRes.result).toBeDefined()
expect(restRes.result?.url).toBe('https://httpbin.org/patch')
expect(restRes.result?.url).toBe('https://postman-echo.com/patch')
expect(restRes.result?.json.name).toBe('foo')
expect(restRes.result?.headers['Accept']).toBe(
expect(restRes.result?.headers[httpm.Headers.Accept]).toBe(
httpm.MediaTypes.ApplicationJson
)
expect(restRes.result?.headers['Content-Type']).toBe(
expect(restRes.result?.headers['content-type']).toBe(
httpm.MediaTypes.ApplicationJson
)
expect(restRes.headers[httpm.Headers.ContentType]).toBe(
expect(restRes.headers['content-type']).toContain(
httpm.MediaTypes.ApplicationJson
)
})
+27 -24
View File
@@ -12,11 +12,11 @@ describe('headers', () => {
it('preserves existing headers on getJson', async () => {
const additionalHeaders = {[httpm.Headers.Accept]: 'foo'}
let jsonObj = await _http.getJson<any>(
'https://httpbin.org/get',
'https://postman-echo.com/get',
additionalHeaders
)
expect(jsonObj.result.headers['Accept']).toBe('foo')
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(
expect(jsonObj.result.headers[httpm.Headers.Accept]).toBe('foo')
expect(jsonObj.headers[httpm.Headers.ContentType]).toContain(
httpm.MediaTypes.ApplicationJson
)
@@ -26,9 +26,9 @@ describe('headers', () => {
[httpm.Headers.Accept]: 'baz'
}
}
jsonObj = await httpWithHeaders.getJson<any>('https://httpbin.org/get')
expect(jsonObj.result.headers['Accept']).toBe('baz')
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(
jsonObj = await httpWithHeaders.getJson<any>('https://postman-echo.com/get')
expect(jsonObj.result.headers[httpm.Headers.Accept]).toBe('baz')
expect(jsonObj.headers[httpm.Headers.ContentType]).toContain(
httpm.MediaTypes.ApplicationJson
)
})
@@ -36,12 +36,12 @@ describe('headers', () => {
it('preserves existing headers on postJson', async () => {
const additionalHeaders = {[httpm.Headers.Accept]: 'foo'}
let jsonObj = await _http.postJson<any>(
'https://httpbin.org/post',
'https://postman-echo.com/post',
{},
additionalHeaders
)
expect(jsonObj.result.headers['Accept']).toBe('foo')
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(
expect(jsonObj.result.headers[httpm.Headers.Accept]).toBe('foo')
expect(jsonObj.headers[httpm.Headers.ContentType]).toContain(
httpm.MediaTypes.ApplicationJson
)
@@ -52,11 +52,11 @@ describe('headers', () => {
}
}
jsonObj = await httpWithHeaders.postJson<any>(
'https://httpbin.org/post',
'https://postman-echo.com/post',
{}
)
expect(jsonObj.result.headers['Accept']).toBe('baz')
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(
expect(jsonObj.result.headers[httpm.Headers.Accept]).toBe('baz')
expect(jsonObj.headers[httpm.Headers.ContentType]).toContain(
httpm.MediaTypes.ApplicationJson
)
})
@@ -64,12 +64,12 @@ describe('headers', () => {
it('preserves existing headers on putJson', async () => {
const additionalHeaders = {[httpm.Headers.Accept]: 'foo'}
let jsonObj = await _http.putJson<any>(
'https://httpbin.org/put',
'https://postman-echo.com/put',
{},
additionalHeaders
)
expect(jsonObj.result.headers['Accept']).toBe('foo')
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(
expect(jsonObj.result.headers[httpm.Headers.Accept]).toBe('foo')
expect(jsonObj.headers[httpm.Headers.ContentType]).toContain(
httpm.MediaTypes.ApplicationJson
)
@@ -79,9 +79,12 @@ describe('headers', () => {
[httpm.Headers.Accept]: 'baz'
}
}
jsonObj = await httpWithHeaders.putJson<any>('https://httpbin.org/put', {})
expect(jsonObj.result.headers['Accept']).toBe('baz')
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(
jsonObj = await httpWithHeaders.putJson<any>(
'https://postman-echo.com/put',
{}
)
expect(jsonObj.result.headers[httpm.Headers.Accept]).toBe('baz')
expect(jsonObj.headers[httpm.Headers.ContentType]).toContain(
httpm.MediaTypes.ApplicationJson
)
})
@@ -89,12 +92,12 @@ describe('headers', () => {
it('preserves existing headers on patchJson', async () => {
const additionalHeaders = {[httpm.Headers.Accept]: 'foo'}
let jsonObj = await _http.patchJson<any>(
'https://httpbin.org/patch',
'https://postman-echo.com/patch',
{},
additionalHeaders
)
expect(jsonObj.result.headers['Accept']).toBe('foo')
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(
expect(jsonObj.result.headers[httpm.Headers.Accept]).toBe('foo')
expect(jsonObj.headers[httpm.Headers.ContentType]).toContain(
httpm.MediaTypes.ApplicationJson
)
@@ -105,11 +108,11 @@ describe('headers', () => {
}
}
jsonObj = await httpWithHeaders.patchJson<any>(
'https://httpbin.org/patch',
'https://postman-echo.com/patch',
{}
)
expect(jsonObj.result.headers['Accept']).toBe('baz')
expect(jsonObj.headers[httpm.Headers.ContentType]).toBe(
expect(jsonObj.result.headers[httpm.Headers.Accept]).toBe('baz')
expect(jsonObj.headers[httpm.Headers.ContentType]).toContain(
httpm.MediaTypes.ApplicationJson
)
})
@@ -13,24 +13,24 @@ describe('basics', () => {
it('does basic http get request with keepAlive true', async () => {
const res: httpm.HttpClientResponse = await _http.get(
'http://httpbin.org/get'
'http://postman-echo.com/get'
)
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
const obj = JSON.parse(body)
expect(obj.url).toBe('http://httpbin.org/get')
expect(obj.url).toBe('http://postman-echo.com/get')
})
it('does basic head request with keepAlive true', async () => {
const res: httpm.HttpClientResponse = await _http.head(
'http://httpbin.org/get'
'http://postman-echo.com/get'
)
expect(res.message.statusCode).toBe(200)
})
it('does basic http delete request with keepAlive true', async () => {
const res: httpm.HttpClientResponse = await _http.del(
'http://httpbin.org/delete'
'http://postman-echo.com/delete'
)
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
@@ -40,32 +40,32 @@ describe('basics', () => {
it('does basic http post request with keepAlive true', async () => {
const b = 'Hello World!'
const res: httpm.HttpClientResponse = await _http.post(
'http://httpbin.org/post',
'http://postman-echo.com/post',
b
)
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
const obj = JSON.parse(body)
expect(obj.data).toBe(b)
expect(obj.url).toBe('http://httpbin.org/post')
expect(obj.url).toBe('http://postman-echo.com/post')
})
it('does basic http patch request with keepAlive true', async () => {
const b = 'Hello World!'
const res: httpm.HttpClientResponse = await _http.patch(
'http://httpbin.org/patch',
'http://postman-echo.com/patch',
b
)
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
const obj = JSON.parse(body)
expect(obj.data).toBe(b)
expect(obj.url).toBe('http://httpbin.org/patch')
expect(obj.url).toBe('http://postman-echo.com/patch')
})
it('does basic http options request with keepAlive true', async () => {
const res: httpm.HttpClientResponse = await _http.options(
'http://httpbin.org'
'http://postman-echo.com'
)
expect(res.message.statusCode).toBe(200)
await res.readBody()
+19 -13
View File
@@ -91,6 +91,12 @@ describe('proxy', () => {
expect(proxyUrl).toBeDefined()
})
it('getProxyUrl returns proxyUrl if http_proxy has no protocol', () => {
process.env['http_proxy'] = 'myproxysvr'
const proxyUrl = pm.getProxyUrl(new URL('http://github.com'))
expect(proxyUrl?.toString()).toBe('http://myproxysvr/')
})
it('checkBypass returns true if host as no_proxy list', () => {
process.env['no_proxy'] = 'myserver'
const bypass = pm.checkBypass(new URL('https://myserver'))
@@ -192,26 +198,26 @@ describe('proxy', () => {
process.env['http_proxy'] = _proxyUrl
const httpClient = new httpm.HttpClient()
const res: httpm.HttpClientResponse = await httpClient.get(
'http://httpbin.org/get'
'http://postman-echo.com/get'
)
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
const obj = JSON.parse(body)
expect(obj.url).toBe('http://httpbin.org/get')
expect(_proxyConnects).toEqual(['httpbin.org:80'])
expect(obj.url).toBe('http://postman-echo.com/get')
expect(_proxyConnects).toEqual(['postman-echo.com:80'])
})
it('HttoClient does basic http get request when bypass proxy', async () => {
it('HttpClient does basic http get request when bypass proxy', async () => {
process.env['http_proxy'] = _proxyUrl
process.env['no_proxy'] = 'httpbin.org'
process.env['no_proxy'] = 'postman-echo.com'
const httpClient = new httpm.HttpClient()
const res: httpm.HttpClientResponse = await httpClient.get(
'http://httpbin.org/get'
'http://postman-echo.com/get'
)
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
const obj = JSON.parse(body)
expect(obj.url).toBe('http://httpbin.org/get')
expect(obj.url).toBe('http://postman-echo.com/get')
expect(_proxyConnects).toHaveLength(0)
})
@@ -219,26 +225,26 @@ describe('proxy', () => {
process.env['https_proxy'] = _proxyUrl
const httpClient = new httpm.HttpClient()
const res: httpm.HttpClientResponse = await httpClient.get(
'https://httpbin.org/get'
'https://postman-echo.com/get'
)
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
const obj = JSON.parse(body)
expect(obj.url).toBe('https://httpbin.org/get')
expect(_proxyConnects).toEqual(['httpbin.org:443'])
expect(obj.url).toBe('https://postman-echo.com/get')
expect(_proxyConnects).toEqual(['postman-echo.com:443'])
})
it('HttpClient does basic https get request when bypass proxy', async () => {
process.env['https_proxy'] = _proxyUrl
process.env['no_proxy'] = 'httpbin.org'
process.env['no_proxy'] = 'postman-echo.com'
const httpClient = new httpm.HttpClient()
const res: httpm.HttpClientResponse = await httpClient.get(
'https://httpbin.org/get'
'https://postman-echo.com/get'
)
expect(res.message.statusCode).toBe(200)
const body: string = await res.readBody()
const obj = JSON.parse(body)
expect(obj.url).toBe('https://httpbin.org/get')
expect(obj.url).toBe('https://postman-echo.com/get')
expect(_proxyConnects).toHaveLength(0)
})
+6 -1
View File
@@ -14,7 +14,12 @@ export function getProxyUrl(reqUrl: URL): URL | undefined {
})()
if (proxyVar) {
return new URL(proxyVar)
try {
return new URL(proxyVar)
} catch {
if (!proxyVar.startsWith('http://') && !proxyVar.startsWith('https://'))
return new URL(`http://${proxyVar}`)
}
} else {
return undefined
}
+3
View File
@@ -1,5 +1,8 @@
# @actions/io Releases
### 1.1.3
- Replace `child_process.exec` with `fs.rm` in `rmRF` for all OS implementations [#1373](https://github.com/actions/toolkit/pull/1373)
### 1.1.2
- Update `lockfileVersion` to `v2` in `package-lock.json [#1020](https://github.com/actions/toolkit/pull/1020)
+16 -24
View File
@@ -3,6 +3,7 @@ import {promises as fs} from 'fs'
import * as os from 'os'
import * as path from 'path'
import * as io from '../src/io'
import * as ioUtil from '../src/io-util'
describe('cp', () => {
beforeAll(async () => {
@@ -331,11 +332,22 @@ describe('rmRF', () => {
await fs.appendFile(filePath, 'some data')
await assertExists(filePath)
const fd = await fs.open(filePath, 'r')
await io.rmRF(testPath)
await assertNotExists(testPath)
// For windows we need to explicitly set an exclusive lock flag, because by default Node will open the file with the 'Delete' FileShare flag.
// See the exclusive lock windows flag definition:
// https://github.com/nodejs/node/blob/c2e4b1fa9ad0b744616c4e4c13a5017772a630c4/deps/uv/src/win/fs.c#L499-L513
const fd = await fs.open(
filePath,
fs.constants.O_RDONLY | ioUtil.UV_FS_O_EXLOCK
)
if (ioUtil.IS_WINDOWS) {
// On Windows, we expect an error due to an lstat call implementation in the underlying libuv code.
// See https://github.com/libuv/libuv/issues/3267 is resolved
await expect(async () => io.rmRF(testPath)).rejects.toThrow('EBUSY')
} else {
await io.rmRF(testPath)
await assertNotExists(testPath)
}
await fd.close()
await io.rmRF(testPath)
await assertNotExists(testPath)
@@ -373,26 +385,6 @@ describe('rmRF', () => {
await assertNotExists(file)
})
it('removes symlink folder with rmRF', async () => {
// create the following layout:
// real_directory
// real_directory/real_file
// symlink_directory -> real_directory
const root: string = path.join(getTestTemp(), 'rmRF_sym_dir_test')
const realDirectory: string = path.join(root, 'real_directory')
const realFile: string = path.join(root, 'real_directory', 'real_file')
const symlinkDirectory: string = path.join(root, 'symlink_directory')
await io.mkdirP(realDirectory)
await fs.writeFile(realFile, 'test file content')
await createSymlinkDir(realDirectory, symlinkDirectory)
await assertExists(path.join(symlinkDirectory, 'real_file'))
await io.rmRF(symlinkDirectory)
await assertExists(realDirectory)
await assertExists(realFile)
await assertNotExists(symlinkDirectory)
})
// creating a symlink to a file on Windows requires elevated
if (os.platform() !== 'win32') {
it('removes symlink file with rmRF', async () => {
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "@actions/io",
"version": "1.1.2",
"version": "1.1.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@actions/io",
"version": "1.1.2",
"version": "1.1.3",
"license": "MIT"
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@actions/io",
"version": "1.1.2",
"version": "1.1.3",
"description": "Actions io lib",
"keywords": [
"github",
+6 -1
View File
@@ -6,16 +6,21 @@ export const {
copyFile,
lstat,
mkdir,
open,
readdir,
readlink,
rename,
rm,
rmdir,
stat,
symlink,
unlink
} = fs.promises
// export const {open} = 'fs'
export const IS_WINDOWS = process.platform === 'win32'
// See https://github.com/nodejs/node/blob/d0153aee367422d0858105abec186da4dff0a0c5/deps/uv/include/uv/win.h#L691
export const UV_FS_O_EXLOCK = 0x10000000
export const READONLY = fs.constants.O_RDONLY
export async function exists(fsPath: string): Promise<boolean> {
try {
+11 -49
View File
@@ -1,12 +1,7 @@
import {ok} from 'assert'
import * as childProcess from 'child_process'
import * as path from 'path'
import {promisify} from 'util'
import * as ioUtil from './io-util'
const exec = promisify(childProcess.exec)
const execFile = promisify(childProcess.execFile)
/**
* Interface for cp/mv options
*/
@@ -116,9 +111,6 @@ export async function mv(
*/
export async function rmRF(inputPath: string): Promise<void> {
if (ioUtil.IS_WINDOWS) {
// Node doesn't provide a delete operation, only an unlink function. This means that if the file is being used by another
// program (e.g. antivirus), it won't be deleted. To address this, we shell out the work to rd/del.
// Check for invalid characters
// https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
if (/[*"<>|]/.test(inputPath)) {
@@ -126,47 +118,17 @@ export async function rmRF(inputPath: string): Promise<void> {
'File path must not contain `*`, `"`, `<`, `>` or `|` on Windows'
)
}
try {
const cmdPath = ioUtil.getCmdPath()
if (await ioUtil.isDirectory(inputPath, true)) {
await exec(`${cmdPath} /s /c "rd /s /q "%inputPath%""`, {
env: {inputPath}
})
} else {
await exec(`${cmdPath} /s /c "del /f /a "%inputPath%""`, {
env: {inputPath}
})
}
} catch (err) {
// if you try to delete a file that doesn't exist, desired result is achieved
// other errors are valid
if (err.code !== 'ENOENT') throw err
}
// Shelling out fails to remove a symlink folder with missing source, this unlink catches that
try {
await ioUtil.unlink(inputPath)
} catch (err) {
// if you try to delete a file that doesn't exist, desired result is achieved
// other errors are valid
if (err.code !== 'ENOENT') throw err
}
} else {
let isDir = false
try {
isDir = await ioUtil.isDirectory(inputPath)
} catch (err) {
// if you try to delete a file that doesn't exist, desired result is achieved
// other errors are valid
if (err.code !== 'ENOENT') throw err
return
}
if (isDir) {
await execFile(`rm`, [`-rf`, `${inputPath}`])
} else {
await ioUtil.unlink(inputPath)
}
}
try {
// note if path does not exist, error is silent
await ioUtil.rm(inputPath, {
force: true,
maxRetries: 3,
recursive: true,
retryDelay: 300
})
} catch (err) {
throw new Error(`File was unable to be removed ${err}`)
}
}