From 91b7bf978c1a6d4af4f2cf6d9dc76db045df94c2 Mon Sep 17 00:00:00 2001 From: Brian Cristante <33549821+brcrista@users.noreply.github.com> Date: Tue, 3 May 2022 11:10:13 -0400 Subject: [PATCH 1/9] Move @actions/http-client into the toolkit (#1062) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 💡 See https://github.com/actions/toolkit/pull/1064 for a better diff! https://github.com/actions/toolkit contains a variety of packages used for building actions. https://github.com/actions/http-client is one such package, but lives outside of the toolkit. Moving it inside of the toolkit will improve discoverability and reduce the number of repos we have to keep track of for maintenance tasks (such as github/c2c-actions-service#2937). I checked with @bryanmacfarlane on the historical decision here. Apparently it was just inertia from before we released the toolkit as multiple packages. The benefits here are: - Have one fewer repo to keep track of - Signal that this is an HTTP client meant for building actions, not for general use. ## Notes - `@actions/http-client` will continue to be released as its own package. - Bumping the package version to **2.0.0**. Since we're compiling in strict mode now, there are some breaking changes to the exported types. This is an improvement because the null-unsafe version of`http-client` is currently breaking the safety of null-safe consumers. - I'm not updating the other packages to use the new version in this PR. I plan to do that in a follow-up. We'll hold off on publishing `http-client` v2 to NPM until that's done just in case other changes shake out of it. --- .github/workflows/releases.yml | 30 +- README.md | 9 + packages/http-client/.gitignore | 2 + packages/http-client/LICENSE | 21 + packages/http-client/README.md | 73 ++ packages/http-client/RELEASES.md | 36 + packages/http-client/__tests__/auth.test.ts | 73 ++ packages/http-client/__tests__/basics.test.ts | 374 +++++++++ .../http-client/__tests__/headers.test.ts | 116 +++ .../http-client/__tests__/keepalive.test.ts | 73 ++ packages/http-client/__tests__/proxy.test.ts | 232 ++++++ packages/http-client/package-lock.json | 332 ++++++++ packages/http-client/package.json | 46 ++ packages/http-client/src/auth.ts | 86 ++ packages/http-client/src/index.ts | 773 ++++++++++++++++++ packages/http-client/src/interfaces.ts | 91 +++ packages/http-client/src/proxy.ts | 60 ++ packages/http-client/tsconfig.json | 11 + scripts/create-package | 4 +- 19 files changed, 2425 insertions(+), 17 deletions(-) create mode 100644 packages/http-client/.gitignore create mode 100644 packages/http-client/LICENSE create mode 100644 packages/http-client/README.md create mode 100644 packages/http-client/RELEASES.md create mode 100644 packages/http-client/__tests__/auth.test.ts create mode 100644 packages/http-client/__tests__/basics.test.ts create mode 100644 packages/http-client/__tests__/headers.test.ts create mode 100644 packages/http-client/__tests__/keepalive.test.ts create mode 100644 packages/http-client/__tests__/proxy.test.ts create mode 100644 packages/http-client/package-lock.json create mode 100644 packages/http-client/package.json create mode 100644 packages/http-client/src/auth.ts create mode 100644 packages/http-client/src/index.ts create mode 100644 packages/http-client/src/interfaces.ts create mode 100644 packages/http-client/src/proxy.ts create mode 100644 packages/http-client/tsconfig.json diff --git a/.github/workflows/releases.yml b/.github/workflows/releases.yml index b5f21974..cbabd034 100644 --- a/.github/workflows/releases.yml +++ b/.github/workflows/releases.yml @@ -5,8 +5,8 @@ on: inputs: package: required: true - description: 'core, artifact, cache, exec, github, glob, io, tool-cache' - + description: 'core, artifact, cache, exec, github, glob, http-client, io, tool-cache' + jobs: test: runs-on: macos-latest @@ -17,40 +17,40 @@ jobs: - name: verify package exists run: ls packages/${{ github.event.inputs.package }} - + - name: Set Node.js 12.x uses: actions/setup-node@v1 with: node-version: 12.x - + - name: npm install run: npm install - + - name: bootstrap run: npm run bootstrap - + - name: build run: npm run build - + - name: test run: npm run test - name: pack run: npm pack working-directory: packages/${{ github.event.inputs.package }} - + - name: upload artifact uses: actions/upload-artifact@v2 with: name: ${{ github.event.inputs.package }} path: packages/${{ github.event.inputs.package }}/*.tgz - + publish: runs-on: macos-latest needs: test environment: npm-publish steps: - + - name: download artifact uses: actions/download-artifact@v2 with: @@ -58,7 +58,7 @@ jobs: - name: setup authentication run: echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" >> .npmrc - env: + env: NPM_TOKEN: ${{ secrets.TOKEN }} - name: publish @@ -68,13 +68,13 @@ jobs: if: failure() run: | curl -X POST -H 'Content-type: application/json' --data '{"text":":pb__failed: Failed to publish a new version of ${{ github.event.inputs.package }}"}' $SLACK_WEBHOOK - env: + env: SLACK_WEBHOOK: ${{ secrets.SLACK }} - + - name: notify slack on success if: success() run: | curl -X POST -H 'Content-type: application/json' --data '{"text":":dance: Successfully published a new version of ${{ github.event.inputs.package }}"}' $SLACK_WEBHOOK - env: + env: SLACK_WEBHOOK: ${{ secrets.SLACK }} - + diff --git a/README.md b/README.md index 7571d1eb..43ee8acd 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,15 @@ $ npm install @actions/glob ```
+:phone: [@actions/http-client](packages/http-client) + +A lightweight HTTP client optimized for building actions. Read more [here](packages/http-client) + +```bash +$ npm install @actions/http-client +``` +
+ :pencil2: [@actions/io](packages/io) Provides disk i/o functions like cp, mv, rmRF, which etc. Read more [here](packages/io) diff --git a/packages/http-client/.gitignore b/packages/http-client/.gitignore new file mode 100644 index 00000000..d481b576 --- /dev/null +++ b/packages/http-client/.gitignore @@ -0,0 +1,2 @@ +testoutput.txt +npm-debug.log diff --git a/packages/http-client/LICENSE b/packages/http-client/LICENSE new file mode 100644 index 00000000..5823a51c --- /dev/null +++ b/packages/http-client/LICENSE @@ -0,0 +1,21 @@ +Actions Http Client for Node.js + +Copyright (c) GitHub, Inc. + +All rights reserved. + +MIT License + +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. diff --git a/packages/http-client/README.md b/packages/http-client/README.md new file mode 100644 index 00000000..7e06adeb --- /dev/null +++ b/packages/http-client/README.md @@ -0,0 +1,73 @@ +# `@actions/http-client` + +A lightweight HTTP client optimized for building actions. + +## Features + + - HTTP client with TypeScript generics and async/await/Promises + - Typings included! + - [Proxy support](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/about-self-hosted-runners#using-a-proxy-server-with-self-hosted-runners) just works with actions and the runner + - Targets ES2019 (runner runs actions with node 12+). Only supported on node 12+. + - Basic, Bearer and PAT Support out of the box. Extensible handlers for others. + - Redirects supported + +Features and releases [here](./RELEASES.md) + +## Install + +``` +npm install @actions/http-client --save +``` + +## Samples + +See the [tests](./__tests__) for detailed examples. + +## Errors + +### HTTP + +The HTTP client does not throw unless truly exceptional. + +* A request that successfully executes resulting in a 404, 500 etc... will return a response object with a status code and a body. +* Redirects (3xx) will be followed by default. + +See the [tests](./__tests__) for detailed examples. + +## Debugging + +To enable detailed console logging of all HTTP requests and responses, set the NODE_DEBUG environment varible: + +```shell +export NODE_DEBUG=http +``` + +## Node support + +The http-client is built using the latest LTS version of Node 12. It may work on previous node LTS versions but it's tested and officially supported on Node12+. + +## Support and Versioning + +We follow semver and will hold compatibility between major versions and increment the minor version with new features and capabilities (while holding compat). + +## Contributing + +We welcome PRs. Please create an issue and if applicable, a design before proceeding with code. + +once: + +``` +npm install +``` + +To build: + +``` +npm run build +``` + +To run all tests: + +``` +npm test +``` diff --git a/packages/http-client/RELEASES.md b/packages/http-client/RELEASES.md new file mode 100644 index 00000000..a097a4e0 --- /dev/null +++ b/packages/http-client/RELEASES.md @@ -0,0 +1,36 @@ +## Releases + +## 2.0.0 +- The package is now compiled with TypeScript's [`strict` compiler setting](https://www.typescriptlang.org/tsconfig#strict). To comply with stricter rules: + - Some exported types now include `| null` or `| undefined`, matching their actual behavior. + - Types implementing the method `RequestHandler.handleAuthentication()` now throw an `Error` rather than returning `null` if they do not support handling an HTTP 401 response. Callers can still use `canHandleAuthentication()` to determine if this handling is supported or not. + - Types using `any` have been scoped to more specific types. +- Following TypeScript's naming conventions, exported interfaces no longer begin with the prefix `I-`. +- Delete the `IHttpClientResponse` interface in favor of the `HttpClientResponse` class. +- Delete the `IHeaders` interface in favor of `http.OutgoingHttpHeaders`. +- The source code of the package was moved to build with [actions/toolkit](https://github.com/actions/toolkit). + +## 1.0.11 + +Contains a bug fix where proxy is defined without a user and password. see [PR here](https://github.com/actions/http-client/pull/42) + +## 1.0.9 +Throw HttpClientError instead of a generic Error from the \Json() helper methods when the server responds with a non-successful status code. + +## 1.0.8 +Fixed security issue where a redirect (e.g. 302) to another domain would pass headers. The fix was to strip the authorization header if the hostname was different. More [details in PR #27](https://github.com/actions/http-client/pull/27) + +## 1.0.7 +Update NPM dependencies and add 429 to the list of HttpCodes + +## 1.0.6 +Automatically sends Content-Type and Accept application/json headers for \Json() helper methods if not set in the client or parameters. + +## 1.0.5 +Adds \Json() helper methods for json over http scenarios. + +## 1.0.4 +Started to add \Json() helper methods. Do not use this release for that. Use >= 1.0.5 since there was an issue with types. + +## 1.0.1 to 1.0.3 +Adds proxy support. diff --git a/packages/http-client/__tests__/auth.test.ts b/packages/http-client/__tests__/auth.test.ts new file mode 100644 index 00000000..878fafe9 --- /dev/null +++ b/packages/http-client/__tests__/auth.test.ts @@ -0,0 +1,73 @@ +import * as httpm from '../lib' +import * as am from '../lib/auth' + +describe('auth', () => { + beforeEach(() => {}) + + afterEach(() => {}) + + it('does basic http get request with basic auth', async () => { + const bh: am.BasicCredentialHandler = new am.BasicCredentialHandler( + 'johndoe', + 'password' + ) + const http: httpm.HttpClient = new httpm.HttpClient('http-client-tests', [ + bh + ]) + const res: httpm.HttpClientResponse = await http.get( + 'http://httpbin.org/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 creds: string = Buffer.from( + auth.substring('Basic '.length), + 'base64' + ).toString() + expect(creds).toBe('johndoe:password') + expect(obj.url).toBe('http://httpbin.org/get') + }) + + it('does basic http get request with pat token auth', async () => { + const token = 'scbfb44vxzku5l4xgc3qfazn3lpk4awflfryc76esaiq7aypcbhs' + const ph: am.PersonalAccessTokenCredentialHandler = new am.PersonalAccessTokenCredentialHandler( + token + ) + + const http: httpm.HttpClient = new httpm.HttpClient('http-client-tests', [ + ph + ]) + const res: httpm.HttpClientResponse = await http.get( + 'http://httpbin.org/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 creds: string = Buffer.from( + auth.substring('Basic '.length), + 'base64' + ).toString() + expect(creds).toBe(`PAT:${token}`) + expect(obj.url).toBe('http://httpbin.org/get') + }) + + it('does basic http get request with pat token auth', async () => { + const token = 'scbfb44vxzku5l4xgc3qfazn3lpk4awflfryc76esaiq7aypcbhs' + const ph: am.BearerCredentialHandler = new am.BearerCredentialHandler(token) + + const http: httpm.HttpClient = new httpm.HttpClient('http-client-tests', [ + ph + ]) + const res: httpm.HttpClientResponse = await http.get( + 'http://httpbin.org/get' + ) + expect(res.message.statusCode).toBe(200) + const body: string = await res.readBody() + const obj = JSON.parse(body) + const auth: string = obj.headers.Authorization + expect(auth).toBe(`Bearer ${token}`) + expect(obj.url).toBe('http://httpbin.org/get') + }) +}) diff --git a/packages/http-client/__tests__/basics.test.ts b/packages/http-client/__tests__/basics.test.ts new file mode 100644 index 00000000..7732264a --- /dev/null +++ b/packages/http-client/__tests__/basics.test.ts @@ -0,0 +1,374 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import * as httpm from '..' +import * as path from 'path' +import * as fs from 'fs' + +const sampleFilePath: string = path.join(__dirname, 'testoutput.txt') + +interface HttpBinData { + url: string + data: any + json: any + headers: any + args?: any +} + +describe('basics', () => { + let _http: httpm.HttpClient + + beforeEach(() => { + _http = new httpm.HttpClient('http-client-tests') + }) + + afterEach(() => {}) + + it('constructs', () => { + const http: httpm.HttpClient = new httpm.HttpClient('thttp-client-tests') + expect(http).toBeDefined() + }) + + // responses from httpbin return something like: + // { + // "args": {}, + // "headers": { + // "Connection": "close", + // "Host": "httpbin.org", + // "User-Agent": "typed-test-client-tests" + // }, + // "origin": "173.95.152.44", + // "url": "https://httpbin.org/get" + // } + + it('does basic http get request', async () => { + const res: httpm.HttpClientResponse = await _http.get( + 'http://httpbin.org/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() + }) + + 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' + ) + 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() + }) + + it('does basic https get request', async () => { + const res: httpm.HttpClientResponse = await _http.get( + 'https://httpbin.org/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') + }) + + it('does basic http get request with default headers', async () => { + const http: httpm.HttpClient = new httpm.HttpClient( + 'http-client-tests', + [], + { + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + } + } + ) + const res: httpm.HttpClientResponse = await http.get( + 'http://httpbin.org/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') + }) + + it('does basic http get request with merged headers', async () => { + const http: httpm.HttpClient = new httpm.HttpClient( + 'http-client-tests', + [], + { + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + } + } + ) + const res: httpm.HttpClientResponse = await http.get( + 'http://httpbin.org/get', + { + 'content-type': 'application/x-www-form-urlencoded' + } + ) + 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/x-www-form-urlencoded' + ) + expect(obj.url).toBe('http://httpbin.org/get') + }) + + it('pipes a get request', async () => { + return new Promise(async resolve => { + const file = fs.createWriteStream(sampleFilePath) + ;(await _http.get('https://httpbin.org/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') + resolve() + }) + }) + }) + + 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' + )}` + ) + 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') + }) + + 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' + )}&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') + }) + + 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' + )}&status_code=303` + ) + expect(res.message.statusCode).toBe(404) + await res.readBody() + }) + + it('does not follow redirects if disabled', async () => { + const http: httpm.HttpClient = new httpm.HttpClient( + 'typed-test-client-tests', + undefined, + {allowRedirects: false} + ) + const res: httpm.HttpClientResponse = await http.get( + `https://httpbin.org/redirect-to?url=${encodeURIComponent( + 'https://httpbin.org/get' + )}` + ) + expect(res.message.statusCode).toBe(302) + await res.readBody() + }) + + it('does not pass auth with diff hostname redirects', async () => { + const headers = { + accept: 'application/json', + authorization: 'shhh' + } + const res: httpm.HttpClientResponse = await _http.get( + `https://httpbin.org/redirect-to?url=${encodeURIComponent( + 'https://www.httpbin.org/get' + )}`, + headers + ) + + expect(res.message.statusCode).toBe(200) + 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['Authorization']).toBeUndefined() + expect(obj.headers['authorization']).toBeUndefined() + expect(obj.url).toBe('https://www.httpbin.org/get') + }) + + it('does not pass Auth with diff hostname redirects', async () => { + const headers = { + Accept: 'application/json', + Authorization: 'shhh' + } + const res: httpm.HttpClientResponse = await _http.get( + `https://httpbin.org/redirect-to?url=${encodeURIComponent( + 'https://www.httpbin.org/get' + )}`, + headers + ) + + expect(res.message.statusCode).toBe(200) + 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['Authorization']).toBeUndefined() + expect(obj.headers['authorization']).toBeUndefined() + expect(obj.url).toBe('https://www.httpbin.org/get') + }) + + it('does basic head request', async () => { + const res: httpm.HttpClientResponse = await _http.head( + 'http://httpbin.org/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' + ) + expect(res.message.statusCode).toBe(200) + const body: string = await res.readBody() + JSON.parse(body) + }) + + it('does basic http post request', async () => { + const b = 'Hello World!' + const res: httpm.HttpClientResponse = await _http.post( + 'http://httpbin.org/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') + }) + + it('does basic http patch request', async () => { + const b = 'Hello World!' + const res: httpm.HttpClientResponse = await _http.patch( + 'http://httpbin.org/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') + }) + + it('does basic http options request', async () => { + const res: httpm.HttpClientResponse = await _http.options( + 'http://httpbin.org' + ) + expect(res.message.statusCode).toBe(200) + await res.readBody() + }) + + it('returns 404 for not found get request', async () => { + const res: httpm.HttpClientResponse = await _http.get( + 'http://httpbin.org/status/404' + ) + expect(res.message.statusCode).toBe(404) + await res.readBody() + }) + + it('gets a json object', async () => { + const jsonObj = await _http.getJson('https://httpbin.org/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( + httpm.MediaTypes.ApplicationJson + ) + expect(jsonObj.headers[httpm.Headers.ContentType]).toBe( + httpm.MediaTypes.ApplicationJson + ) + }) + + it('getting a non existent json object returns null', async () => { + const jsonObj = await _http.getJson( + 'https://httpbin.org/status/404' + ) + expect(jsonObj.statusCode).toBe(404) + expect(jsonObj.result).toBeNull() + }) + + it('posts a json object', async () => { + const res = {name: 'foo'} + const restRes = await _http.postJson( + 'https://httpbin.org/post', + res + ) + expect(restRes.statusCode).toBe(200) + expect(restRes.result).toBeDefined() + expect(restRes.result?.url).toBe('https://httpbin.org/post') + expect(restRes.result?.json.name).toBe('foo') + expect(restRes.result?.headers['Accept']).toBe( + httpm.MediaTypes.ApplicationJson + ) + expect(restRes.result?.headers['Content-Type']).toBe( + httpm.MediaTypes.ApplicationJson + ) + expect(restRes.headers[httpm.Headers.ContentType]).toBe( + httpm.MediaTypes.ApplicationJson + ) + }) + + it('puts a json object', async () => { + const res = {name: 'foo'} + const restRes = await _http.putJson( + 'https://httpbin.org/put', + res + ) + expect(restRes.statusCode).toBe(200) + expect(restRes.result).toBeDefined() + expect(restRes.result?.url).toBe('https://httpbin.org/put') + expect(restRes.result?.json.name).toBe('foo') + + expect(restRes.result?.headers['Accept']).toBe( + httpm.MediaTypes.ApplicationJson + ) + expect(restRes.result?.headers['Content-Type']).toBe( + httpm.MediaTypes.ApplicationJson + ) + expect(restRes.headers[httpm.Headers.ContentType]).toBe( + httpm.MediaTypes.ApplicationJson + ) + }) + + it('patch a json object', async () => { + const res = {name: 'foo'} + const restRes = await _http.patchJson( + 'https://httpbin.org/patch', + res + ) + expect(restRes.statusCode).toBe(200) + expect(restRes.result).toBeDefined() + expect(restRes.result?.url).toBe('https://httpbin.org/patch') + expect(restRes.result?.json.name).toBe('foo') + expect(restRes.result?.headers['Accept']).toBe( + httpm.MediaTypes.ApplicationJson + ) + expect(restRes.result?.headers['Content-Type']).toBe( + httpm.MediaTypes.ApplicationJson + ) + expect(restRes.headers[httpm.Headers.ContentType]).toBe( + httpm.MediaTypes.ApplicationJson + ) + }) +}) diff --git a/packages/http-client/__tests__/headers.test.ts b/packages/http-client/__tests__/headers.test.ts new file mode 100644 index 00000000..0af9563c --- /dev/null +++ b/packages/http-client/__tests__/headers.test.ts @@ -0,0 +1,116 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import * as httpm from '..' + +describe('headers', () => { + let _http: httpm.HttpClient + + beforeEach(() => { + _http = new httpm.HttpClient('http-client-tests') + }) + + it('preserves existing headers on getJson', async () => { + const additionalHeaders = {[httpm.Headers.Accept]: 'foo'} + let jsonObj = await _http.getJson( + 'https://httpbin.org/get', + additionalHeaders + ) + expect(jsonObj.result.headers['Accept']).toBe('foo') + expect(jsonObj.headers[httpm.Headers.ContentType]).toBe( + httpm.MediaTypes.ApplicationJson + ) + + const httpWithHeaders = new httpm.HttpClient() + httpWithHeaders.requestOptions = { + headers: { + [httpm.Headers.Accept]: 'baz' + } + } + jsonObj = await httpWithHeaders.getJson('https://httpbin.org/get') + expect(jsonObj.result.headers['Accept']).toBe('baz') + expect(jsonObj.headers[httpm.Headers.ContentType]).toBe( + httpm.MediaTypes.ApplicationJson + ) + }) + + it('preserves existing headers on postJson', async () => { + const additionalHeaders = {[httpm.Headers.Accept]: 'foo'} + let jsonObj = await _http.postJson( + 'https://httpbin.org/post', + {}, + additionalHeaders + ) + expect(jsonObj.result.headers['Accept']).toBe('foo') + expect(jsonObj.headers[httpm.Headers.ContentType]).toBe( + httpm.MediaTypes.ApplicationJson + ) + + const httpWithHeaders = new httpm.HttpClient() + httpWithHeaders.requestOptions = { + headers: { + [httpm.Headers.Accept]: 'baz' + } + } + jsonObj = await httpWithHeaders.postJson( + 'https://httpbin.org/post', + {} + ) + expect(jsonObj.result.headers['Accept']).toBe('baz') + expect(jsonObj.headers[httpm.Headers.ContentType]).toBe( + httpm.MediaTypes.ApplicationJson + ) + }) + + it('preserves existing headers on putJson', async () => { + const additionalHeaders = {[httpm.Headers.Accept]: 'foo'} + let jsonObj = await _http.putJson( + 'https://httpbin.org/put', + {}, + additionalHeaders + ) + expect(jsonObj.result.headers['Accept']).toBe('foo') + expect(jsonObj.headers[httpm.Headers.ContentType]).toBe( + httpm.MediaTypes.ApplicationJson + ) + + const httpWithHeaders = new httpm.HttpClient() + httpWithHeaders.requestOptions = { + headers: { + [httpm.Headers.Accept]: 'baz' + } + } + jsonObj = await httpWithHeaders.putJson('https://httpbin.org/put', {}) + expect(jsonObj.result.headers['Accept']).toBe('baz') + expect(jsonObj.headers[httpm.Headers.ContentType]).toBe( + httpm.MediaTypes.ApplicationJson + ) + }) + + it('preserves existing headers on patchJson', async () => { + const additionalHeaders = {[httpm.Headers.Accept]: 'foo'} + let jsonObj = await _http.patchJson( + 'https://httpbin.org/patch', + {}, + additionalHeaders + ) + expect(jsonObj.result.headers['Accept']).toBe('foo') + expect(jsonObj.headers[httpm.Headers.ContentType]).toBe( + httpm.MediaTypes.ApplicationJson + ) + + const httpWithHeaders = new httpm.HttpClient() + httpWithHeaders.requestOptions = { + headers: { + [httpm.Headers.Accept]: 'baz' + } + } + jsonObj = await httpWithHeaders.patchJson( + 'https://httpbin.org/patch', + {} + ) + expect(jsonObj.result.headers['Accept']).toBe('baz') + expect(jsonObj.headers[httpm.Headers.ContentType]).toBe( + httpm.MediaTypes.ApplicationJson + ) + }) +}) diff --git a/packages/http-client/__tests__/keepalive.test.ts b/packages/http-client/__tests__/keepalive.test.ts new file mode 100644 index 00000000..ed55be20 --- /dev/null +++ b/packages/http-client/__tests__/keepalive.test.ts @@ -0,0 +1,73 @@ +import * as httpm from '../lib' + +describe('basics', () => { + let _http: httpm.HttpClient + + beforeEach(() => { + _http = new httpm.HttpClient('http-client-tests', [], {keepAlive: true}) + }) + + afterEach(() => { + _http.dispose() + }) + + it('does basic http get request with keepAlive true', async () => { + const res: httpm.HttpClientResponse = await _http.get( + 'http://httpbin.org/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') + }) + + it('does basic head request with keepAlive true', async () => { + const res: httpm.HttpClientResponse = await _http.head( + 'http://httpbin.org/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' + ) + expect(res.message.statusCode).toBe(200) + const body: string = await res.readBody() + JSON.parse(body) + }) + + 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', + 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') + }) + + 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', + 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') + }) + + it('does basic http options request with keepAlive true', async () => { + const res: httpm.HttpClientResponse = await _http.options( + 'http://httpbin.org' + ) + expect(res.message.statusCode).toBe(200) + await res.readBody() + }) +}) diff --git a/packages/http-client/__tests__/proxy.test.ts b/packages/http-client/__tests__/proxy.test.ts new file mode 100644 index 00000000..62e8e962 --- /dev/null +++ b/packages/http-client/__tests__/proxy.test.ts @@ -0,0 +1,232 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import * as http from 'http' +import * as httpm from '../lib/' +import * as pm from '../lib/proxy' +// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports +const proxy = require('proxy') + +let _proxyConnects: string[] +let _proxyServer: http.Server +const _proxyUrl = 'http://127.0.0.1:8080' + +describe('proxy', () => { + beforeAll(async () => { + // Start proxy server + _proxyServer = proxy() + await new Promise(resolve => { + const port = Number(_proxyUrl.split(':')[2]) + _proxyServer.listen(port, () => resolve()) + }) + _proxyServer.on('connect', req => { + _proxyConnects.push(req.url) + }) + }) + + beforeEach(() => { + _proxyConnects = [] + _clearVars() + }) + + afterEach(() => {}) + + afterAll(async () => { + _clearVars() + + // Stop proxy server + await new Promise(resolve => { + _proxyServer.once('close', () => resolve()) + _proxyServer.close() + }) + }) + + it('getProxyUrl does not return proxyUrl if variables not set', () => { + const proxyUrl = pm.getProxyUrl(new URL('https://github.com')) + expect(proxyUrl).toBeUndefined() + }) + + it('getProxyUrl returns proxyUrl if https_proxy set for https url', () => { + process.env['https_proxy'] = 'https://myproxysvr' + const proxyUrl = pm.getProxyUrl(new URL('https://github.com')) + expect(proxyUrl).toBeDefined() + }) + + it('getProxyUrl does not return proxyUrl if http_proxy set for https url', () => { + process.env['http_proxy'] = 'https://myproxysvr' + const proxyUrl = pm.getProxyUrl(new URL('https://github.com')) + expect(proxyUrl).toBeUndefined() + }) + + it('getProxyUrl returns proxyUrl if http_proxy set for http url', () => { + process.env['http_proxy'] = 'http://myproxysvr' + const proxyUrl = pm.getProxyUrl(new URL('http://github.com')) + expect(proxyUrl).toBeDefined() + }) + + it('getProxyUrl does not return proxyUrl if https_proxy set and in no_proxy list', () => { + process.env['https_proxy'] = 'https://myproxysvr' + process.env['no_proxy'] = 'otherserver,myserver,anotherserver:8080' + const proxyUrl = pm.getProxyUrl(new URL('https://myserver')) + expect(proxyUrl).toBeUndefined() + }) + + it('getProxyUrl returns proxyUrl if https_proxy set and not in no_proxy list', () => { + process.env['https_proxy'] = 'https://myproxysvr' + process.env['no_proxy'] = 'otherserver,myserver,anotherserver:8080' + const proxyUrl = pm.getProxyUrl(new URL('https://github.com')) + expect(proxyUrl).toBeDefined() + }) + + it('getProxyUrl does not return proxyUrl if http_proxy set and in no_proxy list', () => { + process.env['http_proxy'] = 'http://myproxysvr' + process.env['no_proxy'] = 'otherserver,myserver,anotherserver:8080' + const proxyUrl = pm.getProxyUrl(new URL('http://myserver')) + expect(proxyUrl).toBeUndefined() + }) + + it('getProxyUrl returns proxyUrl if http_proxy set and not in no_proxy list', () => { + process.env['http_proxy'] = 'http://myproxysvr' + process.env['no_proxy'] = 'otherserver,myserver,anotherserver:8080' + const proxyUrl = pm.getProxyUrl(new URL('http://github.com')) + expect(proxyUrl).toBeDefined() + }) + + it('checkBypass returns true if host as no_proxy list', () => { + process.env['no_proxy'] = 'myserver' + const bypass = pm.checkBypass(new URL('https://myserver')) + expect(bypass).toBeTruthy() + }) + + it('checkBypass returns true if host in no_proxy list', () => { + process.env['no_proxy'] = 'otherserver,myserver,anotherserver:8080' + const bypass = pm.checkBypass(new URL('https://myserver')) + expect(bypass).toBeTruthy() + }) + + it('checkBypass returns true if host in no_proxy list with spaces', () => { + process.env['no_proxy'] = 'otherserver, myserver ,anotherserver:8080' + const bypass = pm.checkBypass(new URL('https://myserver')) + expect(bypass).toBeTruthy() + }) + + it('checkBypass returns true if host in no_proxy list with port', () => { + process.env['no_proxy'] = 'otherserver, myserver:8080 ,anotherserver' + const bypass = pm.checkBypass(new URL('https://myserver:8080')) + expect(bypass).toBeTruthy() + }) + + it('checkBypass returns true if host with port in no_proxy list without port', () => { + process.env['no_proxy'] = 'otherserver, myserver ,anotherserver' + const bypass = pm.checkBypass(new URL('https://myserver:8080')) + expect(bypass).toBeTruthy() + }) + + it('checkBypass returns true if host in no_proxy list with default https port', () => { + process.env['no_proxy'] = 'otherserver, myserver:443 ,anotherserver' + const bypass = pm.checkBypass(new URL('https://myserver')) + expect(bypass).toBeTruthy() + }) + + it('checkBypass returns true if host in no_proxy list with default http port', () => { + process.env['no_proxy'] = 'otherserver, myserver:80 ,anotherserver' + const bypass = pm.checkBypass(new URL('http://myserver')) + expect(bypass).toBeTruthy() + }) + + it('checkBypass returns false if host not in no_proxy list', () => { + process.env['no_proxy'] = 'otherserver, myserver ,anotherserver:8080' + const bypass = pm.checkBypass(new URL('https://github.com')) + expect(bypass).toBeFalsy() + }) + + it('checkBypass returns false if empty no_proxy', () => { + process.env['no_proxy'] = '' + const bypass = pm.checkBypass(new URL('https://github.com')) + expect(bypass).toBeFalsy() + }) + + it('HttpClient does basic http get request through proxy', async () => { + process.env['http_proxy'] = _proxyUrl + const httpClient = new httpm.HttpClient() + const res: httpm.HttpClientResponse = await httpClient.get( + 'http://httpbin.org/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']) + }) + + it('HttoClient does basic http get request when bypass proxy', async () => { + process.env['http_proxy'] = _proxyUrl + process.env['no_proxy'] = 'httpbin.org' + const httpClient = new httpm.HttpClient() + const res: httpm.HttpClientResponse = await httpClient.get( + 'http://httpbin.org/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).toHaveLength(0) + }) + + it('HttpClient does basic https get request through proxy', async () => { + process.env['https_proxy'] = _proxyUrl + const httpClient = new httpm.HttpClient() + const res: httpm.HttpClientResponse = await httpClient.get( + 'https://httpbin.org/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']) + }) + + it('HttpClient does basic https get request when bypass proxy', async () => { + process.env['https_proxy'] = _proxyUrl + process.env['no_proxy'] = 'httpbin.org' + const httpClient = new httpm.HttpClient() + const res: httpm.HttpClientResponse = await httpClient.get( + 'https://httpbin.org/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).toHaveLength(0) + }) + + it('proxyAuth not set in tunnel agent when authentication is not provided', async () => { + process.env['https_proxy'] = 'http://127.0.0.1:8080' + const httpClient = new httpm.HttpClient() + const agent: any = httpClient.getAgent('https://some-url') + // eslint-disable-next-line no-console + console.log(agent) + expect(agent.proxyOptions.host).toBe('127.0.0.1') + expect(agent.proxyOptions.port).toBe('8080') + expect(agent.proxyOptions.proxyAuth).toBe(undefined) + }) + + it('proxyAuth is set in tunnel agent when authentication is provided', async () => { + process.env['https_proxy'] = 'http://user:password@127.0.0.1:8080' + const httpClient = new httpm.HttpClient() + const agent: any = httpClient.getAgent('https://some-url') + // eslint-disable-next-line no-console + console.log(agent) + expect(agent.proxyOptions.host).toBe('127.0.0.1') + expect(agent.proxyOptions.port).toBe('8080') + expect(agent.proxyOptions.proxyAuth).toBe('user:password') + }) +}) + +function _clearVars(): void { + delete process.env.http_proxy + delete process.env.HTTP_PROXY + delete process.env.https_proxy + delete process.env.HTTPS_PROXY + delete process.env.no_proxy + delete process.env.NO_PROXY +} diff --git a/packages/http-client/package-lock.json b/packages/http-client/package-lock.json new file mode 100644 index 00000000..7a2f0f23 --- /dev/null +++ b/packages/http-client/package-lock.json @@ -0,0 +1,332 @@ +{ + "name": "@actions/http-client", + "version": "2.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "@actions/http-client", + "version": "2.0.0", + "license": "MIT", + "devDependencies": { + "@types/tunnel": "0.0.3", + "proxy": "^1.0.1", + "tunnel": "0.0.6" + } + }, + "node_modules/@types/node": { + "version": "12.12.31", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.31.tgz", + "integrity": "sha512-T+wnJno8uh27G9c+1T+a1/WYCHzLeDqtsGJkoEdSp2X8RTh3oOCZQcUnjAx90CS8cmmADX51O0FI/tu9s0yssg==", + "dev": true + }, + "node_modules/@types/tunnel": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/tunnel/-/tunnel-0.0.3.tgz", + "integrity": "sha512-sOUTGn6h1SfQ+gbgqC364jLFBw2lnFqkgF3q0WovEHRLMrVD1sd5aufqi/aJObLekJO+Aq5z646U4Oxy6shXMA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/args": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/args/-/args-5.0.1.tgz", + "integrity": "sha512-1kqmFCFsPffavQFGt8OxJdIcETti99kySRUPMpOhaGjL6mRJn8HFU1OxKY5bMqfZKUwTQc1mZkAjmGYaVOHFtQ==", + "dev": true, + "dependencies": { + "camelcase": "5.0.0", + "chalk": "2.4.2", + "leven": "2.1.0", + "mri": "1.1.4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/basic-auth-parser": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/basic-auth-parser/-/basic-auth-parser-0.0.2.tgz", + "integrity": "sha1-zp5xp38jwSee7NJlmypGJEwVbkE=", + "dev": true + }, + "node_modules/camelcase": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", + "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/leven": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", + "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mri": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.4.tgz", + "integrity": "sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/proxy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/proxy/-/proxy-1.0.2.tgz", + "integrity": "sha512-KNac2ueWRpjbUh77OAFPZuNdfEqNynm9DD4xHT14CccGpW8wKZwEkN0yjlb7X9G9Z9F55N0Q+1z+WfgAhwYdzQ==", + "dev": true, + "dependencies": { + "args": "5.0.1", + "basic-auth-parser": "0.0.2", + "debug": "^4.1.1" + }, + "bin": { + "proxy": "bin/proxy.js" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "dev": true, + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + } + }, + "dependencies": { + "@types/node": { + "version": "12.12.31", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.31.tgz", + "integrity": "sha512-T+wnJno8uh27G9c+1T+a1/WYCHzLeDqtsGJkoEdSp2X8RTh3oOCZQcUnjAx90CS8cmmADX51O0FI/tu9s0yssg==", + "dev": true + }, + "@types/tunnel": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/tunnel/-/tunnel-0.0.3.tgz", + "integrity": "sha512-sOUTGn6h1SfQ+gbgqC364jLFBw2lnFqkgF3q0WovEHRLMrVD1sd5aufqi/aJObLekJO+Aq5z646U4Oxy6shXMA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "args": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/args/-/args-5.0.1.tgz", + "integrity": "sha512-1kqmFCFsPffavQFGt8OxJdIcETti99kySRUPMpOhaGjL6mRJn8HFU1OxKY5bMqfZKUwTQc1mZkAjmGYaVOHFtQ==", + "dev": true, + "requires": { + "camelcase": "5.0.0", + "chalk": "2.4.2", + "leven": "2.1.0", + "mri": "1.1.4" + } + }, + "basic-auth-parser": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/basic-auth-parser/-/basic-auth-parser-0.0.2.tgz", + "integrity": "sha1-zp5xp38jwSee7NJlmypGJEwVbkE=", + "dev": true + }, + "camelcase": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", + "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "leven": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", + "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", + "dev": true + }, + "mri": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.4.tgz", + "integrity": "sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "proxy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/proxy/-/proxy-1.0.2.tgz", + "integrity": "sha512-KNac2ueWRpjbUh77OAFPZuNdfEqNynm9DD4xHT14CccGpW8wKZwEkN0yjlb7X9G9Z9F55N0Q+1z+WfgAhwYdzQ==", + "dev": true, + "requires": { + "args": "5.0.1", + "basic-auth-parser": "0.0.2", + "debug": "^4.1.1" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "dev": true + } + } +} diff --git a/packages/http-client/package.json b/packages/http-client/package.json new file mode 100644 index 00000000..f9db7e77 --- /dev/null +++ b/packages/http-client/package.json @@ -0,0 +1,46 @@ +{ + "name": "@actions/http-client", + "version": "2.0.0", + "description": "Actions Http Client", + "keywords": [ + "github", + "actions", + "http" + ], + "homepage": "https://github.com/actions/toolkit/tree/main/packages/http-client", + "license": "MIT", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "directories": { + "lib": "lib", + "test": "__tests__" + }, + "files": [ + "lib", + "!.DS_Store" + ], + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/actions/toolkit.git", + "directory": "packages/github" + }, + "scripts": { + "audit-moderate": "npm install && npm audit --json --audit-level=moderate > audit.json", + "test": "echo \"Error: run tests from root\" && exit 1", + "build": "tsc", + "format": "prettier --write **/*.ts", + "format-check": "prettier --check **/*.ts", + "tsc": "tsc" + }, + "bugs": { + "url": "https://github.com/actions/toolkit/issues" + }, + "devDependencies": { + "@types/tunnel": "0.0.3", + "proxy": "^1.0.1", + "tunnel": "0.0.6" + } +} diff --git a/packages/http-client/src/auth.ts b/packages/http-client/src/auth.ts new file mode 100644 index 00000000..639adbe2 --- /dev/null +++ b/packages/http-client/src/auth.ts @@ -0,0 +1,86 @@ +import * as http from 'http' +import * as ifm from './interfaces' +import {HttpClientResponse} from './index' + +export class BasicCredentialHandler implements ifm.RequestHandler { + username: string + password: string + + constructor(username: string, password: string) { + this.username = username + this.password = password + } + + prepareRequest(options: http.RequestOptions): void { + if (!options.headers) { + throw Error('The request has no headers') + } + options.headers['Authorization'] = `Basic ${Buffer.from( + `${this.username}:${this.password}` + ).toString('base64')}` + } + + // This handler cannot handle 401 + canHandleAuthentication(): boolean { + return false + } + + async handleAuthentication(): Promise { + throw new Error('not implemented') + } +} + +export class BearerCredentialHandler implements ifm.RequestHandler { + token: string + + constructor(token: string) { + this.token = token + } + + // currently implements pre-authorization + // TODO: support preAuth = false where it hooks on 401 + prepareRequest(options: http.RequestOptions): void { + if (!options.headers) { + throw Error('The request has no headers') + } + options.headers['Authorization'] = `Bearer ${this.token}` + } + + // This handler cannot handle 401 + canHandleAuthentication(): boolean { + return false + } + + async handleAuthentication(): Promise { + throw new Error('not implemented') + } +} + +export class PersonalAccessTokenCredentialHandler + implements ifm.RequestHandler { + token: string + + constructor(token: string) { + this.token = token + } + + // currently implements pre-authorization + // TODO: support preAuth = false where it hooks on 401 + prepareRequest(options: http.RequestOptions): void { + if (!options.headers) { + throw Error('The request has no headers') + } + options.headers['Authorization'] = `Basic ${Buffer.from( + `PAT:${this.token}` + ).toString('base64')}` + } + + // This handler cannot handle 401 + canHandleAuthentication(): boolean { + return false + } + + async handleAuthentication(): Promise { + throw new Error('not implemented') + } +} diff --git a/packages/http-client/src/index.ts b/packages/http-client/src/index.ts new file mode 100644 index 00000000..f02c2754 --- /dev/null +++ b/packages/http-client/src/index.ts @@ -0,0 +1,773 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import * as http from 'http' +import * as https from 'https' +import * as ifm from './interfaces' +import * as net from 'net' +import * as pm from './proxy' +import * as tunnel from 'tunnel' + +export enum HttpCodes { + OK = 200, + MultipleChoices = 300, + MovedPermanently = 301, + ResourceMoved = 302, + SeeOther = 303, + NotModified = 304, + UseProxy = 305, + SwitchProxy = 306, + TemporaryRedirect = 307, + PermanentRedirect = 308, + BadRequest = 400, + Unauthorized = 401, + PaymentRequired = 402, + Forbidden = 403, + NotFound = 404, + MethodNotAllowed = 405, + NotAcceptable = 406, + ProxyAuthenticationRequired = 407, + RequestTimeout = 408, + Conflict = 409, + Gone = 410, + TooManyRequests = 429, + InternalServerError = 500, + NotImplemented = 501, + BadGateway = 502, + ServiceUnavailable = 503, + GatewayTimeout = 504 +} + +export enum Headers { + Accept = 'accept', + ContentType = 'content-type' +} + +export enum MediaTypes { + ApplicationJson = 'application/json' +} + +/** + * Returns the proxy URL, depending upon the supplied url and proxy environment variables. + * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com + */ +export function getProxyUrl(serverUrl: string): string { + const proxyUrl = pm.getProxyUrl(new URL(serverUrl)) + return proxyUrl ? proxyUrl.href : '' +} + +const HttpRedirectCodes: number[] = [ + HttpCodes.MovedPermanently, + HttpCodes.ResourceMoved, + HttpCodes.SeeOther, + HttpCodes.TemporaryRedirect, + HttpCodes.PermanentRedirect +] +const HttpResponseRetryCodes: number[] = [ + HttpCodes.BadGateway, + HttpCodes.ServiceUnavailable, + HttpCodes.GatewayTimeout +] +const RetryableHttpVerbs: string[] = ['OPTIONS', 'GET', 'DELETE', 'HEAD'] +const ExponentialBackoffCeiling = 10 +const ExponentialBackoffTimeSlice = 5 + +export class HttpClientError extends Error { + constructor(message: string, statusCode: number) { + super(message) + this.name = 'HttpClientError' + this.statusCode = statusCode + Object.setPrototypeOf(this, HttpClientError.prototype) + } + + statusCode: number + result?: any +} + +export class HttpClientResponse { + constructor(message: http.IncomingMessage) { + this.message = message + } + + message: http.IncomingMessage + async readBody(): Promise { + return new Promise(async resolve => { + let output = Buffer.alloc(0) + + this.message.on('data', (chunk: Buffer) => { + output = Buffer.concat([output, chunk]) + }) + + this.message.on('end', () => { + resolve(output.toString()) + }) + }) + } +} + +export function isHttps(requestUrl: string): boolean { + const parsedUrl: URL = new URL(requestUrl) + return parsedUrl.protocol === 'https:' +} + +export class HttpClient { + userAgent: string | undefined + handlers: ifm.RequestHandler[] + requestOptions: ifm.RequestOptions | undefined + + private _ignoreSslError = false + private _socketTimeout: number | undefined + private _allowRedirects = true + private _allowRedirectDowngrade = false + private _maxRedirects = 50 + private _allowRetries = false + private _maxRetries = 1 + private _agent: any + private _proxyAgent: any + private _keepAlive = false + private _disposed = false + + constructor( + userAgent?: string, + handlers?: ifm.RequestHandler[], + requestOptions?: ifm.RequestOptions + ) { + this.userAgent = userAgent + this.handlers = handlers || [] + this.requestOptions = requestOptions + if (requestOptions) { + if (requestOptions.ignoreSslError != null) { + this._ignoreSslError = requestOptions.ignoreSslError + } + + this._socketTimeout = requestOptions.socketTimeout + + if (requestOptions.allowRedirects != null) { + this._allowRedirects = requestOptions.allowRedirects + } + + if (requestOptions.allowRedirectDowngrade != null) { + this._allowRedirectDowngrade = requestOptions.allowRedirectDowngrade + } + + if (requestOptions.maxRedirects != null) { + this._maxRedirects = Math.max(requestOptions.maxRedirects, 0) + } + + if (requestOptions.keepAlive != null) { + this._keepAlive = requestOptions.keepAlive + } + + if (requestOptions.allowRetries != null) { + this._allowRetries = requestOptions.allowRetries + } + + if (requestOptions.maxRetries != null) { + this._maxRetries = requestOptions.maxRetries + } + } + } + + async options( + requestUrl: string, + additionalHeaders?: http.OutgoingHttpHeaders + ): Promise { + return this.request('OPTIONS', requestUrl, null, additionalHeaders || {}) + } + + async get( + requestUrl: string, + additionalHeaders?: http.OutgoingHttpHeaders + ): Promise { + return this.request('GET', requestUrl, null, additionalHeaders || {}) + } + + async del( + requestUrl: string, + additionalHeaders?: http.OutgoingHttpHeaders + ): Promise { + return this.request('DELETE', requestUrl, null, additionalHeaders || {}) + } + + async post( + requestUrl: string, + data: string, + additionalHeaders?: http.OutgoingHttpHeaders + ): Promise { + return this.request('POST', requestUrl, data, additionalHeaders || {}) + } + + async patch( + requestUrl: string, + data: string, + additionalHeaders?: http.OutgoingHttpHeaders + ): Promise { + return this.request('PATCH', requestUrl, data, additionalHeaders || {}) + } + + async put( + requestUrl: string, + data: string, + additionalHeaders?: http.OutgoingHttpHeaders + ): Promise { + return this.request('PUT', requestUrl, data, additionalHeaders || {}) + } + + async head( + requestUrl: string, + additionalHeaders?: http.OutgoingHttpHeaders + ): Promise { + return this.request('HEAD', requestUrl, null, additionalHeaders || {}) + } + + async sendStream( + verb: string, + requestUrl: string, + stream: NodeJS.ReadableStream, + additionalHeaders?: http.OutgoingHttpHeaders + ): Promise { + return this.request(verb, requestUrl, stream, additionalHeaders) + } + + /** + * Gets a typed object from an endpoint + * Be aware that not found returns a null. Other errors (4xx, 5xx) reject the promise + */ + async getJson( + requestUrl: string, + additionalHeaders: http.OutgoingHttpHeaders = {} + ): Promise> { + additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader( + additionalHeaders, + Headers.Accept, + MediaTypes.ApplicationJson + ) + const res: HttpClientResponse = await this.get( + requestUrl, + additionalHeaders + ) + return this._processResponse(res, this.requestOptions) + } + + async postJson( + requestUrl: string, + obj: any, + additionalHeaders: http.OutgoingHttpHeaders = {} + ): Promise> { + const data: string = JSON.stringify(obj, null, 2) + additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader( + additionalHeaders, + Headers.Accept, + MediaTypes.ApplicationJson + ) + additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader( + additionalHeaders, + Headers.ContentType, + MediaTypes.ApplicationJson + ) + const res: HttpClientResponse = await this.post( + requestUrl, + data, + additionalHeaders + ) + return this._processResponse(res, this.requestOptions) + } + + async putJson( + requestUrl: string, + obj: any, + additionalHeaders: http.OutgoingHttpHeaders = {} + ): Promise> { + const data: string = JSON.stringify(obj, null, 2) + additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader( + additionalHeaders, + Headers.Accept, + MediaTypes.ApplicationJson + ) + additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader( + additionalHeaders, + Headers.ContentType, + MediaTypes.ApplicationJson + ) + const res: HttpClientResponse = await this.put( + requestUrl, + data, + additionalHeaders + ) + return this._processResponse(res, this.requestOptions) + } + + async patchJson( + requestUrl: string, + obj: any, + additionalHeaders: http.OutgoingHttpHeaders = {} + ): Promise> { + const data: string = JSON.stringify(obj, null, 2) + additionalHeaders[Headers.Accept] = this._getExistingOrDefaultHeader( + additionalHeaders, + Headers.Accept, + MediaTypes.ApplicationJson + ) + additionalHeaders[Headers.ContentType] = this._getExistingOrDefaultHeader( + additionalHeaders, + Headers.ContentType, + MediaTypes.ApplicationJson + ) + const res: HttpClientResponse = await this.patch( + requestUrl, + data, + additionalHeaders + ) + return this._processResponse(res, this.requestOptions) + } + + /** + * Makes a raw http request. + * All other methods such as get, post, patch, and request ultimately call this. + * Prefer get, del, post and patch + */ + async request( + verb: string, + requestUrl: string, + data: string | NodeJS.ReadableStream | null, + headers?: http.OutgoingHttpHeaders + ): Promise { + if (this._disposed) { + throw new Error('Client has already been disposed.') + } + + const parsedUrl = new URL(requestUrl) + let info: ifm.RequestInfo = this._prepareRequest(verb, parsedUrl, headers) + + // Only perform retries on reads since writes may not be idempotent. + const maxTries: number = + this._allowRetries && RetryableHttpVerbs.includes(verb) + ? this._maxRetries + 1 + : 1 + let numTries = 0 + + let response: HttpClientResponse | undefined + do { + response = await this.requestRaw(info, data) + + // Check if it's an authentication challenge + if ( + response && + response.message && + response.message.statusCode === HttpCodes.Unauthorized + ) { + let authenticationHandler: ifm.RequestHandler | undefined + + for (const handler of this.handlers) { + if (handler.canHandleAuthentication(response)) { + authenticationHandler = handler + break + } + } + + if (authenticationHandler) { + return authenticationHandler.handleAuthentication(this, info, data) + } else { + // We have received an unauthorized response but have no handlers to handle it. + // Let the response return to the caller. + return response + } + } + + let redirectsRemaining: number = this._maxRedirects + while ( + response.message.statusCode && + HttpRedirectCodes.includes(response.message.statusCode) && + this._allowRedirects && + redirectsRemaining > 0 + ) { + const redirectUrl: string | undefined = + response.message.headers['location'] + if (!redirectUrl) { + // if there's no location to redirect to, we won't + break + } + const parsedRedirectUrl = new URL(redirectUrl) + if ( + parsedUrl.protocol === 'https:' && + parsedUrl.protocol !== parsedRedirectUrl.protocol && + !this._allowRedirectDowngrade + ) { + throw new Error( + 'Redirect from HTTPS to HTTP protocol. This downgrade is not allowed for security reasons. If you want to allow this behavior, set the allowRedirectDowngrade option to true.' + ) + } + + // we need to finish reading the response before reassigning response + // which will leak the open socket. + await response.readBody() + + // strip authorization header if redirected to a different hostname + if (parsedRedirectUrl.hostname !== parsedUrl.hostname) { + for (const header in headers) { + // header names are case insensitive + if (header.toLowerCase() === 'authorization') { + delete headers[header] + } + } + } + + // let's make the request with the new redirectUrl + info = this._prepareRequest(verb, parsedRedirectUrl, headers) + response = await this.requestRaw(info, data) + redirectsRemaining-- + } + + if ( + !response.message.statusCode || + !HttpResponseRetryCodes.includes(response.message.statusCode) + ) { + // If not a retry code, return immediately instead of retrying + return response + } + + numTries += 1 + + if (numTries < maxTries) { + await response.readBody() + await this._performExponentialBackoff(numTries) + } + } while (numTries < maxTries) + + return response + } + + /** + * Needs to be called if keepAlive is set to true in request options. + */ + dispose(): void { + if (this._agent) { + this._agent.destroy() + } + + this._disposed = true + } + + /** + * Raw request. + * @param info + * @param data + */ + async requestRaw( + info: ifm.RequestInfo, + data: string | NodeJS.ReadableStream | null + ): Promise { + return new Promise((resolve, reject) => { + function callbackForResult(err?: Error, res?: HttpClientResponse): void { + if (err) { + reject(err) + } else if (!res) { + // If `err` is not passed, then `res` must be passed. + reject(new Error('Unknown error')) + } else { + resolve(res) + } + } + + this.requestRawWithCallback(info, data, callbackForResult) + }) + } + + /** + * Raw request with callback. + * @param info + * @param data + * @param onResult + */ + requestRawWithCallback( + info: ifm.RequestInfo, + data: string | NodeJS.ReadableStream | null, + onResult: (err?: Error, res?: HttpClientResponse) => void + ): void { + if (typeof data === 'string') { + if (!info.options.headers) { + info.options.headers = {} + } + info.options.headers['Content-Length'] = Buffer.byteLength(data, 'utf8') + } + + let callbackCalled = false + function handleResult(err?: Error, res?: HttpClientResponse): void { + if (!callbackCalled) { + callbackCalled = true + onResult(err, res) + } + } + + const req: http.ClientRequest = info.httpModule.request( + info.options, + (msg: http.IncomingMessage) => { + const res: HttpClientResponse = new HttpClientResponse(msg) + handleResult(undefined, res) + } + ) + + let socket: net.Socket + req.on('socket', sock => { + socket = sock + }) + + // If we ever get disconnected, we want the socket to timeout eventually + req.setTimeout(this._socketTimeout || 3 * 60000, () => { + if (socket) { + socket.end() + } + handleResult(new Error(`Request timeout: ${info.options.path}`)) + }) + + req.on('error', function(err) { + // err has statusCode property + // res should have headers + handleResult(err) + }) + + if (data && typeof data === 'string') { + req.write(data, 'utf8') + } + + if (data && typeof data !== 'string') { + data.on('close', function() { + req.end() + }) + + data.pipe(req) + } else { + req.end() + } + } + + /** + * Gets an http agent. This function is useful when you need an http agent that handles + * routing through a proxy server - depending upon the url and proxy environment variables. + * @param serverUrl The server URL where the request will be sent. For example, https://api.github.com + */ + getAgent(serverUrl: string): http.Agent { + const parsedUrl = new URL(serverUrl) + return this._getAgent(parsedUrl) + } + + private _prepareRequest( + method: string, + requestUrl: URL, + headers?: http.OutgoingHttpHeaders + ): ifm.RequestInfo { + const info: ifm.RequestInfo = {} + + info.parsedUrl = requestUrl + const usingSsl: boolean = info.parsedUrl.protocol === 'https:' + info.httpModule = usingSsl ? https : http + const defaultPort: number = usingSsl ? 443 : 80 + + info.options = {} + info.options.host = info.parsedUrl.hostname + info.options.port = info.parsedUrl.port + ? parseInt(info.parsedUrl.port) + : defaultPort + info.options.path = + (info.parsedUrl.pathname || '') + (info.parsedUrl.search || '') + info.options.method = method + info.options.headers = this._mergeHeaders(headers) + if (this.userAgent != null) { + info.options.headers['user-agent'] = this.userAgent + } + + info.options.agent = this._getAgent(info.parsedUrl) + + // gives handlers an opportunity to participate + if (this.handlers) { + for (const handler of this.handlers) { + handler.prepareRequest(info.options) + } + } + + return info + } + + private _mergeHeaders( + headers?: http.OutgoingHttpHeaders + ): http.OutgoingHttpHeaders { + if (this.requestOptions && this.requestOptions.headers) { + return Object.assign( + {}, + lowercaseKeys(this.requestOptions.headers), + lowercaseKeys(headers || {}) + ) + } + + return lowercaseKeys(headers || {}) + } + + private _getExistingOrDefaultHeader( + additionalHeaders: http.OutgoingHttpHeaders, + header: string, + _default: string + ): string | number | string[] { + let clientHeader: string | undefined + if (this.requestOptions && this.requestOptions.headers) { + clientHeader = lowercaseKeys(this.requestOptions.headers)[header] + } + return additionalHeaders[header] || clientHeader || _default + } + + private _getAgent(parsedUrl: URL): http.Agent { + let agent + const proxyUrl = pm.getProxyUrl(parsedUrl) + const useProxy = proxyUrl && proxyUrl.hostname + + if (this._keepAlive && useProxy) { + agent = this._proxyAgent + } + + if (this._keepAlive && !useProxy) { + agent = this._agent + } + + // if agent is already assigned use that agent. + if (agent) { + return agent + } + + const usingSsl = parsedUrl.protocol === 'https:' + let maxSockets = 100 + if (this.requestOptions) { + maxSockets = this.requestOptions.maxSockets || http.globalAgent.maxSockets + } + + // This is `useProxy` again, but we need to check `proxyURl` directly for TypeScripts's flow analysis. + if (proxyUrl && proxyUrl.hostname) { + const agentOptions = { + maxSockets, + keepAlive: this._keepAlive, + proxy: { + ...((proxyUrl.username || proxyUrl.password) && { + proxyAuth: `${proxyUrl.username}:${proxyUrl.password}` + }), + host: proxyUrl.hostname, + port: proxyUrl.port + } + } + + let tunnelAgent: Function + const overHttps = proxyUrl.protocol === 'https:' + if (usingSsl) { + tunnelAgent = overHttps ? tunnel.httpsOverHttps : tunnel.httpsOverHttp + } else { + tunnelAgent = overHttps ? tunnel.httpOverHttps : tunnel.httpOverHttp + } + + agent = tunnelAgent(agentOptions) + this._proxyAgent = agent + } + + // if reusing agent across request and tunneling agent isn't assigned create a new agent + if (this._keepAlive && !agent) { + const options = {keepAlive: this._keepAlive, maxSockets} + agent = usingSsl ? new https.Agent(options) : new http.Agent(options) + this._agent = agent + } + + // if not using private agent and tunnel agent isn't setup then use global agent + if (!agent) { + agent = usingSsl ? https.globalAgent : http.globalAgent + } + + if (usingSsl && this._ignoreSslError) { + // we don't want to set NODE_TLS_REJECT_UNAUTHORIZED=0 since that will affect request for entire process + // http.RequestOptions doesn't expose a way to modify RequestOptions.agent.options + // we have to cast it to any and change it directly + agent.options = Object.assign(agent.options || {}, { + rejectUnauthorized: false + }) + } + + return agent + } + + private async _performExponentialBackoff(retryNumber: number): Promise { + retryNumber = Math.min(ExponentialBackoffCeiling, retryNumber) + const ms: number = ExponentialBackoffTimeSlice * Math.pow(2, retryNumber) + return new Promise(resolve => setTimeout(() => resolve(), ms)) + } + + private async _processResponse( + res: HttpClientResponse, + options?: ifm.RequestOptions + ): Promise> { + return new Promise>(async (resolve, reject) => { + const statusCode = res.message.statusCode || 0 + + const response: ifm.TypedResponse = { + statusCode, + result: null, + headers: {} + } + + // not found leads to null obj returned + if (statusCode === HttpCodes.NotFound) { + resolve(response) + } + + // get the result from the body + + function dateTimeDeserializer(key: any, value: any): any { + if (typeof value === 'string') { + const a = new Date(value) + if (!isNaN(a.valueOf())) { + return a + } + } + + return value + } + + let obj: any + let contents: string | undefined + + try { + contents = await res.readBody() + if (contents && contents.length > 0) { + if (options && options.deserializeDates) { + obj = JSON.parse(contents, dateTimeDeserializer) + } else { + obj = JSON.parse(contents) + } + + response.result = obj + } + + response.headers = res.message.headers + } catch (err) { + // Invalid resource (contents not json); leaving result obj null + } + + // note that 3xx redirects are handled by the http layer. + if (statusCode > 299) { + let msg: string + + // if exception/error in body, attempt to get better error + if (obj && obj.message) { + msg = obj.message + } else if (contents && contents.length > 0) { + // it may be the case that the exception is in the body message as string + msg = contents + } else { + msg = `Failed request: (${statusCode})` + } + + const err = new HttpClientError(msg, statusCode) + err.result = response.result + + reject(err) + } else { + resolve(response) + } + }) + } +} + +const lowercaseKeys = (obj: {[index: string]: any}): any => + Object.keys(obj).reduce((c: any, k) => ((c[k.toLowerCase()] = obj[k]), c), {}) diff --git a/packages/http-client/src/interfaces.ts b/packages/http-client/src/interfaces.ts new file mode 100644 index 00000000..96b0fec7 --- /dev/null +++ b/packages/http-client/src/interfaces.ts @@ -0,0 +1,91 @@ +import * as http from 'http' +import * as https from 'https' +import {HttpClientResponse} from './index' + +export interface HttpClient { + options( + requestUrl: string, + additionalHeaders?: http.OutgoingHttpHeaders + ): Promise + get( + requestUrl: string, + additionalHeaders?: http.OutgoingHttpHeaders + ): Promise + del( + requestUrl: string, + additionalHeaders?: http.OutgoingHttpHeaders + ): Promise + post( + requestUrl: string, + data: string, + additionalHeaders?: http.OutgoingHttpHeaders + ): Promise + patch( + requestUrl: string, + data: string, + additionalHeaders?: http.OutgoingHttpHeaders + ): Promise + put( + requestUrl: string, + data: string, + additionalHeaders?: http.OutgoingHttpHeaders + ): Promise + sendStream( + verb: string, + requestUrl: string, + stream: NodeJS.ReadableStream, + additionalHeaders?: http.OutgoingHttpHeaders + ): Promise + request( + verb: string, + requestUrl: string, + data: string | NodeJS.ReadableStream, + headers: http.OutgoingHttpHeaders + ): Promise + requestRaw( + info: RequestInfo, + data: string | NodeJS.ReadableStream + ): Promise + requestRawWithCallback( + info: RequestInfo, + data: string | NodeJS.ReadableStream, + onResult: (err?: Error, res?: HttpClientResponse) => void + ): void +} + +export interface RequestHandler { + prepareRequest(options: http.RequestOptions): void + canHandleAuthentication(response: HttpClientResponse): boolean + handleAuthentication( + httpClient: HttpClient, + requestInfo: RequestInfo, + data: string | NodeJS.ReadableStream | null + ): Promise +} + +export interface RequestInfo { + options: http.RequestOptions + parsedUrl: URL + httpModule: typeof http | typeof https +} + +export interface RequestOptions { + headers?: http.OutgoingHttpHeaders + socketTimeout?: number + ignoreSslError?: boolean + allowRedirects?: boolean + allowRedirectDowngrade?: boolean + maxRedirects?: number + maxSockets?: number + keepAlive?: boolean + deserializeDates?: boolean + // Allows retries only on Read operations (since writes may not be idempotent) + allowRetries?: boolean + maxRetries?: number +} + +export interface TypedResponse { + statusCode: number + result: T | null + headers: http.IncomingHttpHeaders +} diff --git a/packages/http-client/src/proxy.ts b/packages/http-client/src/proxy.ts new file mode 100644 index 00000000..f13409b5 --- /dev/null +++ b/packages/http-client/src/proxy.ts @@ -0,0 +1,60 @@ +export function getProxyUrl(reqUrl: URL): URL | undefined { + const usingSsl = reqUrl.protocol === 'https:' + + if (checkBypass(reqUrl)) { + return undefined + } + + const proxyVar = (() => { + if (usingSsl) { + return process.env['https_proxy'] || process.env['HTTPS_PROXY'] + } else { + return process.env['http_proxy'] || process.env['HTTP_PROXY'] + } + })() + + if (proxyVar) { + return new URL(proxyVar) + } else { + return undefined + } +} + +export function checkBypass(reqUrl: URL): boolean { + if (!reqUrl.hostname) { + return false + } + + const noProxy = process.env['no_proxy'] || process.env['NO_PROXY'] || '' + if (!noProxy) { + return false + } + + // Determine the request port + let reqPort: number | undefined + if (reqUrl.port) { + reqPort = Number(reqUrl.port) + } else if (reqUrl.protocol === 'http:') { + reqPort = 80 + } else if (reqUrl.protocol === 'https:') { + reqPort = 443 + } + + // Format the request hostname and hostname with port + const upperReqHosts = [reqUrl.hostname.toUpperCase()] + if (typeof reqPort === 'number') { + upperReqHosts.push(`${upperReqHosts[0]}:${reqPort}`) + } + + // Compare request host against noproxy + for (const upperNoProxyItem of noProxy + .split(',') + .map(x => x.trim().toUpperCase()) + .filter(x => x)) { + if (upperReqHosts.some(x => x === upperNoProxyItem)) { + return true + } + } + + return false +} diff --git a/packages/http-client/tsconfig.json b/packages/http-client/tsconfig.json new file mode 100644 index 00000000..4abc2b1c --- /dev/null +++ b/packages/http-client/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./lib", + "rootDir": "./src", + "moduleResolution": "node" + }, + "include": [ + "./src" + ] +} \ No newline at end of file diff --git a/scripts/create-package b/scripts/create-package index ed38d73a..29d07feb 100755 --- a/scripts/create-package +++ b/scripts/create-package @@ -9,5 +9,5 @@ if [[ -z "$name" ]]; then exit 1 fi -lerna create @actions/$name -cp packages/toolkit/tsconfig.json packages/$name/tsconfig.json \ No newline at end of file +npx lerna create @actions/$name +cp packages/core/tsconfig.json packages/$name/tsconfig.json \ No newline at end of file From 3d29fb91d1fd414ad3cf8264d3ec028d92fb484c Mon Sep 17 00:00:00 2001 From: Rob Herley Date: Thu, 5 May 2022 17:29:20 +0000 Subject: [PATCH 2/9] sed 's/markdownSummary/summary/g' --- ...rkdown-summary.test.ts => summary.test.ts} | 84 +++++++++---------- packages/core/src/core.ts | 4 +- .../src/{markdown-summary.ts => summary.ts} | 72 ++++++++-------- 3 files changed, 77 insertions(+), 83 deletions(-) rename packages/core/__tests__/{markdown-summary.test.ts => summary.test.ts} (76%) rename packages/core/src/{markdown-summary.ts => summary.ts} (80%) diff --git a/packages/core/__tests__/markdown-summary.test.ts b/packages/core/__tests__/summary.test.ts similarity index 76% rename from packages/core/__tests__/markdown-summary.test.ts rename to packages/core/__tests__/summary.test.ts index d9b8ee5c..c13b0179 100644 --- a/packages/core/__tests__/markdown-summary.test.ts +++ b/packages/core/__tests__/summary.test.ts @@ -1,9 +1,10 @@ import * as fs from 'fs' import * as os from 'os' import path from 'path' -import {markdownSummary, SUMMARY_ENV_VAR} from '../src/markdown-summary' +import {summary, SUMMARY_ENV_VAR} from '../src/summary' -const testFilePath = path.join(__dirname, 'test', 'test-summary.md') +const testDirectoryPath = path.join(__dirname, 'test') +const testFilePath = path.join(testDirectoryPath, 'test-summary.md') async function assertSummary(expected: string): Promise { const file = await fs.promises.readFile(testFilePath, {encoding: 'utf8'}) @@ -67,11 +68,12 @@ const fixtures = { } } -describe('@actions/core/src/markdown-summary', () => { +describe('@actions/core/src/summary', () => { beforeEach(async () => { process.env[SUMMARY_ENV_VAR] = testFilePath + await fs.promises.mkdir(testDirectoryPath, {recursive: true}) await fs.promises.writeFile(testFilePath, '', {encoding: 'utf8'}) - markdownSummary.emptyBuffer() + summary.emptyBuffer() }) afterAll(async () => { @@ -80,39 +82,39 @@ describe('@actions/core/src/markdown-summary', () => { it('throws if summary env var is undefined', async () => { process.env[SUMMARY_ENV_VAR] = undefined - const write = markdownSummary.addRaw(fixtures.text).write() + const write = summary.addRaw(fixtures.text).write() await expect(write).rejects.toThrow() }) it('throws if summary file does not exist', async () => { await fs.promises.unlink(testFilePath) - const write = markdownSummary.addRaw(fixtures.text).write() + const write = summary.addRaw(fixtures.text).write() await expect(write).rejects.toThrow() }) it('appends text to summary file', async () => { await fs.promises.writeFile(testFilePath, '# ', {encoding: 'utf8'}) - await markdownSummary.addRaw(fixtures.text).write() + await summary.addRaw(fixtures.text).write() await assertSummary(`# ${fixtures.text}`) }) it('overwrites text to summary file', async () => { await fs.promises.writeFile(testFilePath, 'overwrite', {encoding: 'utf8'}) - await markdownSummary.addRaw(fixtures.text).write({overwrite: true}) + await summary.addRaw(fixtures.text).write({overwrite: true}) await assertSummary(fixtures.text) }) it('appends text with EOL to summary file', async () => { await fs.promises.writeFile(testFilePath, '# ', {encoding: 'utf8'}) - await markdownSummary.addRaw(fixtures.text, true).write() + await summary.addRaw(fixtures.text, true).write() await assertSummary(`# ${fixtures.text}${os.EOL}`) }) it('chains appends text to summary file', async () => { await fs.promises.writeFile(testFilePath, '', {encoding: 'utf8'}) - await markdownSummary + await summary .addRaw(fixtures.text) .addRaw(fixtures.text) .addRaw(fixtures.text) @@ -122,33 +124,33 @@ describe('@actions/core/src/markdown-summary', () => { it('empties buffer after write', async () => { await fs.promises.writeFile(testFilePath, '', {encoding: 'utf8'}) - await markdownSummary.addRaw(fixtures.text).write() + await summary.addRaw(fixtures.text).write() await assertSummary(fixtures.text) - expect(markdownSummary.isEmptyBuffer()).toBe(true) + expect(summary.isEmptyBuffer()).toBe(true) }) it('returns summary buffer as string', () => { - markdownSummary.addRaw(fixtures.text) - expect(markdownSummary.stringify()).toEqual(fixtures.text) + summary.addRaw(fixtures.text) + expect(summary.stringify()).toEqual(fixtures.text) }) it('return correct values for isEmptyBuffer', () => { - markdownSummary.addRaw(fixtures.text) - expect(markdownSummary.isEmptyBuffer()).toBe(false) + summary.addRaw(fixtures.text) + expect(summary.isEmptyBuffer()).toBe(false) - markdownSummary.emptyBuffer() - expect(markdownSummary.isEmptyBuffer()).toBe(true) + summary.emptyBuffer() + expect(summary.isEmptyBuffer()).toBe(true) }) it('clears a buffer and summary file', async () => { await fs.promises.writeFile(testFilePath, 'content', {encoding: 'utf8'}) - await markdownSummary.clear() + await summary.clear() await assertSummary('') - expect(markdownSummary.isEmptyBuffer()).toBe(true) + expect(summary.isEmptyBuffer()).toBe(true) }) it('adds EOL', async () => { - await markdownSummary + await summary .addRaw(fixtures.text) .addEOL() .write() @@ -156,37 +158,37 @@ describe('@actions/core/src/markdown-summary', () => { }) it('adds a code block without language', async () => { - await markdownSummary.addCodeBlock(fixtures.code).write() + await summary.addCodeBlock(fixtures.code).write() const expected = `
func fork() {\n  for {\n    go fork()\n  }\n}
${os.EOL}` await assertSummary(expected) }) it('adds a code block with a language', async () => { - await markdownSummary.addCodeBlock(fixtures.code, 'go').write() + await summary.addCodeBlock(fixtures.code, 'go').write() const expected = `
func fork() {\n  for {\n    go fork()\n  }\n}
${os.EOL}` await assertSummary(expected) }) it('adds an unordered list', async () => { - await markdownSummary.addList(fixtures.list).write() + await summary.addList(fixtures.list).write() const expected = `
  • foo
  • bar
  • baz
  • 💣
${os.EOL}` await assertSummary(expected) }) it('adds an ordered list', async () => { - await markdownSummary.addList(fixtures.list, true).write() + await summary.addList(fixtures.list, true).write() const expected = `
  1. foo
  2. bar
  3. baz
  4. 💣
${os.EOL}` await assertSummary(expected) }) it('adds a table', async () => { - await markdownSummary.addTable(fixtures.table).write() + await summary.addTable(fixtures.table).write() const expected = `
foobarbaztall
onetwothree
wide
${os.EOL}` await assertSummary(expected) }) it('adds a details element', async () => { - await markdownSummary + await summary .addDetails(fixtures.details.label, fixtures.details.content) .write() const expected = `
open me🎉 surprise
${os.EOL}` @@ -194,13 +196,13 @@ describe('@actions/core/src/markdown-summary', () => { }) it('adds an image with alt text', async () => { - await markdownSummary.addImage(fixtures.img.src, fixtures.img.alt).write() + await summary.addImage(fixtures.img.src, fixtures.img.alt).write() const expected = `actions logo${os.EOL}` await assertSummary(expected) }) it('adds an image with custom dimensions', async () => { - await markdownSummary + await summary .addImage(fixtures.img.src, fixtures.img.alt, fixtures.img.options) .write() const expected = `actions logo${os.EOL}` @@ -208,7 +210,7 @@ describe('@actions/core/src/markdown-summary', () => { }) it('adds an image with custom dimensions', async () => { - await markdownSummary + await summary .addImage(fixtures.img.src, fixtures.img.alt, fixtures.img.options) .write() const expected = `actions logo${os.EOL}` @@ -217,21 +219,21 @@ describe('@actions/core/src/markdown-summary', () => { it('adds headings h1...h6', async () => { for (const i of [1, 2, 3, 4, 5, 6]) { - markdownSummary.addHeading('heading', i) + summary.addHeading('heading', i) } - await markdownSummary.write() + await summary.write() const expected = `

heading

${os.EOL}

heading

${os.EOL}

heading

${os.EOL}

heading

${os.EOL}
heading
${os.EOL}
heading
${os.EOL}` await assertSummary(expected) }) it('adds h1 if heading level not specified', async () => { - await markdownSummary.addHeading('heading').write() + await summary.addHeading('heading').write() const expected = `

heading

${os.EOL}` await assertSummary(expected) }) it('uses h1 if heading level is garbage or out of range', async () => { - await markdownSummary + await summary .addHeading('heading', 'foobar') .addHeading('heading', 1337) .addHeading('heading', -1) @@ -242,35 +244,31 @@ describe('@actions/core/src/markdown-summary', () => { }) it('adds a separator', async () => { - await markdownSummary.addSeparator().write() + await summary.addSeparator().write() const expected = `
${os.EOL}` await assertSummary(expected) }) it('adds a break', async () => { - await markdownSummary.addBreak().write() + await summary.addBreak().write() const expected = `
${os.EOL}` await assertSummary(expected) }) it('adds a quote', async () => { - await markdownSummary.addQuote(fixtures.quote.text).write() + await summary.addQuote(fixtures.quote.text).write() const expected = `
Where the world builds software
${os.EOL}` await assertSummary(expected) }) it('adds a quote with citation', async () => { - await markdownSummary - .addQuote(fixtures.quote.text, fixtures.quote.cite) - .write() + await summary.addQuote(fixtures.quote.text, fixtures.quote.cite).write() const expected = `
Where the world builds software
${os.EOL}` await assertSummary(expected) }) it('adds a link with href', async () => { - await markdownSummary - .addLink(fixtures.link.text, fixtures.link.href) - .write() + await summary.addLink(fixtures.link.text, fixtures.link.href).write() const expected = `GitHub${os.EOL}` await assertSummary(expected) }) diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index 8a9170ca..97073839 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -361,6 +361,6 @@ export async function getIDToken(aud?: string): Promise { } /** - * Markdown summary exports + * Summary exports */ -export {markdownSummary} from './markdown-summary' +export {summary} from './summary' diff --git a/packages/core/src/markdown-summary.ts b/packages/core/src/summary.ts similarity index 80% rename from packages/core/src/markdown-summary.ts rename to packages/core/src/summary.ts index 97d2d3ca..41db1de1 100644 --- a/packages/core/src/markdown-summary.ts +++ b/packages/core/src/summary.ts @@ -4,7 +4,7 @@ const {access, appendFile, writeFile} = promises export const SUMMARY_ENV_VAR = 'GITHUB_STEP_SUMMARY' export const SUMMARY_DOCS_URL = - 'https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-markdown-summary' + 'https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-job-summary' export type SummaryTableRow = (SummaryTableCell | string)[] @@ -51,7 +51,7 @@ export interface SummaryWriteOptions { overwrite?: boolean } -class MarkdownSummary { +class Summary { private _buffer: string private _filePath?: string @@ -73,7 +73,7 @@ class MarkdownSummary { const pathFromEnv = process.env[SUMMARY_ENV_VAR] if (!pathFromEnv) { throw new Error( - `Unable to find environment variable for $${SUMMARY_ENV_VAR}. Check if your runtime environment supports markdown summaries.` + `Unable to find environment variable for $${SUMMARY_ENV_VAR}. Check if your runtime environment supports job summaries.` ) } @@ -119,9 +119,9 @@ class MarkdownSummary { * * @param {SummaryWriteOptions} [options] (optional) options for write operation * - * @returns {Promise} markdown summary instance + * @returns {Promise} summary instance */ - async write(options?: SummaryWriteOptions): Promise { + async write(options?: SummaryWriteOptions): Promise { const overwrite = !!options?.overwrite const filePath = await this.filePath() const writeFunc = overwrite ? writeFile : appendFile @@ -132,9 +132,9 @@ class MarkdownSummary { /** * Clears the summary buffer and wipes the summary file * - * @returns {MarkdownSummary} markdown summary instance + * @returns {Summary} summary instance */ - async clear(): Promise { + async clear(): Promise { return this.emptyBuffer().write({overwrite: true}) } @@ -159,9 +159,9 @@ class MarkdownSummary { /** * Resets the summary buffer without writing to summary file * - * @returns {MarkdownSummary} markdown summary instance + * @returns {Summary} summary instance */ - emptyBuffer(): MarkdownSummary { + emptyBuffer(): Summary { this._buffer = '' return this } @@ -172,9 +172,9 @@ class MarkdownSummary { * @param {string} text content to add * @param {boolean} [addEOL=false] (optional) append an EOL to the raw text (default: false) * - * @returns {MarkdownSummary} markdown summary instance + * @returns {Summary} summary instance */ - addRaw(text: string, addEOL = false): MarkdownSummary { + addRaw(text: string, addEOL = false): Summary { this._buffer += text return addEOL ? this.addEOL() : this } @@ -182,9 +182,9 @@ class MarkdownSummary { /** * Adds the operating system-specific end-of-line marker to the buffer * - * @returns {MarkdownSummary} markdown summary instance + * @returns {Summary} summary instance */ - addEOL(): MarkdownSummary { + addEOL(): Summary { return this.addRaw(EOL) } @@ -194,9 +194,9 @@ class MarkdownSummary { * @param {string} code content to render within fenced code block * @param {string} lang (optional) language to syntax highlight code * - * @returns {MarkdownSummary} markdown summary instance + * @returns {Summary} summary instance */ - addCodeBlock(code: string, lang?: string): MarkdownSummary { + addCodeBlock(code: string, lang?: string): Summary { const attrs = { ...(lang && {lang}) } @@ -210,9 +210,9 @@ class MarkdownSummary { * @param {string[]} items list of items to render * @param {boolean} [ordered=false] (optional) if the rendered list should be ordered or not (default: false) * - * @returns {MarkdownSummary} markdown summary instance + * @returns {Summary} summary instance */ - addList(items: string[], ordered = false): MarkdownSummary { + addList(items: string[], ordered = false): Summary { const tag = ordered ? 'ol' : 'ul' const listItems = items.map(item => this.wrap('li', item)).join('') const element = this.wrap(tag, listItems) @@ -224,9 +224,9 @@ class MarkdownSummary { * * @param {SummaryTableCell[]} rows table rows * - * @returns {MarkdownSummary} markdown summary instance + * @returns {Summary} summary instance */ - addTable(rows: SummaryTableRow[]): MarkdownSummary { + addTable(rows: SummaryTableRow[]): Summary { const tableBody = rows .map(row => { const cells = row @@ -260,9 +260,9 @@ class MarkdownSummary { * @param {string} label text for the closed state * @param {string} content collapsable content * - * @returns {MarkdownSummary} markdown summary instance + * @returns {Summary} summary instance */ - addDetails(label: string, content: string): MarkdownSummary { + addDetails(label: string, content: string): Summary { const element = this.wrap('details', this.wrap('summary', label) + content) return this.addRaw(element).addEOL() } @@ -274,13 +274,9 @@ class MarkdownSummary { * @param {string} alt text description of the image * @param {SummaryImageOptions} options (optional) addition image attributes * - * @returns {MarkdownSummary} markdown summary instance + * @returns {Summary} summary instance */ - addImage( - src: string, - alt: string, - options?: SummaryImageOptions - ): MarkdownSummary { + addImage(src: string, alt: string, options?: SummaryImageOptions): Summary { const {width, height} = options || {} const attrs = { ...(width && {width}), @@ -297,9 +293,9 @@ class MarkdownSummary { * @param {string} text heading text * @param {number | string} [level=1] (optional) the heading level, default: 1 * - * @returns {MarkdownSummary} markdown summary instance + * @returns {Summary} summary instance */ - addHeading(text: string, level?: number | string): MarkdownSummary { + addHeading(text: string, level?: number | string): Summary { const tag = `h${level}` const allowedTag = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(tag) ? tag @@ -311,9 +307,9 @@ class MarkdownSummary { /** * Adds an HTML thematic break (
) to the summary buffer * - * @returns {MarkdownSummary} markdown summary instance + * @returns {Summary} summary instance */ - addSeparator(): MarkdownSummary { + addSeparator(): Summary { const element = this.wrap('hr', null) return this.addRaw(element).addEOL() } @@ -321,9 +317,9 @@ class MarkdownSummary { /** * Adds an HTML line break (
) to the summary buffer * - * @returns {MarkdownSummary} markdown summary instance + * @returns {Summary} summary instance */ - addBreak(): MarkdownSummary { + addBreak(): Summary { const element = this.wrap('br', null) return this.addRaw(element).addEOL() } @@ -334,9 +330,9 @@ class MarkdownSummary { * @param {string} text quote text * @param {string} cite (optional) citation url * - * @returns {MarkdownSummary} markdown summary instance + * @returns {Summary} summary instance */ - addQuote(text: string, cite?: string): MarkdownSummary { + addQuote(text: string, cite?: string): Summary { const attrs = { ...(cite && {cite}) } @@ -350,13 +346,13 @@ class MarkdownSummary { * @param {string} text link text/content * @param {string} href hyperlink * - * @returns {MarkdownSummary} markdown summary instance + * @returns {Summary} summary instance */ - addLink(text: string, href: string): MarkdownSummary { + addLink(text: string, href: string): Summary { const element = this.wrap('a', text, {href}) return this.addRaw(element).addEOL() } } // singleton export -export const markdownSummary = new MarkdownSummary() +export const summary = new Summary() From 07242b37a49ef3c3704f429570b3c9e377b72ecb Mon Sep 17 00:00:00 2001 From: Rob Herley Date: Thu, 5 May 2022 19:44:13 +0000 Subject: [PATCH 3/9] add & deprecate old markdownSummary export --- packages/core/src/core.ts | 5 +++++ packages/core/src/summary.ts | 9 +++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/core/src/core.ts b/packages/core/src/core.ts index 97073839..f5e7941b 100644 --- a/packages/core/src/core.ts +++ b/packages/core/src/core.ts @@ -364,3 +364,8 @@ export async function getIDToken(aud?: string): Promise { * Summary exports */ export {summary} from './summary' + +/** + * @deprecated use core.summary + */ +export {markdownSummary} from './summary' diff --git a/packages/core/src/summary.ts b/packages/core/src/summary.ts index 41db1de1..015f2eea 100644 --- a/packages/core/src/summary.ts +++ b/packages/core/src/summary.ts @@ -354,5 +354,10 @@ class Summary { } } -// singleton export -export const summary = new Summary() +const _summary = new Summary() + +/** + * @deprecated use `core.summary` + */ +export const markdownSummary = _summary +export const summary = _summary From e73063a93c5d570d765a2b7aa9c77a538d28689c Mon Sep 17 00:00:00 2001 From: Rob Herley Date: Thu, 5 May 2022 20:17:30 +0000 Subject: [PATCH 4/9] @actions/core 1.8.0 release --- packages/core/RELEASES.md | 5 +++++ packages/core/package-lock.json | 2 +- packages/core/package.json | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/core/RELEASES.md b/packages/core/RELEASES.md index fa0c93ae..d35801ee 100644 --- a/packages/core/RELEASES.md +++ b/packages/core/RELEASES.md @@ -1,5 +1,10 @@ # @actions/core Releases +### 1.8.0 +- Deprecate `markdownSummary` extension export in favor of `summary` + - https://github.com/actions/toolkit/pull/1072 + - https://github.com/actions/toolkit/pull/1073 + ### 1.7.0 - [Added `markdownSummary` extension](https://github.com/actions/toolkit/pull/1014) diff --git a/packages/core/package-lock.json b/packages/core/package-lock.json index 9a638c5a..b4392f8d 100644 --- a/packages/core/package-lock.json +++ b/packages/core/package-lock.json @@ -1,6 +1,6 @@ { "name": "@actions/core", - "version": "1.7.0", + "version": "1.8.0", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/packages/core/package.json b/packages/core/package.json index 56ee8427..c63533fa 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@actions/core", - "version": "1.7.0", + "version": "1.8.0", "description": "Actions core lib", "keywords": [ "github", From aa676f3cc725685fdc6eef04a0c75342005f10db Mon Sep 17 00:00:00 2001 From: Brian Cristante <33549821+brcrista@users.noreply.github.com> Date: Wed, 11 May 2022 17:14:25 -0400 Subject: [PATCH 5/9] Update other packages to use http-client v2 (#1082) We moved `@actions/http-client` to be part of the toolkit in https://github.com/actions/toolkit/pull/1062. We also made some breaking changes to exported types and released v2. The biggest change in terms of lines of code affected was to get rid of the `I-` prefix for interfaces since TypeScript doesn't follow this convention. I bumped the patch version of all packages except for `tool-cache`, where I bumped the major version. The rationale is explained in the release notes for that package. --- packages/artifact/RELEASES.md | 6 +- packages/artifact/__tests__/retry.test.ts | 5 +- packages/artifact/package-lock.json | 44 ++++++---- packages/artifact/package.json | 4 +- .../src/internal/download-http-client.ts | 8 +- .../artifact/src/internal/http-manager.ts | 2 +- .../artifact/src/internal/requestUtils.ts | 12 +-- .../src/internal/upload-http-client.ts | 9 +- packages/artifact/src/internal/utils.ts | 19 ++--- packages/cache/RELEASES.md | 3 + packages/cache/__tests__/saveCache.test.ts | 8 +- packages/cache/package-lock.json | 63 +++++--------- packages/cache/package.json | 4 +- .../cache/src/internal/cacheHttpClient.ts | 13 +-- packages/cache/src/internal/contracts.d.ts | 4 +- packages/cache/src/internal/downloadUtils.ts | 5 +- packages/cache/src/internal/requestUtils.ts | 15 ++-- packages/core/RELEASES.md | 3 + packages/core/package-lock.json | 37 ++------ packages/core/package.json | 4 +- packages/core/src/oidc-utils.ts | 6 +- packages/github/RELEASES.md | 3 + packages/github/package-lock.json | 37 ++------ packages/github/package.json | 4 +- packages/glob/package-lock.json | 49 +++++++++-- packages/http-client/package.json | 2 +- packages/tool-cache/RELEASES.md | 5 ++ packages/tool-cache/package-lock.json | 84 +++++++++++-------- packages/tool-cache/package.json | 4 +- packages/tool-cache/src/tool-cache.ts | 10 +-- 30 files changed, 249 insertions(+), 223 deletions(-) diff --git a/packages/artifact/RELEASES.md b/packages/artifact/RELEASES.md index 8f3fd713..3d4425d8 100644 --- a/packages/artifact/RELEASES.md +++ b/packages/artifact/RELEASES.md @@ -77,4 +77,8 @@ ### 1.0.0 -- Update `lockfileVersion` to `v2` in `package-lock.json [#1009](https://github.com/actions/toolkit/pull/1009) \ No newline at end of file +- Update `lockfileVersion` to `v2` in `package-lock.json` [#1009](https://github.com/actions/toolkit/pull/1009) + +### 1.0.1 + +- Update to v2.0.0 of `@actions/http-client` \ No newline at end of file diff --git a/packages/artifact/__tests__/retry.test.ts b/packages/artifact/__tests__/retry.test.ts index 12c49784..d1e9256e 100644 --- a/packages/artifact/__tests__/retry.test.ts +++ b/packages/artifact/__tests__/retry.test.ts @@ -3,7 +3,6 @@ import * as net from 'net' import * as core from '@actions/core' import * as configVariables from '../src/internal/config-variables' import {retry} from '../src/internal/requestUtils' -import {IHttpClientResponse} from '@actions/http-client/interfaces' import {HttpClientResponse} from '@actions/http-client' jest.mock('../src/internal/config-variables') @@ -42,7 +41,7 @@ async function testRetry( async function handleResponse( testResponseCode: number | undefined -): Promise { +): Promise { if (!testResponseCode) { throw new Error( 'Test incorrectly set up. reverse.pop() was called too many times so not enough test response codes were supplied' @@ -72,7 +71,7 @@ async function emptyMockReadBody(): Promise { async function setupSingleMockResponse( statusCode: number -): Promise { +): Promise { const mockMessage = new http.IncomingMessage(new net.Socket()) const mockReadBody = emptyMockReadBody mockMessage.statusCode = statusCode diff --git a/packages/artifact/package-lock.json b/packages/artifact/package-lock.json index 7f5ec7d2..56e6a712 100644 --- a/packages/artifact/package-lock.json +++ b/packages/artifact/package-lock.json @@ -1,16 +1,16 @@ { "name": "@actions/artifact", - "version": "0.6.1", + "version": "1.0.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@actions/artifact", - "version": "0.6.1", + "version": "1.0.1", "license": "MIT", "dependencies": { "@actions/core": "^1.2.6", - "@actions/http-client": "^1.0.11", + "@actions/http-client": "^2.0.0", "tmp": "^0.2.1", "tmp-promise": "^3.0.2" }, @@ -20,14 +20,14 @@ } }, "node_modules/@actions/core": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.6.0.tgz", - "integrity": "sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.0.tgz", + "integrity": "sha512-XirM+Zo/PFlA+1h+i4bkfvagujta+LIM2AOSzPbt8JqXbbuxb1HTB+FqIyaKmue9yiCx/JIJY6pXsOl3+T8JGw==", "dependencies": { "@actions/http-client": "^1.0.11" } }, - "node_modules/@actions/http-client": { + "node_modules/@actions/core/node_modules/@actions/http-client": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz", "integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==", @@ -35,6 +35,11 @@ "tunnel": "0.0.6" } }, + "node_modules/@actions/http-client": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.0.tgz", + "integrity": "sha512-fm1+OPPey5ypgStT9K8zbBhICj4J4UV/TJIHDhuWlkb8KyJaAtjcZK184dTqul0dV0nPKX97FNtDXX20BTLXSA==" + }, "node_modules/@types/tmp": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.2.3.tgz", @@ -187,20 +192,27 @@ }, "dependencies": { "@actions/core": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.6.0.tgz", - "integrity": "sha512-NB1UAZomZlCV/LmJqkLhNTqtKfFXJZAUPcfl/zqG7EfsQdeUJtaWO98SGbuQ3pydJ3fHl2CvI/51OKYlCYYcaw==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.0.tgz", + "integrity": "sha512-XirM+Zo/PFlA+1h+i4bkfvagujta+LIM2AOSzPbt8JqXbbuxb1HTB+FqIyaKmue9yiCx/JIJY6pXsOl3+T8JGw==", "requires": { "@actions/http-client": "^1.0.11" + }, + "dependencies": { + "@actions/http-client": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz", + "integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==", + "requires": { + "tunnel": "0.0.6" + } + } } }, "@actions/http-client": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz", - "integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==", - "requires": { - "tunnel": "0.0.6" - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.0.tgz", + "integrity": "sha512-fm1+OPPey5ypgStT9K8zbBhICj4J4UV/TJIHDhuWlkb8KyJaAtjcZK184dTqul0dV0nPKX97FNtDXX20BTLXSA==" }, "@types/tmp": { "version": "0.2.3", diff --git a/packages/artifact/package.json b/packages/artifact/package.json index 6dd84aa2..64c51668 100644 --- a/packages/artifact/package.json +++ b/packages/artifact/package.json @@ -1,6 +1,6 @@ { "name": "@actions/artifact", - "version": "1.0.0", + "version": "1.0.1", "preview": true, "description": "Actions artifact lib", "keywords": [ @@ -38,7 +38,7 @@ }, "dependencies": { "@actions/core": "^1.2.6", - "@actions/http-client": "^1.0.11", + "@actions/http-client": "^2.0.0", "tmp": "^0.2.1", "tmp-promise": "^3.0.2" }, diff --git a/packages/artifact/src/internal/download-http-client.ts b/packages/artifact/src/internal/download-http-client.ts index c81ac917..2df4675f 100644 --- a/packages/artifact/src/internal/download-http-client.ts +++ b/packages/artifact/src/internal/download-http-client.ts @@ -18,7 +18,7 @@ import {URL} from 'url' import {StatusReporter} from './status-reporter' import {performance} from 'perf_hooks' import {ListArtifactsResponse, QueryArtifactResponse} from './contracts' -import {IHttpClientResponse} from '@actions/http-client/interfaces' +import {HttpClientResponse} from '@actions/http-client' import {HttpManager} from './http-manager' import {DownloadItem} from './download-specification' import {getDownloadFileConcurrency, getRetryLimit} from './config-variables' @@ -152,7 +152,7 @@ export class DownloadHttpClient { const headers = getDownloadHeaders('application/json', true, true) // a single GET request is used to download a file - const makeDownloadRequest = async (): Promise => { + const makeDownloadRequest = async (): Promise => { const client = this.downloadHttpManager.getClient(httpClientIndex) return await client.get(artifactLocation, headers) } @@ -225,7 +225,7 @@ export class DownloadHttpClient { // keep trying to download a file until a retry limit has been reached while (retryCount <= retryLimit) { - let response: IHttpClientResponse + let response: HttpClientResponse try { response = await makeDownloadRequest() } catch (error) { @@ -295,7 +295,7 @@ export class DownloadHttpClient { * @param isGzip a boolean denoting if the content is compressed using gzip and if we need to decode it */ async pipeResponseToFile( - response: IHttpClientResponse, + response: HttpClientResponse, destinationStream: fs.WriteStream, isGzip: boolean ): Promise { diff --git a/packages/artifact/src/internal/http-manager.ts b/packages/artifact/src/internal/http-manager.ts index 9c19a620..9b44fb85 100644 --- a/packages/artifact/src/internal/http-manager.ts +++ b/packages/artifact/src/internal/http-manager.ts @@ -1,4 +1,4 @@ -import {HttpClient} from '@actions/http-client/index' +import {HttpClient} from '@actions/http-client' import {createHttpClient} from './utils' /** diff --git a/packages/artifact/src/internal/requestUtils.ts b/packages/artifact/src/internal/requestUtils.ts index 65f40e7b..4abc5b03 100644 --- a/packages/artifact/src/internal/requestUtils.ts +++ b/packages/artifact/src/internal/requestUtils.ts @@ -1,4 +1,4 @@ -import {IHttpClientResponse} from '@actions/http-client/interfaces' +import {HttpClientResponse} from '@actions/http-client' import { isRetryableStatusCode, isSuccessStatusCode, @@ -11,11 +11,11 @@ import {getRetryLimit} from './config-variables' export async function retry( name: string, - operation: () => Promise, + operation: () => Promise, customErrorMessages: Map, maxAttempts: number -): Promise { - let response: IHttpClientResponse | undefined = undefined +): Promise { + let response: HttpClientResponse | undefined = undefined let statusCode: number | undefined = undefined let isRetryable = false let errorMessage = '' @@ -71,9 +71,9 @@ export async function retry( export async function retryHttpClientRequest( name: string, - method: () => Promise, + method: () => Promise, customErrorMessages: Map = new Map(), maxAttempts = getRetryLimit() -): Promise { +): Promise { return await retry(name, method, customErrorMessages, maxAttempts) } diff --git a/packages/artifact/src/internal/upload-http-client.ts b/packages/artifact/src/internal/upload-http-client.ts index 9892a42d..180466e7 100644 --- a/packages/artifact/src/internal/upload-http-client.ts +++ b/packages/artifact/src/internal/upload-http-client.ts @@ -31,8 +31,7 @@ import {promisify} from 'util' import {URL} from 'url' import {performance} from 'perf_hooks' import {StatusReporter} from './status-reporter' -import {HttpCodes} from '@actions/http-client' -import {IHttpClientResponse} from '@actions/http-client/interfaces' +import {HttpCodes, HttpClientResponse} from '@actions/http-client' import {HttpManager} from './http-manager' import {UploadSpecification} from './upload-specification' import {UploadOptions} from './upload-options' @@ -416,7 +415,7 @@ export class UploadHttpClient { getContentRange(start, end, uploadFileSize) ) - const uploadChunkRequest = async (): Promise => { + const uploadChunkRequest = async (): Promise => { const client = this.uploadHttpManager.getClient(httpClientIndex) return await client.sendStream('PUT', resourceUrl, openStream(), headers) } @@ -427,7 +426,7 @@ export class UploadHttpClient { // Increments the current retry count and then checks if the retry limit has been reached // If there have been too many retries, fail so the download stops const incrementAndCheckRetryLimit = ( - response?: IHttpClientResponse + response?: HttpClientResponse ): boolean => { retryCount++ if (retryCount > retryLimit) { @@ -464,7 +463,7 @@ export class UploadHttpClient { // allow for failed chunks to be retried multiple times while (retryCount <= retryLimit) { - let response: IHttpClientResponse + let response: HttpClientResponse try { response = await uploadChunkRequest() diff --git a/packages/artifact/src/internal/utils.ts b/packages/artifact/src/internal/utils.ts index f2b99f33..2f2883e7 100644 --- a/packages/artifact/src/internal/utils.ts +++ b/packages/artifact/src/internal/utils.ts @@ -1,9 +1,8 @@ -import {debug, info, warning} from '@actions/core' import {promises as fs} from 'fs' -import {HttpCodes, HttpClient} from '@actions/http-client' -import {BearerCredentialHandler} from '@actions/http-client/auth' -import {IHeaders, IHttpClientResponse} from '@actions/http-client/interfaces' -import {IncomingHttpHeaders} from 'http' +import {IncomingHttpHeaders, OutgoingHttpHeaders} from 'http' +import {debug, info, warning} from '@actions/core' +import {HttpCodes, HttpClient, HttpClientResponse} from '@actions/http-client' +import {BearerCredentialHandler} from '@actions/http-client/lib/auth' import { getRuntimeToken, getRuntimeUrl, @@ -139,8 +138,8 @@ export function getDownloadHeaders( contentType: string, isKeepAlive?: boolean, acceptGzip?: boolean -): IHeaders { - const requestOptions: IHeaders = {} +): OutgoingHttpHeaders { + const requestOptions: OutgoingHttpHeaders = {} if (contentType) { requestOptions['Content-Type'] = contentType @@ -181,8 +180,8 @@ export function getUploadHeaders( uncompressedLength?: number, contentLength?: number, contentRange?: string -): IHeaders { - const requestOptions: IHeaders = {} +): OutgoingHttpHeaders { + const requestOptions: OutgoingHttpHeaders = {} requestOptions['Accept'] = `application/json;api-version=${getApiVersion()}` if (contentType) { requestOptions['Content-Type'] = contentType @@ -227,7 +226,7 @@ export function getArtifactUrl(): string { * Certain information such as the TLSSocket and the Readable state are not really useful for diagnostic purposes so they can be avoided. * Other information such as the headers, the response code and message might be useful, so this is displayed. */ -export function displayHttpDiagnostics(response: IHttpClientResponse): void { +export function displayHttpDiagnostics(response: HttpClientResponse): void { info( `##### Begin Diagnostic HTTP information ##### Status Code: ${response.message.statusCode} diff --git a/packages/cache/RELEASES.md b/packages/cache/RELEASES.md index ec77c2bc..58217f86 100644 --- a/packages/cache/RELEASES.md +++ b/packages/cache/RELEASES.md @@ -56,3 +56,6 @@ ### 2.0.0 - Added support to check if Actions cache service feature is available or not [#1028](https://github.com/actions/toolkit/pull/1028) + +### 2.0.3 +- Update to v2.0.0 of `@actions/http-client` \ No newline at end of file diff --git a/packages/cache/__tests__/saveCache.test.ts b/packages/cache/__tests__/saveCache.test.ts index 6949759b..4627f2c7 100644 --- a/packages/cache/__tests__/saveCache.test.ts +++ b/packages/cache/__tests__/saveCache.test.ts @@ -5,7 +5,7 @@ import * as cacheHttpClient from '../src/internal/cacheHttpClient' import * as cacheUtils from '../src/internal/cacheUtils' import {CacheFilename, CompressionMethod} from '../src/internal/constants' import * as tar from '../src/internal/tar' -import {ITypedResponse} from '@actions/http-client/interfaces' +import {TypedResponse} from '@actions/http-client/lib/interfaces' import { ReserveCacheResponse, ITypedResponseWithError @@ -172,7 +172,7 @@ test('save with reserve cache failure should fail', async () => { const reserveCacheMock = jest .spyOn(cacheHttpClient, 'reserveCache') .mockImplementation(async () => { - const response: ITypedResponse = { + const response: TypedResponse = { statusCode: 500, result: null, headers: {} @@ -208,7 +208,7 @@ test('save with server error should fail', async () => { const reserveCacheMock = jest .spyOn(cacheHttpClient, 'reserveCache') .mockImplementation(async () => { - const response: ITypedResponse = { + const response: TypedResponse = { statusCode: 500, result: {cacheId}, headers: {} @@ -257,7 +257,7 @@ test('save with valid inputs uploads a cache', async () => { const reserveCacheMock = jest .spyOn(cacheHttpClient, 'reserveCache') .mockImplementation(async () => { - const response: ITypedResponse = { + const response: TypedResponse = { statusCode: 500, result: {cacheId}, headers: {} diff --git a/packages/cache/package-lock.json b/packages/cache/package-lock.json index 2ec7b7d6..d577d79f 100644 --- a/packages/cache/package-lock.json +++ b/packages/cache/package-lock.json @@ -1,18 +1,18 @@ { "name": "@actions/cache", - "version": "2.0.2", + "version": "2.0.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@actions/cache", - "version": "2.0.0", + "version": "2.0.3", "license": "MIT", "dependencies": { "@actions/core": "^1.2.6", "@actions/exec": "^1.0.1", "@actions/glob": "^0.1.0", - "@actions/http-client": "^1.0.9", + "@actions/http-client": "^2.0.0", "@actions/io": "^1.0.1", "@azure/ms-rest-js": "^2.6.0", "@azure/storage-blob": "^12.8.0", @@ -31,9 +31,9 @@ "integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA==" }, "node_modules/@actions/exec": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.0.4.tgz", - "integrity": "sha512-4DPChWow9yc9W3WqEbUj8Nr86xkpyE29ZzWjXucHItclLbEW6jr80Zx4nqv18QL6KK65+cifiQZXvnqgTV6oHw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", + "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", "dependencies": { "@actions/io": "^1.0.1" } @@ -48,25 +48,14 @@ } }, "node_modules/@actions/http-client": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.9.tgz", - "integrity": "sha512-0O4SsJ7q+MK0ycvXPl2e6bMXV7dxAXOGjrXS1eTF9s2S401Tp6c/P3c3Joz04QefC1J6Gt942Wl2jbm3f4mLcg==", - "dependencies": { - "tunnel": "0.0.6" - } - }, - "node_modules/@actions/http-client/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" - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.0.tgz", + "integrity": "sha512-fm1+OPPey5ypgStT9K8zbBhICj4J4UV/TJIHDhuWlkb8KyJaAtjcZK184dTqul0dV0nPKX97FNtDXX20BTLXSA==" }, "node_modules/@actions/io": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.0.2.tgz", - "integrity": "sha512-J8KuFqVPr3p6U8W93DOXlXW6zFvrQAJANdS+vw0YhusLIq+bszW8zmK2Fh1C2kDPX8FMvwIl1OUcFgvJoXLbAg==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.2.tgz", + "integrity": "sha512-d+RwPlMp+2qmBfeLYPLXuSRykDIFEwdTA0MMxzS9kh4kvP1ftrc/9fzy6pX6qAjthdXruHQ6/6kjT/DNo5ALuw==" }, "node_modules/@azure/abort-controller": { "version": "1.0.4", @@ -618,9 +607,9 @@ "integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA==" }, "@actions/exec": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.0.4.tgz", - "integrity": "sha512-4DPChWow9yc9W3WqEbUj8Nr86xkpyE29ZzWjXucHItclLbEW6jr80Zx4nqv18QL6KK65+cifiQZXvnqgTV6oHw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", + "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", "requires": { "@actions/io": "^1.0.1" } @@ -635,24 +624,14 @@ } }, "@actions/http-client": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.9.tgz", - "integrity": "sha512-0O4SsJ7q+MK0ycvXPl2e6bMXV7dxAXOGjrXS1eTF9s2S401Tp6c/P3c3Joz04QefC1J6Gt942Wl2jbm3f4mLcg==", - "requires": { - "tunnel": "0.0.6" - }, - "dependencies": { - "tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" - } - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.0.tgz", + "integrity": "sha512-fm1+OPPey5ypgStT9K8zbBhICj4J4UV/TJIHDhuWlkb8KyJaAtjcZK184dTqul0dV0nPKX97FNtDXX20BTLXSA==" }, "@actions/io": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.0.2.tgz", - "integrity": "sha512-J8KuFqVPr3p6U8W93DOXlXW6zFvrQAJANdS+vw0YhusLIq+bszW8zmK2Fh1C2kDPX8FMvwIl1OUcFgvJoXLbAg==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.2.tgz", + "integrity": "sha512-d+RwPlMp+2qmBfeLYPLXuSRykDIFEwdTA0MMxzS9kh4kvP1ftrc/9fzy6pX6qAjthdXruHQ6/6kjT/DNo5ALuw==" }, "@azure/abort-controller": { "version": "1.0.4", diff --git a/packages/cache/package.json b/packages/cache/package.json index 97f774b1..1185abed 100644 --- a/packages/cache/package.json +++ b/packages/cache/package.json @@ -1,6 +1,6 @@ { "name": "@actions/cache", - "version": "2.0.2", + "version": "2.0.3", "preview": true, "description": "Actions cache lib", "keywords": [ @@ -40,7 +40,7 @@ "@actions/core": "^1.2.6", "@actions/exec": "^1.0.1", "@actions/glob": "^0.1.0", - "@actions/http-client": "^1.0.9", + "@actions/http-client": "^2.0.0", "@actions/io": "^1.0.1", "@azure/ms-rest-js": "^2.6.0", "@azure/storage-blob": "^12.8.0", diff --git a/packages/cache/src/internal/cacheHttpClient.ts b/packages/cache/src/internal/cacheHttpClient.ts index 21f69917..c66d1a73 100644 --- a/packages/cache/src/internal/cacheHttpClient.ts +++ b/packages/cache/src/internal/cacheHttpClient.ts @@ -1,7 +1,10 @@ import * as core from '@actions/core' import {HttpClient} from '@actions/http-client' -import {BearerCredentialHandler} from '@actions/http-client/auth' -import {IRequestOptions, ITypedResponse} from '@actions/http-client/interfaces' +import {BearerCredentialHandler} from '@actions/http-client/lib/auth' +import { + RequestOptions, + TypedResponse +} from '@actions/http-client/lib/interfaces' import * as crypto from 'crypto' import * as fs from 'fs' import {URL} from 'url' @@ -46,8 +49,8 @@ function createAcceptHeader(type: string, apiVersion: string): string { return `${type};api-version=${apiVersion}` } -function getRequestOptions(): IRequestOptions { - const requestOptions: IRequestOptions = { +function getRequestOptions(): RequestOptions { + const requestOptions: RequestOptions = { headers: { Accept: createAcceptHeader('application/json', '6.0-preview.1') } @@ -275,7 +278,7 @@ async function commitCache( httpClient: HttpClient, cacheId: number, filesize: number -): Promise> { +): Promise> { const commitCacheRequest: CommitCacheRequest = {size: filesize} return await retryTypedResponse('commitCache', async () => httpClient.postJson( diff --git a/packages/cache/src/internal/contracts.d.ts b/packages/cache/src/internal/contracts.d.ts index eb79fdae..1b2a13a1 100644 --- a/packages/cache/src/internal/contracts.d.ts +++ b/packages/cache/src/internal/contracts.d.ts @@ -1,8 +1,8 @@ import {CompressionMethod} from './constants' -import {ITypedResponse} from '@actions/http-client/interfaces' +import {TypedResponse} from '@actions/http-client/lib/interfaces' import {HttpClientError} from '@actions/http-client' -export interface ITypedResponseWithError extends ITypedResponse { +export interface ITypedResponseWithError extends TypedResponse { error?: HttpClientError } diff --git a/packages/cache/src/internal/downloadUtils.ts b/packages/cache/src/internal/downloadUtils.ts index bedaa375..08b2dee8 100644 --- a/packages/cache/src/internal/downloadUtils.ts +++ b/packages/cache/src/internal/downloadUtils.ts @@ -1,6 +1,5 @@ import * as core from '@actions/core' -import {HttpClient} from '@actions/http-client' -import {IHttpClientResponse} from '@actions/http-client/interfaces' +import {HttpClient, HttpClientResponse} from '@actions/http-client' import {BlockBlobClient} from '@azure/storage-blob' import {TransferProgressEvent} from '@azure/ms-rest-js' import * as buffer from 'buffer' @@ -20,7 +19,7 @@ import {retryHttpClientResponse} from './requestUtils' * @param output the writable stream */ async function pipeResponseToStream( - response: IHttpClientResponse, + response: HttpClientResponse, output: NodeJS.WritableStream ): Promise { const pipeline = util.promisify(stream.pipeline) diff --git a/packages/cache/src/internal/requestUtils.ts b/packages/cache/src/internal/requestUtils.ts index be254b93..043c8a7c 100644 --- a/packages/cache/src/internal/requestUtils.ts +++ b/packages/cache/src/internal/requestUtils.ts @@ -1,6 +1,9 @@ import * as core from '@actions/core' -import {HttpCodes, HttpClientError} from '@actions/http-client' -import {IHttpClientResponse} from '@actions/http-client/interfaces' +import { + HttpCodes, + HttpClientError, + HttpClientResponse +} from '@actions/http-client' import {DefaultRetryDelay, DefaultRetryAttempts} from './constants' import {ITypedResponseWithError} from './contracts' @@ -103,7 +106,7 @@ export async function retryTypedResponse( maxAttempts, delay, // If the error object contains the statusCode property, extract it and return - // an ITypedResponse so it can be processed by the retry logic. + // an TypedResponse so it can be processed by the retry logic. (error: Error) => { if (error instanceof HttpClientError) { return { @@ -121,14 +124,14 @@ export async function retryTypedResponse( export async function retryHttpClientResponse( name: string, - method: () => Promise, + method: () => Promise, maxAttempts = DefaultRetryAttempts, delay = DefaultRetryDelay -): Promise { +): Promise { return await retry( name, method, - (response: IHttpClientResponse) => response.message.statusCode, + (response: HttpClientResponse) => response.message.statusCode, maxAttempts, delay ) diff --git a/packages/core/RELEASES.md b/packages/core/RELEASES.md index d35801ee..2f00f0ce 100644 --- a/packages/core/RELEASES.md +++ b/packages/core/RELEASES.md @@ -1,5 +1,8 @@ # @actions/core Releases +### 1.8.1 +- Update to v2.0.0 of `@actions/http-client` + ### 1.8.0 - Deprecate `markdownSummary` extension export in favor of `summary` - https://github.com/actions/toolkit/pull/1072 diff --git a/packages/core/package-lock.json b/packages/core/package-lock.json index b4392f8d..cd2ff3ed 100644 --- a/packages/core/package-lock.json +++ b/packages/core/package-lock.json @@ -1,62 +1,43 @@ { "name": "@actions/core", - "version": "1.8.0", + "version": "1.8.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@actions/core", - "version": "1.6.0", + "version": "1.8.1", "license": "MIT", "dependencies": { - "@actions/http-client": "^1.0.11" + "@actions/http-client": "^2.0.0" }, "devDependencies": { "@types/node": "^12.0.2" } }, "node_modules/@actions/http-client": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz", - "integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==", - "dependencies": { - "tunnel": "0.0.6" - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.0.tgz", + "integrity": "sha512-fm1+OPPey5ypgStT9K8zbBhICj4J4UV/TJIHDhuWlkb8KyJaAtjcZK184dTqul0dV0nPKX97FNtDXX20BTLXSA==" }, "node_modules/@types/node": { "version": "12.0.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.2.tgz", "integrity": "sha512-5tabW/i+9mhrfEOUcLDu2xBPsHJ+X5Orqy9FKpale3SjDA17j5AEpYq5vfy3oAeAHGcvANRCO3NV3d2D6q3NiA==", "dev": true - }, - "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" - } } }, "dependencies": { "@actions/http-client": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz", - "integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==", - "requires": { - "tunnel": "0.0.6" - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.0.tgz", + "integrity": "sha512-fm1+OPPey5ypgStT9K8zbBhICj4J4UV/TJIHDhuWlkb8KyJaAtjcZK184dTqul0dV0nPKX97FNtDXX20BTLXSA==" }, "@types/node": { "version": "12.0.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.2.tgz", "integrity": "sha512-5tabW/i+9mhrfEOUcLDu2xBPsHJ+X5Orqy9FKpale3SjDA17j5AEpYq5vfy3oAeAHGcvANRCO3NV3d2D6q3NiA==", "dev": true - }, - "tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" } } } diff --git a/packages/core/package.json b/packages/core/package.json index c63533fa..cd914386 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@actions/core", - "version": "1.8.0", + "version": "1.8.1", "description": "Actions core lib", "keywords": [ "github", @@ -36,7 +36,7 @@ "url": "https://github.com/actions/toolkit/issues" }, "dependencies": { - "@actions/http-client": "^1.0.11" + "@actions/http-client": "^2.0.0" }, "devDependencies": { "@types/node": "^12.0.2" diff --git a/packages/core/src/oidc-utils.ts b/packages/core/src/oidc-utils.ts index e33da5f1..d490a3ce 100644 --- a/packages/core/src/oidc-utils.ts +++ b/packages/core/src/oidc-utils.ts @@ -1,8 +1,8 @@ /* eslint-disable @typescript-eslint/no-extraneous-class */ import * as actions_http_client from '@actions/http-client' -import {IRequestOptions} from '@actions/http-client/interfaces' +import {RequestOptions} from '@actions/http-client/lib/interfaces' import {HttpClient} from '@actions/http-client' -import {BearerCredentialHandler} from '@actions/http-client/auth' +import {BearerCredentialHandler} from '@actions/http-client/lib/auth' import {debug, setSecret} from './core' interface TokenResponse { value?: string @@ -13,7 +13,7 @@ export class OidcClient { allowRetry = true, maxRetry = 10 ): actions_http_client.HttpClient { - const requestOptions: IRequestOptions = { + const requestOptions: RequestOptions = { allowRetries: allowRetry, maxRetries: maxRetry } diff --git a/packages/github/RELEASES.md b/packages/github/RELEASES.md index 225953b5..abbca6f1 100644 --- a/packages/github/RELEASES.md +++ b/packages/github/RELEASES.md @@ -1,5 +1,8 @@ # @actions/github Releases +### 5.0.2 +- Update to v2.0.0 of `@actions/http-client` + ### 5.0.1 - [Update Octokit Dependencies](https://github.com/actions/toolkit/pull/1037) ### 5.0.0 diff --git a/packages/github/package-lock.json b/packages/github/package-lock.json index 0a497e0d..defa7724 100644 --- a/packages/github/package-lock.json +++ b/packages/github/package-lock.json @@ -1,15 +1,15 @@ { "name": "@actions/github", - "version": "5.0.1", + "version": "5.0.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@actions/github", - "version": "5.0.1", + "version": "5.0.2", "license": "MIT", "dependencies": { - "@actions/http-client": "^1.0.11", + "@actions/http-client": "^2.0.0", "@octokit/core": "^3.6.0", "@octokit/plugin-paginate-rest": "^2.17.0", "@octokit/plugin-rest-endpoint-methods": "^5.13.0" @@ -19,12 +19,9 @@ } }, "node_modules/@actions/http-client": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz", - "integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==", - "dependencies": { - "tunnel": "0.0.6" - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.0.tgz", + "integrity": "sha512-fm1+OPPey5ypgStT9K8zbBhICj4J4UV/TJIHDhuWlkb8KyJaAtjcZK184dTqul0dV0nPKX97FNtDXX20BTLXSA==" }, "node_modules/@octokit/auth-token": { "version": "2.4.5", @@ -340,14 +337,6 @@ "proxy": "bin/proxy.js" } }, - "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/universal-user-agent": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", @@ -361,12 +350,9 @@ }, "dependencies": { "@actions/http-client": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz", - "integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==", - "requires": { - "tunnel": "0.0.6" - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.0.tgz", + "integrity": "sha512-fm1+OPPey5ypgStT9K8zbBhICj4J4UV/TJIHDhuWlkb8KyJaAtjcZK184dTqul0dV0nPKX97FNtDXX20BTLXSA==" }, "@octokit/auth-token": { "version": "2.4.5", @@ -635,11 +621,6 @@ "debug": "^4.1.1" } }, - "tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" - }, "universal-user-agent": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", diff --git a/packages/github/package.json b/packages/github/package.json index 208b5a79..8ed6c424 100644 --- a/packages/github/package.json +++ b/packages/github/package.json @@ -1,6 +1,6 @@ { "name": "@actions/github", - "version": "5.0.1", + "version": "5.0.2", "description": "Actions github lib", "keywords": [ "github", @@ -38,7 +38,7 @@ "url": "https://github.com/actions/toolkit/issues" }, "dependencies": { - "@actions/http-client": "^1.0.11", + "@actions/http-client": "^2.0.0", "@octokit/core": "^3.6.0", "@octokit/plugin-paginate-rest": "^2.17.0", "@octokit/plugin-rest-endpoint-methods": "^5.13.0" diff --git a/packages/glob/package-lock.json b/packages/glob/package-lock.json index ee9a1739..0aee7b60 100644 --- a/packages/glob/package-lock.json +++ b/packages/glob/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "@actions/glob", - "version": "0.2.1", + "version": "0.3.0", "license": "MIT", "dependencies": { "@actions/core": "^1.2.6", @@ -14,9 +14,20 @@ } }, "node_modules/@actions/core": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.6.tgz", - "integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA==" + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.0.tgz", + "integrity": "sha512-XirM+Zo/PFlA+1h+i4bkfvagujta+LIM2AOSzPbt8JqXbbuxb1HTB+FqIyaKmue9yiCx/JIJY6pXsOl3+T8JGw==", + "dependencies": { + "@actions/http-client": "^1.0.11" + } + }, + "node_modules/@actions/http-client": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz", + "integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==", + "dependencies": { + "tunnel": "0.0.6" + } }, "node_modules/balanced-match": { "version": "1.0.0", @@ -47,13 +58,32 @@ "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" + } } }, "dependencies": { "@actions/core": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.6.tgz", - "integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA==" + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.0.tgz", + "integrity": "sha512-XirM+Zo/PFlA+1h+i4bkfvagujta+LIM2AOSzPbt8JqXbbuxb1HTB+FqIyaKmue9yiCx/JIJY6pXsOl3+T8JGw==", + "requires": { + "@actions/http-client": "^1.0.11" + } + }, + "@actions/http-client": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz", + "integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==", + "requires": { + "tunnel": "0.0.6" + } }, "balanced-match": { "version": "1.0.0", @@ -81,6 +111,11 @@ "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==" } } } diff --git a/packages/http-client/package.json b/packages/http-client/package.json index f9db7e77..ed4129c0 100644 --- a/packages/http-client/package.json +++ b/packages/http-client/package.json @@ -25,7 +25,7 @@ "repository": { "type": "git", "url": "git+https://github.com/actions/toolkit.git", - "directory": "packages/github" + "directory": "packages/http-client" }, "scripts": { "audit-moderate": "npm install && npm audit --json --audit-level=moderate > audit.json", diff --git a/packages/tool-cache/RELEASES.md b/packages/tool-cache/RELEASES.md index c613f183..8285cb22 100644 --- a/packages/tool-cache/RELEASES.md +++ b/packages/tool-cache/RELEASES.md @@ -1,5 +1,10 @@ # @actions/tool-cache Releases +### 2.0.0 +- Update to v2.0.0 of `@actions/http-client` +- The type of the `headers` parameter in the exported function `downloadTool` has been narrowed from `{ [header: string]: any }` to `{ [header: string]: number | string | string[] | undefined; }` (that is, `http.OutgoingHttpHeaders`). + This is strictly a compile-time change for TypeScript consumers. Previous attempts to use a header value of a type other than those now accepted would have resulted in an error at run time. + ### 1.7.2 - Update `lockfileVersion` to `v2` in `package-lock.json [#1025](https://github.com/actions/toolkit/pull/1025) diff --git a/packages/tool-cache/package-lock.json b/packages/tool-cache/package-lock.json index 524d1345..bb33ad7f 100644 --- a/packages/tool-cache/package-lock.json +++ b/packages/tool-cache/package-lock.json @@ -1,17 +1,17 @@ { "name": "@actions/tool-cache", - "version": "1.7.2", + "version": "2.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@actions/tool-cache", - "version": "1.7.2", + "version": "2.0.0", "license": "MIT", "dependencies": { "@actions/core": "^1.2.6", "@actions/exec": "^1.0.0", - "@actions/http-client": "^1.0.8", + "@actions/http-client": "^2.0.0", "@actions/io": "^1.1.1", "semver": "^6.1.0", "uuid": "^3.3.2" @@ -24,30 +24,38 @@ } }, "node_modules/@actions/core": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.6.tgz", - "integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA==" + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.0.tgz", + "integrity": "sha512-XirM+Zo/PFlA+1h+i4bkfvagujta+LIM2AOSzPbt8JqXbbuxb1HTB+FqIyaKmue9yiCx/JIJY6pXsOl3+T8JGw==", + "dependencies": { + "@actions/http-client": "^1.0.11" + } + }, + "node_modules/@actions/core/node_modules/@actions/http-client": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz", + "integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==", + "dependencies": { + "tunnel": "0.0.6" + } }, "node_modules/@actions/exec": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.0.3.tgz", - "integrity": "sha512-TogJGnueOmM7ntCi0ASTUj4LapRRtDfj57Ja4IhPmg2fls28uVOPbAn8N+JifaOumN2UG3oEO/Ixek2A4NcYSA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", + "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", "dependencies": { "@actions/io": "^1.0.1" } }, "node_modules/@actions/http-client": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.8.tgz", - "integrity": "sha512-G4JjJ6f9Hb3Zvejj+ewLLKLf99ZC+9v+yCxoYf9vSyH+WkzPLB2LuUtRMGNkooMqdugGBFStIKXOuvH1W+EctA==", - "dependencies": { - "tunnel": "0.0.6" - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.0.tgz", + "integrity": "sha512-fm1+OPPey5ypgStT9K8zbBhICj4J4UV/TJIHDhuWlkb8KyJaAtjcZK184dTqul0dV0nPKX97FNtDXX20BTLXSA==" }, "node_modules/@actions/io": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.1.tgz", - "integrity": "sha512-Qi4JoKXjmE0O67wAOH6y0n26QXhMKMFo7GD/4IXNVcrtLjUlGjGuVys6pQgwF3ArfGTQu0XpqaNr0YhED2RaRA==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.2.tgz", + "integrity": "sha512-d+RwPlMp+2qmBfeLYPLXuSRykDIFEwdTA0MMxzS9kh4kvP1ftrc/9fzy6pX6qAjthdXruHQ6/6kjT/DNo5ALuw==" }, "node_modules/@types/nock": { "version": "10.0.3", @@ -280,30 +288,40 @@ }, "dependencies": { "@actions/core": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.6.tgz", - "integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA==" + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.0.tgz", + "integrity": "sha512-XirM+Zo/PFlA+1h+i4bkfvagujta+LIM2AOSzPbt8JqXbbuxb1HTB+FqIyaKmue9yiCx/JIJY6pXsOl3+T8JGw==", + "requires": { + "@actions/http-client": "^1.0.11" + }, + "dependencies": { + "@actions/http-client": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.11.tgz", + "integrity": "sha512-VRYHGQV1rqnROJqdMvGUbY/Kn8vriQe/F9HR2AlYHzmKuM/p3kjNuXhmdBfcVgsvRWTz5C5XW5xvndZrVBuAYg==", + "requires": { + "tunnel": "0.0.6" + } + } + } }, "@actions/exec": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.0.3.tgz", - "integrity": "sha512-TogJGnueOmM7ntCi0ASTUj4LapRRtDfj57Ja4IhPmg2fls28uVOPbAn8N+JifaOumN2UG3oEO/Ixek2A4NcYSA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", + "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", "requires": { "@actions/io": "^1.0.1" } }, "@actions/http-client": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-1.0.8.tgz", - "integrity": "sha512-G4JjJ6f9Hb3Zvejj+ewLLKLf99ZC+9v+yCxoYf9vSyH+WkzPLB2LuUtRMGNkooMqdugGBFStIKXOuvH1W+EctA==", - "requires": { - "tunnel": "0.0.6" - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.0.tgz", + "integrity": "sha512-fm1+OPPey5ypgStT9K8zbBhICj4J4UV/TJIHDhuWlkb8KyJaAtjcZK184dTqul0dV0nPKX97FNtDXX20BTLXSA==" }, "@actions/io": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.1.tgz", - "integrity": "sha512-Qi4JoKXjmE0O67wAOH6y0n26QXhMKMFo7GD/4IXNVcrtLjUlGjGuVys6pQgwF3ArfGTQu0XpqaNr0YhED2RaRA==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.2.tgz", + "integrity": "sha512-d+RwPlMp+2qmBfeLYPLXuSRykDIFEwdTA0MMxzS9kh4kvP1ftrc/9fzy6pX6qAjthdXruHQ6/6kjT/DNo5ALuw==" }, "@types/nock": { "version": "10.0.3", diff --git a/packages/tool-cache/package.json b/packages/tool-cache/package.json index da75109d..7c48d91a 100644 --- a/packages/tool-cache/package.json +++ b/packages/tool-cache/package.json @@ -1,6 +1,6 @@ { "name": "@actions/tool-cache", - "version": "1.7.2", + "version": "2.0.0", "description": "Actions tool-cache lib", "keywords": [ "github", @@ -38,7 +38,7 @@ "dependencies": { "@actions/core": "^1.2.6", "@actions/exec": "^1.0.0", - "@actions/http-client": "^1.0.8", + "@actions/http-client": "^2.0.0", "@actions/io": "^1.1.1", "semver": "^6.1.0", "uuid": "^3.3.2" diff --git a/packages/tool-cache/src/tool-cache.ts b/packages/tool-cache/src/tool-cache.ts index 92fd519a..694d1252 100644 --- a/packages/tool-cache/src/tool-cache.ts +++ b/packages/tool-cache/src/tool-cache.ts @@ -8,12 +8,12 @@ import * as httpm from '@actions/http-client' import * as semver from 'semver' import * as stream from 'stream' import * as util from 'util' +import {ok} from 'assert' +import {OutgoingHttpHeaders} from 'http' import uuidV4 from 'uuid/v4' import {exec} from '@actions/exec/lib/exec' import {ExecOptions} from '@actions/exec/lib/interfaces' -import {ok} from 'assert' import {RetryHelper} from './retry-helper' -import {IHeaders} from '@actions/http-client/interfaces' export class HTTPError extends Error { constructor(readonly httpStatusCode: number | undefined) { @@ -39,7 +39,7 @@ export async function downloadTool( url: string, dest?: string, auth?: string, - headers?: IHeaders + headers?: OutgoingHttpHeaders ): Promise { dest = dest || path.join(_getTempDirectory(), uuidV4()) await io.mkdirP(path.dirname(dest)) @@ -82,7 +82,7 @@ async function downloadToolAttempt( url: string, dest: string, auth?: string, - headers?: IHeaders + headers?: OutgoingHttpHeaders ): Promise { if (fs.existsSync(dest)) { throw new Error(`Destination file path ${dest} already exists`) @@ -596,7 +596,7 @@ export async function getManifestFromRepo( const treeUrl = `https://api.github.com/repos/${owner}/${repo}/git/trees/${branch}` const http: httpm.HttpClient = new httpm.HttpClient('tool-cache') - const headers: IHeaders = {} + const headers: OutgoingHttpHeaders = {} if (auth) { core.debug('set auth') headers.authorization = auth From e48f1d0c542f4b4c2f7ca8a963e61a9462064077 Mon Sep 17 00:00:00 2001 From: Konrad Pabjan Date: Fri, 13 May 2022 10:19:06 -0400 Subject: [PATCH 6/9] Make tunnel a prod dependency for http-client (#1085) --- packages/http-client/package-lock.json | 10 +++++----- packages/http-client/package.json | 6 ++++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/http-client/package-lock.json b/packages/http-client/package-lock.json index 7a2f0f23..ed6d25ac 100644 --- a/packages/http-client/package-lock.json +++ b/packages/http-client/package-lock.json @@ -8,10 +8,12 @@ "name": "@actions/http-client", "version": "2.0.0", "license": "MIT", + "dependencies": { + "tunnel": "^0.0.6" + }, "devDependencies": { "@types/tunnel": "0.0.3", - "proxy": "^1.0.1", - "tunnel": "0.0.6" + "proxy": "^1.0.1" } }, "node_modules/@types/node": { @@ -182,7 +184,6 @@ "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", - "dev": true, "engines": { "node": ">=0.6.11 <=0.7.0 || >=0.7.3" } @@ -325,8 +326,7 @@ "tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", - "dev": true + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" } } } diff --git a/packages/http-client/package.json b/packages/http-client/package.json index ed4129c0..b140ac4a 100644 --- a/packages/http-client/package.json +++ b/packages/http-client/package.json @@ -40,7 +40,9 @@ }, "devDependencies": { "@types/tunnel": "0.0.3", - "proxy": "^1.0.1", - "tunnel": "0.0.6" + "proxy": "^1.0.1" + }, + "dependencies": { + "tunnel": "^0.0.6" } } From 2abc7c46f8ed6d554f3b2ac0c83cc8173f379808 Mon Sep 17 00:00:00 2001 From: Konrad Pabjan Date: Fri, 13 May 2022 10:29:29 -0400 Subject: [PATCH 7/9] Bump to version 2.0.1 (#1086) --- packages/http-client/RELEASES.md | 3 +++ packages/http-client/package-lock.json | 2 +- packages/http-client/package.json | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/http-client/RELEASES.md b/packages/http-client/RELEASES.md index a097a4e0..344555f9 100644 --- a/packages/http-client/RELEASES.md +++ b/packages/http-client/RELEASES.md @@ -1,5 +1,8 @@ ## Releases +## 2.0.1 +- Fix an issue with missing `tunnel` dependency [#1085](https://github.com/actions/toolkit/pull/1085) + ## 2.0.0 - The package is now compiled with TypeScript's [`strict` compiler setting](https://www.typescriptlang.org/tsconfig#strict). To comply with stricter rules: - Some exported types now include `| null` or `| undefined`, matching their actual behavior. diff --git a/packages/http-client/package-lock.json b/packages/http-client/package-lock.json index ed6d25ac..3c2c4e54 100644 --- a/packages/http-client/package-lock.json +++ b/packages/http-client/package-lock.json @@ -1,6 +1,6 @@ { "name": "@actions/http-client", - "version": "2.0.0", + "version": "2.0.1", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/packages/http-client/package.json b/packages/http-client/package.json index b140ac4a..c1de2213 100644 --- a/packages/http-client/package.json +++ b/packages/http-client/package.json @@ -1,6 +1,6 @@ { "name": "@actions/http-client", - "version": "2.0.0", + "version": "2.0.1", "description": "Actions Http Client", "keywords": [ "github", From 82efa3d28565ebe2aabe24fcea597e83a4b66d5f Mon Sep 17 00:00:00 2001 From: Konrad Pabjan Date: Fri, 13 May 2022 10:58:36 -0400 Subject: [PATCH 8/9] Bump @actions/http-client in all packages that use it (#1087) --- packages/artifact/package-lock.json | 20 ++++++++++------ packages/artifact/package.json | 2 +- packages/cache/package-lock.json | 20 ++++++++++------ packages/cache/package.json | 6 ++--- packages/core/package-lock.json | 33 +++++++++++++++++++++------ packages/core/package.json | 2 +- packages/github/package-lock.json | 33 +++++++++++++++++++++------ packages/github/package.json | 2 +- packages/tool-cache/package-lock.json | 20 ++++++++++------ packages/tool-cache/package.json | 2 +- 10 files changed, 98 insertions(+), 42 deletions(-) diff --git a/packages/artifact/package-lock.json b/packages/artifact/package-lock.json index 56e6a712..0740ed4d 100644 --- a/packages/artifact/package-lock.json +++ b/packages/artifact/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT", "dependencies": { "@actions/core": "^1.2.6", - "@actions/http-client": "^2.0.0", + "@actions/http-client": "^2.0.1", "tmp": "^0.2.1", "tmp-promise": "^3.0.2" }, @@ -36,9 +36,12 @@ } }, "node_modules/@actions/http-client": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.0.tgz", - "integrity": "sha512-fm1+OPPey5ypgStT9K8zbBhICj4J4UV/TJIHDhuWlkb8KyJaAtjcZK184dTqul0dV0nPKX97FNtDXX20BTLXSA==" + "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/@types/tmp": { "version": "0.2.3", @@ -210,9 +213,12 @@ } }, "@actions/http-client": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.0.tgz", - "integrity": "sha512-fm1+OPPey5ypgStT9K8zbBhICj4J4UV/TJIHDhuWlkb8KyJaAtjcZK184dTqul0dV0nPKX97FNtDXX20BTLXSA==" + "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" + } }, "@types/tmp": { "version": "0.2.3", diff --git a/packages/artifact/package.json b/packages/artifact/package.json index 64c51668..cb56c1a8 100644 --- a/packages/artifact/package.json +++ b/packages/artifact/package.json @@ -38,7 +38,7 @@ }, "dependencies": { "@actions/core": "^1.2.6", - "@actions/http-client": "^2.0.0", + "@actions/http-client": "^2.0.1", "tmp": "^0.2.1", "tmp-promise": "^3.0.2" }, diff --git a/packages/cache/package-lock.json b/packages/cache/package-lock.json index d577d79f..cdc4c5cd 100644 --- a/packages/cache/package-lock.json +++ b/packages/cache/package-lock.json @@ -12,7 +12,7 @@ "@actions/core": "^1.2.6", "@actions/exec": "^1.0.1", "@actions/glob": "^0.1.0", - "@actions/http-client": "^2.0.0", + "@actions/http-client": "^2.0.1", "@actions/io": "^1.0.1", "@azure/ms-rest-js": "^2.6.0", "@azure/storage-blob": "^12.8.0", @@ -48,9 +48,12 @@ } }, "node_modules/@actions/http-client": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.0.tgz", - "integrity": "sha512-fm1+OPPey5ypgStT9K8zbBhICj4J4UV/TJIHDhuWlkb8KyJaAtjcZK184dTqul0dV0nPKX97FNtDXX20BTLXSA==" + "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/@actions/io": { "version": "1.1.2", @@ -624,9 +627,12 @@ } }, "@actions/http-client": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.0.tgz", - "integrity": "sha512-fm1+OPPey5ypgStT9K8zbBhICj4J4UV/TJIHDhuWlkb8KyJaAtjcZK184dTqul0dV0nPKX97FNtDXX20BTLXSA==" + "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" + } }, "@actions/io": { "version": "1.1.2", diff --git a/packages/cache/package.json b/packages/cache/package.json index 1185abed..21bb683a 100644 --- a/packages/cache/package.json +++ b/packages/cache/package.json @@ -40,7 +40,7 @@ "@actions/core": "^1.2.6", "@actions/exec": "^1.0.1", "@actions/glob": "^0.1.0", - "@actions/http-client": "^2.0.0", + "@actions/http-client": "^2.0.1", "@actions/io": "^1.0.1", "@azure/ms-rest-js": "^2.6.0", "@azure/storage-blob": "^12.8.0", @@ -48,8 +48,8 @@ "uuid": "^3.3.3" }, "devDependencies": { - "typescript": "^3.8.3", "@types/semver": "^6.0.0", - "@types/uuid": "^3.4.5" + "@types/uuid": "^3.4.5", + "typescript": "^3.8.3" } } diff --git a/packages/core/package-lock.json b/packages/core/package-lock.json index cd2ff3ed..dcb996b1 100644 --- a/packages/core/package-lock.json +++ b/packages/core/package-lock.json @@ -9,35 +9,54 @@ "version": "1.8.1", "license": "MIT", "dependencies": { - "@actions/http-client": "^2.0.0" + "@actions/http-client": "^2.0.1" }, "devDependencies": { "@types/node": "^12.0.2" } }, "node_modules/@actions/http-client": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.0.tgz", - "integrity": "sha512-fm1+OPPey5ypgStT9K8zbBhICj4J4UV/TJIHDhuWlkb8KyJaAtjcZK184dTqul0dV0nPKX97FNtDXX20BTLXSA==" + "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/@types/node": { "version": "12.0.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.2.tgz", "integrity": "sha512-5tabW/i+9mhrfEOUcLDu2xBPsHJ+X5Orqy9FKpale3SjDA17j5AEpYq5vfy3oAeAHGcvANRCO3NV3d2D6q3NiA==", "dev": true + }, + "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" + } } }, "dependencies": { "@actions/http-client": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.0.tgz", - "integrity": "sha512-fm1+OPPey5ypgStT9K8zbBhICj4J4UV/TJIHDhuWlkb8KyJaAtjcZK184dTqul0dV0nPKX97FNtDXX20BTLXSA==" + "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" + } }, "@types/node": { "version": "12.0.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.2.tgz", "integrity": "sha512-5tabW/i+9mhrfEOUcLDu2xBPsHJ+X5Orqy9FKpale3SjDA17j5AEpYq5vfy3oAeAHGcvANRCO3NV3d2D6q3NiA==", "dev": true + }, + "tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" } } } diff --git a/packages/core/package.json b/packages/core/package.json index cd914386..8eefd72d 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -36,7 +36,7 @@ "url": "https://github.com/actions/toolkit/issues" }, "dependencies": { - "@actions/http-client": "^2.0.0" + "@actions/http-client": "^2.0.1" }, "devDependencies": { "@types/node": "^12.0.2" diff --git a/packages/github/package-lock.json b/packages/github/package-lock.json index defa7724..3e8992fb 100644 --- a/packages/github/package-lock.json +++ b/packages/github/package-lock.json @@ -9,7 +9,7 @@ "version": "5.0.2", "license": "MIT", "dependencies": { - "@actions/http-client": "^2.0.0", + "@actions/http-client": "^2.0.1", "@octokit/core": "^3.6.0", "@octokit/plugin-paginate-rest": "^2.17.0", "@octokit/plugin-rest-endpoint-methods": "^5.13.0" @@ -19,9 +19,12 @@ } }, "node_modules/@actions/http-client": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.0.tgz", - "integrity": "sha512-fm1+OPPey5ypgStT9K8zbBhICj4J4UV/TJIHDhuWlkb8KyJaAtjcZK184dTqul0dV0nPKX97FNtDXX20BTLXSA==" + "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/@octokit/auth-token": { "version": "2.4.5", @@ -337,6 +340,14 @@ "proxy": "bin/proxy.js" } }, + "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/universal-user-agent": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", @@ -350,9 +361,12 @@ }, "dependencies": { "@actions/http-client": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.0.tgz", - "integrity": "sha512-fm1+OPPey5ypgStT9K8zbBhICj4J4UV/TJIHDhuWlkb8KyJaAtjcZK184dTqul0dV0nPKX97FNtDXX20BTLXSA==" + "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" + } }, "@octokit/auth-token": { "version": "2.4.5", @@ -621,6 +635,11 @@ "debug": "^4.1.1" } }, + "tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" + }, "universal-user-agent": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", diff --git a/packages/github/package.json b/packages/github/package.json index 8ed6c424..881c595e 100644 --- a/packages/github/package.json +++ b/packages/github/package.json @@ -38,7 +38,7 @@ "url": "https://github.com/actions/toolkit/issues" }, "dependencies": { - "@actions/http-client": "^2.0.0", + "@actions/http-client": "^2.0.1", "@octokit/core": "^3.6.0", "@octokit/plugin-paginate-rest": "^2.17.0", "@octokit/plugin-rest-endpoint-methods": "^5.13.0" diff --git a/packages/tool-cache/package-lock.json b/packages/tool-cache/package-lock.json index bb33ad7f..8bacb776 100644 --- a/packages/tool-cache/package-lock.json +++ b/packages/tool-cache/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@actions/core": "^1.2.6", "@actions/exec": "^1.0.0", - "@actions/http-client": "^2.0.0", + "@actions/http-client": "^2.0.1", "@actions/io": "^1.1.1", "semver": "^6.1.0", "uuid": "^3.3.2" @@ -48,9 +48,12 @@ } }, "node_modules/@actions/http-client": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.0.tgz", - "integrity": "sha512-fm1+OPPey5ypgStT9K8zbBhICj4J4UV/TJIHDhuWlkb8KyJaAtjcZK184dTqul0dV0nPKX97FNtDXX20BTLXSA==" + "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/@actions/io": { "version": "1.1.2", @@ -314,9 +317,12 @@ } }, "@actions/http-client": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.0.tgz", - "integrity": "sha512-fm1+OPPey5ypgStT9K8zbBhICj4J4UV/TJIHDhuWlkb8KyJaAtjcZK184dTqul0dV0nPKX97FNtDXX20BTLXSA==" + "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" + } }, "@actions/io": { "version": "1.1.2", diff --git a/packages/tool-cache/package.json b/packages/tool-cache/package.json index 7c48d91a..8c157bcc 100644 --- a/packages/tool-cache/package.json +++ b/packages/tool-cache/package.json @@ -38,7 +38,7 @@ "dependencies": { "@actions/core": "^1.2.6", "@actions/exec": "^1.0.0", - "@actions/http-client": "^2.0.0", + "@actions/http-client": "^2.0.1", "@actions/io": "^1.1.1", "semver": "^6.1.0", "uuid": "^3.3.2" From 500d0b42fee2552ae9eeb5933091fe2fbf14e72d Mon Sep 17 00:00:00 2001 From: Konrad Pabjan Date: Fri, 13 May 2022 11:12:58 -0400 Subject: [PATCH 9/9] Bump all packages that have @actions/http-client as a dependency (#1088) * bump @actions/artifact * update @actions/cache * Update @actions/core * Update @actions/github * update @actions/tool-cache --- packages/artifact/RELEASES.md | 6 +++++- packages/artifact/package-lock.json | 2 +- packages/artifact/package.json | 2 +- packages/cache/RELEASES.md | 5 ++++- packages/cache/package-lock.json | 2 +- packages/cache/package.json | 2 +- packages/core/RELEASES.md | 3 +++ packages/core/package-lock.json | 2 +- packages/core/package.json | 2 +- packages/github/RELEASES.md | 3 +++ packages/github/package-lock.json | 2 +- packages/github/package.json | 2 +- packages/tool-cache/RELEASES.md | 3 +++ packages/tool-cache/package-lock.json | 2 +- packages/tool-cache/package.json | 2 +- 15 files changed, 28 insertions(+), 12 deletions(-) diff --git a/packages/artifact/RELEASES.md b/packages/artifact/RELEASES.md index 3d4425d8..d9e1935c 100644 --- a/packages/artifact/RELEASES.md +++ b/packages/artifact/RELEASES.md @@ -81,4 +81,8 @@ ### 1.0.1 -- Update to v2.0.0 of `@actions/http-client` \ No newline at end of file +- Update to v2.0.0 of `@actions/http-client` + +### 1.0.2 + +- Update to v2.0.1 of `@actions/http-client` [#1087](https://github.com/actions/toolkit/pull/1087) \ No newline at end of file diff --git a/packages/artifact/package-lock.json b/packages/artifact/package-lock.json index 0740ed4d..f46f3efd 100644 --- a/packages/artifact/package-lock.json +++ b/packages/artifact/package-lock.json @@ -1,6 +1,6 @@ { "name": "@actions/artifact", - "version": "1.0.1", + "version": "1.0.2", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/packages/artifact/package.json b/packages/artifact/package.json index cb56c1a8..1a8e1b7a 100644 --- a/packages/artifact/package.json +++ b/packages/artifact/package.json @@ -1,6 +1,6 @@ { "name": "@actions/artifact", - "version": "1.0.1", + "version": "1.0.2", "preview": true, "description": "Actions artifact lib", "keywords": [ diff --git a/packages/cache/RELEASES.md b/packages/cache/RELEASES.md index 58217f86..8adb7e3c 100644 --- a/packages/cache/RELEASES.md +++ b/packages/cache/RELEASES.md @@ -58,4 +58,7 @@ - Added support to check if Actions cache service feature is available or not [#1028](https://github.com/actions/toolkit/pull/1028) ### 2.0.3 -- Update to v2.0.0 of `@actions/http-client` \ No newline at end of file +- Update to v2.0.0 of `@actions/http-client` + +### 2.0.4 +- Update to v2.0.1 of `@actions/http-client` [#1087](https://github.com/actions/toolkit/pull/1087) \ No newline at end of file diff --git a/packages/cache/package-lock.json b/packages/cache/package-lock.json index cdc4c5cd..8ff62189 100644 --- a/packages/cache/package-lock.json +++ b/packages/cache/package-lock.json @@ -1,6 +1,6 @@ { "name": "@actions/cache", - "version": "2.0.3", + "version": "2.0.4", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/packages/cache/package.json b/packages/cache/package.json index 21bb683a..0b7bff06 100644 --- a/packages/cache/package.json +++ b/packages/cache/package.json @@ -1,6 +1,6 @@ { "name": "@actions/cache", - "version": "2.0.3", + "version": "2.0.4", "preview": true, "description": "Actions cache lib", "keywords": [ diff --git a/packages/core/RELEASES.md b/packages/core/RELEASES.md index 2f00f0ce..f751b4ef 100644 --- a/packages/core/RELEASES.md +++ b/packages/core/RELEASES.md @@ -1,5 +1,8 @@ # @actions/core Releases +### 1.8.2 +- Update to v2.0.1 of `@actions/http-client` [#1087](https://github.com/actions/toolkit/pull/1087) + ### 1.8.1 - Update to v2.0.0 of `@actions/http-client` diff --git a/packages/core/package-lock.json b/packages/core/package-lock.json index dcb996b1..82ddb5f8 100644 --- a/packages/core/package-lock.json +++ b/packages/core/package-lock.json @@ -1,6 +1,6 @@ { "name": "@actions/core", - "version": "1.8.1", + "version": "1.8.2", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/packages/core/package.json b/packages/core/package.json index 8eefd72d..7a0129c0 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@actions/core", - "version": "1.8.1", + "version": "1.8.2", "description": "Actions core lib", "keywords": [ "github", diff --git a/packages/github/RELEASES.md b/packages/github/RELEASES.md index abbca6f1..fb7ac2c7 100644 --- a/packages/github/RELEASES.md +++ b/packages/github/RELEASES.md @@ -1,5 +1,8 @@ # @actions/github Releases +### 5.0.3 +- - Update to v2.0.1 of `@actions/http-client` [#1087](https://github.com/actions/toolkit/pull/1087) + ### 5.0.2 - Update to v2.0.0 of `@actions/http-client` diff --git a/packages/github/package-lock.json b/packages/github/package-lock.json index 3e8992fb..b66a87f0 100644 --- a/packages/github/package-lock.json +++ b/packages/github/package-lock.json @@ -1,6 +1,6 @@ { "name": "@actions/github", - "version": "5.0.2", + "version": "5.0.3", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/packages/github/package.json b/packages/github/package.json index 881c595e..30da3279 100644 --- a/packages/github/package.json +++ b/packages/github/package.json @@ -1,6 +1,6 @@ { "name": "@actions/github", - "version": "5.0.2", + "version": "5.0.3", "description": "Actions github lib", "keywords": [ "github", diff --git a/packages/tool-cache/RELEASES.md b/packages/tool-cache/RELEASES.md index 8285cb22..9fdd4898 100644 --- a/packages/tool-cache/RELEASES.md +++ b/packages/tool-cache/RELEASES.md @@ -1,5 +1,8 @@ # @actions/tool-cache Releases +### 2.0.1 +- Update to v2.0.1 of `@actions/http-client` [#1087](https://github.com/actions/toolkit/pull/1087) + ### 2.0.0 - Update to v2.0.0 of `@actions/http-client` - The type of the `headers` parameter in the exported function `downloadTool` has been narrowed from `{ [header: string]: any }` to `{ [header: string]: number | string | string[] | undefined; }` (that is, `http.OutgoingHttpHeaders`). diff --git a/packages/tool-cache/package-lock.json b/packages/tool-cache/package-lock.json index 8bacb776..1c7dfe7f 100644 --- a/packages/tool-cache/package-lock.json +++ b/packages/tool-cache/package-lock.json @@ -1,6 +1,6 @@ { "name": "@actions/tool-cache", - "version": "2.0.0", + "version": "2.0.1", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/packages/tool-cache/package.json b/packages/tool-cache/package.json index 8c157bcc..c7744d58 100644 --- a/packages/tool-cache/package.json +++ b/packages/tool-cache/package.json @@ -1,6 +1,6 @@ { "name": "@actions/tool-cache", - "version": "2.0.0", + "version": "2.0.1", "description": "Actions tool-cache lib", "keywords": [ "github",