From 4a89cf72de68713d3a465254e90537d8ea5b421e Mon Sep 17 00:00:00 2001 From: Thomas Boop <52323235+thboop@users.noreply.github.com> Date: Tue, 2 Jun 2020 21:39:46 -0400 Subject: [PATCH] @actions/github v3 using Octokit/core (#453) * Rebuild to use @Octokit/Core --- packages/github/README.md | 31 ++- .../github/__tests__/github.proxy.test.ts | 109 ++++++++++ packages/github/__tests__/github.test.ts | 55 ++--- packages/github/package-lock.json | 193 +++++++----------- packages/github/package.json | 7 +- packages/github/src/github.ts | 166 ++------------- packages/github/src/internal/utils.ts | 25 +++ packages/github/src/utils.ts | 44 ++++ 8 files changed, 311 insertions(+), 319 deletions(-) create mode 100644 packages/github/__tests__/github.proxy.test.ts create mode 100644 packages/github/src/internal/utils.ts create mode 100644 packages/github/src/utils.ts diff --git a/packages/github/README.md b/packages/github/README.md index ce606c19..eb034088 100644 --- a/packages/github/README.md +++ b/packages/github/README.md @@ -4,7 +4,7 @@ ## Usage -Returns an authenticated Octokit client that follows the machine [proxy settings](https://help.github.com/en/actions/hosting-your-own-runners/using-a-proxy-server-with-self-hosted-runners). See https://octokit.github.io/rest.js for the API. +Returns an authenticated Octokit client that follows the machine [proxy settings](https://help.github.com/en/actions/hosting-your-own-runners/using-a-proxy-server-with-self-hosted-runners) and correctly sets GHES base urls. See https://octokit.github.io/rest.js for the API. ```js const github = require('@actions/github'); @@ -17,7 +17,10 @@ async function run() { // https://help.github.com/en/actions/automating-your-workflow-with-github-actions/authenticating-with-the-github_token#about-the-github_token-secret const myToken = core.getInput('myToken'); - const octokit = new github.GitHub(myToken); + const octokit = github.getOctokit(token) + + // You can also pass in additional options as a second parameter to getOctokit + // const octokit = github.getOctokit(myToken, {userAgent: "MyActionVersion1"}); const { data: pullRequest } = await octokit.pulls.get({ owner: 'octokit', @@ -34,8 +37,6 @@ async function run() { run(); ``` -You can pass client options, as specified by [Octokit](https://octokit.github.io/rest.js/), as a second argument to the `GitHub` constructor. - You can also make GraphQL requests. See https://github.com/octokit/graphql.js for the API. ```js @@ -72,3 +73,25 @@ if (github.context.eventName === 'push') { core.info(`The head commit is: ${pushPayload.head}`) } ``` + +## Extending the Octokit instance +`@octokit/core` now supports the [plugin architecture](https://github.com/octokit/core.js#plugins). You can extend the GitHub instance using plugins. + +For example, using the `@octokit/plugin-enterprise-server` you can now access enterprise admin apis on GHES instances. + +```ts +import { GitHub, getOctokitOptions } from '@actions/github/lib/utils' +import { enterpriseServer220Admin } from '@octokit/plugin-enterprise-server' + +const octokit = GitHub.plugin(enterpriseServer220Admin) +// or override some of the default values as well +// const octokit = GitHub.plugin(enterpriseServer220Admin).defaults({userAgent: "MyNewUserAgent"}) + +const myToken = core.getInput('myToken'); +const myOctokit = new octokit(getOctokitOptions(token)) +// Create a new user +myOctokit.enterpriseAdmin.createUser({ + login: "testuser", + email: "testuser@test.com", +}); +``` diff --git a/packages/github/__tests__/github.proxy.test.ts b/packages/github/__tests__/github.proxy.test.ts new file mode 100644 index 00000000..5da06582 --- /dev/null +++ b/packages/github/__tests__/github.proxy.test.ts @@ -0,0 +1,109 @@ +import * as http from 'http' +import * as https from 'https' +import proxy from 'proxy' + +// Default values are set when the module is imported, so we need to set proxy first. +const proxyUrl = 'http://127.0.0.1:8081' +const originalProxyUrl = process.env['https_proxy'] +process.env['https_proxy'] = proxyUrl +// eslint-disable-next-line import/first +import {getOctokit} from '../src/github' + +describe('@actions/github', () => { + let proxyConnects: string[] + let proxyServer: http.Server + let first = true + + 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 = [] + }) + + afterAll(async () => { + // Stop proxy server + await new Promise(resolve => { + proxyServer.once('close', () => resolve()) + proxyServer.close() + }) + + if (originalProxyUrl) { + process.env['https_proxy'] = originalProxyUrl + } + }) + + it('basic REST client with proxy', async () => { + const token = getToken() + if (!token) { + return + } + + const octokit = getOctokit(token) + const branch = await octokit.repos.getBranch({ + owner: 'actions', + repo: 'toolkit', + branch: 'master' + }) + expect(branch.data.name).toBe('master') + expect(proxyConnects).toEqual(['api.github.com:443']) + }) + + it('basic GraphQL client with proxy', async () => { + const token = getToken() + if (!token) { + return + } + process.env['https_proxy'] = proxyUrl + const octokit = getOctokit(token) + + const repository = await octokit.graphql( + '{repository(owner:"actions", name:"toolkit"){name}}' + ) + expect(repository).toEqual({repository: {name: 'toolkit'}}) + expect(proxyConnects).toEqual(['api.github.com:443']) + }) + + it('should only use default agent if one is not provided', async () => { + const token = getToken() + if (!token) { + return + } + + // Valid token + const octokit = getOctokit(token, { + request: { + agent: new https.Agent() + } + }) + const branch = await octokit.repos.getBranch({ + owner: 'actions', + repo: 'toolkit', + branch: 'master' + }) + expect(branch.data.name).toBe('master') + expect(proxyConnects).toHaveLength(0) + }) + + function getToken(): string { + const token = process.env['GITHUB_TOKEN'] || '' + if (!token && first) { + /* eslint-disable-next-line no-console */ + console.warn( + 'Skipping GitHub tests. Set $GITHUB_TOKEN to run REST client and GraphQL client tests' + ) + first = false + } + + return token + } +}) diff --git a/packages/github/__tests__/github.test.ts b/packages/github/__tests__/github.test.ts index bf81b07a..4e02c7b3 100644 --- a/packages/github/__tests__/github.test.ts +++ b/packages/github/__tests__/github.test.ts @@ -1,6 +1,7 @@ import * as http from 'http' import proxy from 'proxy' -import {GitHub} from '../src/github' +import {getOctokit} from '../src/github' +import {GitHub, getOctokitOptions} from '../src/utils' describe('@actions/github', () => { const proxyUrl = 'http://127.0.0.1:8080' @@ -43,8 +44,22 @@ describe('@actions/github', () => { if (!token) { return } + const octokit = new GitHub(getOctokitOptions(token)) + const branch = await octokit.repos.getBranch({ + owner: 'actions', + repo: 'toolkit', + branch: 'master' + }) + expect(branch.data.name).toBe('master') + expect(proxyConnects).toHaveLength(0) + }) - const octokit = new GitHub(token) + it('basic getOctokit client', async () => { + const token = getToken() + if (!token) { + return + } + const octokit = getOctokit(token) const branch = await octokit.repos.getBranch({ owner: 'actions', repo: 'toolkit', @@ -85,30 +100,13 @@ describe('@actions/github', () => { expect(failed).toBeTruthy() }) - it('basic REST client with proxy', async () => { - const token = getToken() - if (!token) { - return - } - - process.env['https_proxy'] = proxyUrl - const octokit = new GitHub(token) - const branch = await octokit.repos.getBranch({ - owner: 'actions', - repo: 'toolkit', - branch: 'master' - }) - expect(branch.data.name).toBe('master') - expect(proxyConnects).toEqual(['api.github.com:443']) - }) - it('basic GraphQL client', async () => { const token = getToken() if (!token) { return } - const octokit = new GitHub(token) + const octokit = getOctokit(token) const repository = await octokit.graphql( '{repository(owner:"actions", name:"toolkit"){name}}' ) @@ -123,7 +121,7 @@ describe('@actions/github', () => { } // Valid token - let octokit = new GitHub(token) + let octokit = getOctokit(token) const repository = await octokit.graphql( '{repository(owner:"actions", name:"toolkit"){name}}' ) @@ -143,21 +141,6 @@ describe('@actions/github', () => { expect(failed).toBeTruthy() }) - it('basic GraphQL client with proxy', async () => { - const token = getToken() - if (!token) { - return - } - - process.env['https_proxy'] = proxyUrl - const octokit = new GitHub(token) - const repository = await octokit.graphql( - '{repository(owner:"actions", name:"toolkit"){name}}' - ) - expect(repository).toEqual({repository: {name: 'toolkit'}}) - expect(proxyConnects).toEqual(['api.github.com:443']) - }) - function getToken(): string { const token = process.env['GITHUB_TOKEN'] || '' if (!token && first) { diff --git a/packages/github/package-lock.json b/packages/github/package-lock.json index a075eac2..5d0ed1b3 100644 --- a/packages/github/package-lock.json +++ b/packages/github/package-lock.json @@ -1,6 +1,6 @@ { "name": "@actions/github", - "version": "2.2.0", + "version": "3.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -464,130 +464,105 @@ "@octokit/types": "^2.0.0" } }, - "@octokit/endpoint": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-5.5.1.tgz", - "integrity": "sha512-nBFhRUb5YzVTCX/iAK1MgQ4uWo89Gu0TH00qQHoYRCsE12dWcG1OiLd7v2EIo2+tpUKPMOQ62QFy9hy9Vg2ULg==", + "@octokit/core": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-2.5.2.tgz", + "integrity": "sha512-+hEKCEGvbS902uuSk/TyVnI7eWDEKVm1BIPnbKy8gsxjTYaybEU8EG73B3Ju5cMj2/OIZ0uHoQWD1nGWhWsj2g==", "requires": { + "@octokit/auth-token": "^2.4.0", + "@octokit/graphql": "^4.3.1", + "@octokit/request": "^5.4.0", "@octokit/types": "^2.0.0", + "before-after-hook": "^2.1.0", + "universal-user-agent": "^5.0.0" + } + }, + "@octokit/endpoint": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.1.tgz", + "integrity": "sha512-pOPHaSz57SFT/m3R5P8MUu4wLPszokn5pXcB/pzavLTQf2jbU+6iayTvzaY6/BiotuRS0qyEUkx3QglT4U958A==", + "requires": { + "@octokit/types": "^2.11.1", "is-plain-object": "^3.0.0", - "universal-user-agent": "^4.0.0" - }, - "dependencies": { - "universal-user-agent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.0.tgz", - "integrity": "sha512-eM8knLpev67iBDizr/YtqkJsF3GK8gzDc6st/WKzrTuPtcsOKW/0IdL4cnMBsU69pOx0otavLWBDGTwg+dB0aA==", - "requires": { - "os-name": "^3.1.0" - } - } + "universal-user-agent": "^5.0.0" } }, "@octokit/graphql": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.3.1.tgz", - "integrity": "sha512-hCdTjfvrK+ilU2keAdqNBWOk+gm1kai1ZcdjRfB30oA3/T6n53UVJb7w0L5cR3/rhU91xT3HSqCd+qbvH06yxA==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.4.0.tgz", + "integrity": "sha512-Du3hAaSROQ8EatmYoSAJjzAz3t79t9Opj/WY1zUgxVUGfIKn0AEjg+hlOLscF6fv6i/4y/CeUvsWgIfwMkTccw==", "requires": { "@octokit/request": "^5.3.0", "@octokit/types": "^2.0.0", - "universal-user-agent": "^4.0.0" + "universal-user-agent": "^5.0.0" + } + }, + "@octokit/plugin-paginate-rest": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.2.0.tgz", + "integrity": "sha512-KoNxC3PLNar8UJwR+1VMQOw2IoOrrFdo5YOiDKnBhpVbKpw+zkBKNMNKwM44UWL25Vkn0Sl3nYIEGKY+gW5ebw==", + "requires": { + "@octokit/types": "^2.12.1" }, "dependencies": { - "universal-user-agent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.0.tgz", - "integrity": "sha512-eM8knLpev67iBDizr/YtqkJsF3GK8gzDc6st/WKzrTuPtcsOKW/0IdL4cnMBsU69pOx0otavLWBDGTwg+dB0aA==", + "@octokit/types": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.12.2.tgz", + "integrity": "sha512-1GHLI/Jll3j6F0GbYyZPFTcHZMGjAiRfkTEoRUyaVVk2IWbDdwEiClAJvXzfXCDayuGSNCqAUH8lpjZtqW9GDw==", "requires": { - "os-name": "^3.1.0" + "@types/node": ">= 8" } } } }, - "@octokit/plugin-paginate-rest": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-1.1.2.tgz", - "integrity": "sha512-jbsSoi5Q1pj63sC16XIUboklNw+8tL9VOnJsWycWYR78TKss5PVpIPb1TUUcMQ+bBh7cY579cVAWmf5qG+dw+Q==", - "requires": { - "@octokit/types": "^2.0.1" - } - }, - "@octokit/plugin-request-log": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.0.tgz", - "integrity": "sha512-ywoxP68aOT3zHCLgWZgwUJatiENeHE7xJzYjfz8WI0goynp96wETBF+d95b8g/uL4QmS6owPVlaxiz3wyMAzcw==" - }, "@octokit/plugin-rest-endpoint-methods": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-2.4.0.tgz", - "integrity": "sha512-EZi/AWhtkdfAYi01obpX0DF7U6b1VRr30QNQ5xSFPITMdLSfhcBqjamE3F+sKcxPbD7eZuMHu3Qkk2V+JGxBDQ==", + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-3.10.0.tgz", + "integrity": "sha512-Z2DBsdnkWKuVBVFiLoEUKP/82ylH4Ij5F1Mss106hnQYXTxDfCWAyHW+hJ6ophuHVJ9Flaaue3fYn4CggzkHTg==", "requires": { - "@octokit/types": "^2.0.1", + "@octokit/types": "^2.14.0", "deprecation": "^2.3.1" + }, + "dependencies": { + "@octokit/types": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.14.0.tgz", + "integrity": "sha512-1w2wxpN45rEXPDFeB7rGain7wcJ/aTRg8bdILITVnS0O7a4zEGELa3JmIe+jeLdekQjvZRbVfNPqS+mi5fKCKQ==", + "requires": { + "@types/node": ">= 8" + } + } } }, "@octokit/request": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.3.1.tgz", - "integrity": "sha512-5/X0AL1ZgoU32fAepTfEoggFinO3rxsMLtzhlUX+RctLrusn/CApJuGFCd0v7GMFhF+8UiCsTTfsu7Fh1HnEJg==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.2.tgz", + "integrity": "sha512-zKdnGuQ2TQ2vFk9VU8awFT4+EYf92Z/v3OlzRaSh4RIP0H6cvW1BFPXq4XYvNez+TPQjqN+0uSkCYnMFFhcFrw==", "requires": { - "@octokit/endpoint": "^5.5.0", - "@octokit/request-error": "^1.0.1", - "@octokit/types": "^2.0.0", + "@octokit/endpoint": "^6.0.1", + "@octokit/request-error": "^2.0.0", + "@octokit/types": "^2.11.1", "deprecation": "^2.0.0", "is-plain-object": "^3.0.0", "node-fetch": "^2.3.0", "once": "^1.4.0", - "universal-user-agent": "^4.0.0" - }, - "dependencies": { - "universal-user-agent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.0.tgz", - "integrity": "sha512-eM8knLpev67iBDizr/YtqkJsF3GK8gzDc6st/WKzrTuPtcsOKW/0IdL4cnMBsU69pOx0otavLWBDGTwg+dB0aA==", - "requires": { - "os-name": "^3.1.0" - } - } + "universal-user-agent": "^5.0.0" } }, "@octokit/request-error": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-1.2.0.tgz", - "integrity": "sha512-DNBhROBYjjV/I9n7A8kVkmQNkqFAMem90dSxqvPq57e2hBr7mNTX98y3R2zDpqMQHVRpBDjsvsfIGgBzy+4PAg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.0.tgz", + "integrity": "sha512-rtYicB4Absc60rUv74Rjpzek84UbVHGHJRu4fNVlZ1mCcyUPPuzFfG9Rn6sjHrd95DEsmjSt1Axlc699ZlbDkw==", "requires": { "@octokit/types": "^2.0.0", "deprecation": "^2.0.0", "once": "^1.4.0" } }, - "@octokit/rest": { - "version": "16.43.1", - "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.43.1.tgz", - "integrity": "sha512-gfFKwRT/wFxq5qlNjnW2dh+qh74XgTQ2B179UX5K1HYCluioWj8Ndbgqw2PVqa1NnVJkGHp2ovMpVn/DImlmkw==", - "requires": { - "@octokit/auth-token": "^2.4.0", - "@octokit/plugin-paginate-rest": "^1.1.1", - "@octokit/plugin-request-log": "^1.0.0", - "@octokit/plugin-rest-endpoint-methods": "2.4.0", - "@octokit/request": "^5.2.0", - "@octokit/request-error": "^1.0.2", - "atob-lite": "^2.0.0", - "before-after-hook": "^2.0.0", - "btoa-lite": "^1.0.0", - "deprecation": "^2.0.0", - "lodash.get": "^4.4.2", - "lodash.set": "^4.3.2", - "lodash.uniq": "^4.5.0", - "octokit-pagination-methods": "^1.1.0", - "once": "^1.4.0", - "universal-user-agent": "^4.0.0" - } - }, "@octokit/types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.0.2.tgz", - "integrity": "sha512-StASIL2lgT3TRjxv17z9pAqbnI7HGu9DrJlg3sEBFfCLaMEqp+O3IQPUF6EZtQ4xkAu2ml6kMBBCtGxjvmtmuQ==", + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz", + "integrity": "sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==", "requires": { "@types/node": ">= 8" } @@ -921,11 +896,6 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, - "atob-lite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/atob-lite/-/atob-lite-2.0.0.tgz", - "integrity": "sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY=" - }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -1124,11 +1094,6 @@ "node-int64": "^0.4.0" } }, - "btoa-lite": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz", - "integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc=" - }, "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", @@ -3031,27 +2996,12 @@ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, - "lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" - }, - "lodash.set": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", - "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=" - }, "lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", "dev": true }, - "lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" - }, "lolex": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz", @@ -3413,11 +3363,6 @@ } } }, - "octokit-pagination-methods": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz", - "integrity": "sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ==" - }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -4615,9 +4560,9 @@ } }, "universal-user-agent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.0.tgz", - "integrity": "sha512-eM8knLpev67iBDizr/YtqkJsF3GK8gzDc6st/WKzrTuPtcsOKW/0IdL4cnMBsU69pOx0otavLWBDGTwg+dB0aA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-5.0.0.tgz", + "integrity": "sha512-B5TPtzZleXyPrUMKCpEHFmVhMN6EhmJYjG5PQna9s7mXeSqGTLap4OpqLl5FCEFUI3UBmllkETwKf/db66Y54Q==", "requires": { "os-name": "^3.1.0" } @@ -4813,9 +4758,9 @@ "dev": true }, "windows-release": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-3.2.0.tgz", - "integrity": "sha512-QTlz2hKLrdqukrsapKsINzqMgOUpQW268eJ0OaOpJN32h272waxR9fkB9VoWRtK7uKHG5EHJcTXQBD8XZVJkFA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-3.3.0.tgz", + "integrity": "sha512-2HetyTg1Y+R+rUgrKeUEhAG/ZuOmTrI1NBb3ZyAGQMYmOJjBBPe4MTodghRkmLJZHwkuPi02anbeGP+Zf401LQ==", "requires": { "execa": "^1.0.0" } diff --git a/packages/github/package.json b/packages/github/package.json index ef58523b..1eab9a75 100644 --- a/packages/github/package.json +++ b/packages/github/package.json @@ -1,6 +1,6 @@ { "name": "@actions/github", - "version": "2.2.0", + "version": "3.0.0", "description": "Actions github lib", "keywords": [ "github", @@ -38,8 +38,9 @@ }, "dependencies": { "@actions/http-client": "^1.0.3", - "@octokit/graphql": "^4.3.1", - "@octokit/rest": "^16.43.1" + "@octokit/core": "^2.5.1", + "@octokit/plugin-paginate-rest": "^2.2.0", + "@octokit/plugin-rest-endpoint-methods": "^3.10.0" }, "devDependencies": { "jest": "^25.1.0", diff --git a/packages/github/src/github.ts b/packages/github/src/github.ts index 699998dc..bada7e52 100644 --- a/packages/github/src/github.ts +++ b/packages/github/src/github.ts @@ -1,158 +1,20 @@ -// Originally pulled from https://github.com/JasonEtco/actions-toolkit/blob/master/src/github.ts -import {graphql} from '@octokit/graphql' - -// we need this type to set up a property on the GitHub object -// that has token authorization -// (it is not exported from octokit by default) -import { - graphql as GraphQL, - RequestParameters as GraphQLRequestParameters -} from '@octokit/graphql/dist-types/types' - -import {Octokit} from '@octokit/rest' import * as Context from './context' -import * as http from 'http' -import * as httpClient from '@actions/http-client' +import {GitHub, getOctokitOptions} from './utils' -// We need this in order to extend Octokit -Octokit.prototype = new Octokit() +// octokit + plugins +import {OctokitOptions} from '@octokit/core/dist-types/types' export const context = new Context.Context() -export class GitHub extends Octokit { - graphql: GraphQL - - /* eslint-disable no-dupe-class-members */ - // Disable no-dupe-class-members due to false positive for method overload - // https://github.com/typescript-eslint/typescript-eslint/issues/291 - - /** - * Sets up the REST client and GraphQL client with auth and proxy support. - * The parameter `token` or `opts.auth` must be supplied. The GraphQL client - * authorization is not setup when `opts.auth` is a function or object. - * - * @param token Auth token - * @param opts Octokit options - */ - constructor(token: string, opts?: Omit) - constructor(opts: Octokit.Options) - constructor(token: string | Octokit.Options, opts?: Octokit.Options) { - super(GitHub.getOctokitOptions(GitHub.disambiguate(token, opts))) - - this.graphql = GitHub.getGraphQL(GitHub.disambiguate(token, opts)) - } - - /** - * Disambiguates the constructor overload parameters - */ - private static disambiguate( - token: string | Octokit.Options, - opts?: Octokit.Options - ): [string, Octokit.Options] { - return [ - typeof token === 'string' ? token : '', - typeof token === 'object' ? token : opts || {} - ] - } - - private static getOctokitOptions( - args: [string, Octokit.Options] - ): Octokit.Options { - const token = args[0] - const options = {...args[1]} // Shallow clone - don't mutate the object provided by the caller - - // Base URL - GHES or Dotcom - options.baseUrl = options.baseUrl || this.getApiBaseUrl() - - // Auth - const auth = GitHub.getAuthString(token, options) - if (auth) { - options.auth = auth - } - - // Proxy - const agent = GitHub.getProxyAgent(options.baseUrl, options) - if (agent) { - // Shallow clone - don't mutate the object provided by the caller - options.request = options.request ? {...options.request} : {} - - // Set the agent - options.request.agent = agent - } - - return options - } - - private static getGraphQL(args: [string, Octokit.Options]): GraphQL { - const defaults: GraphQLRequestParameters = {} - defaults.baseUrl = this.getGraphQLBaseUrl() - const token = args[0] - const options = args[1] - - // Authorization - const auth = this.getAuthString(token, options) - if (auth) { - defaults.headers = { - authorization: auth - } - } - - // Proxy - const agent = GitHub.getProxyAgent(defaults.baseUrl, options) - if (agent) { - defaults.request = {agent} - } - - return graphql.defaults(defaults) - } - - private static getAuthString( - token: string, - options: Octokit.Options - ): string | undefined { - // Validate args - if (!token && !options.auth) { - throw new Error('Parameter token or opts.auth is required') - } else if (token && options.auth) { - throw new Error( - 'Parameters token and opts.auth may not both be specified' - ) - } - - return typeof options.auth === 'string' ? options.auth : `token ${token}` - } - - private static getProxyAgent( - destinationUrl: string, - options: Octokit.Options - ): http.Agent | undefined { - if (!options.request?.agent) { - if (httpClient.getProxyUrl(destinationUrl)) { - const hc = new httpClient.HttpClient() - return hc.getAgent(destinationUrl) - } - } - - return undefined - } - - private static getApiBaseUrl(): string { - return process.env['GITHUB_API_URL'] || 'https://api.github.com' - } - - private static getGraphQLBaseUrl(): string { - let url = - process.env['GITHUB_GRAPHQL_URL'] || 'https://api.github.com/graphql' - - // Shouldn't be a trailing slash, but remove if so - if (url.endsWith('/')) { - url = url.substr(0, url.length - 1) - } - - // Remove trailing "/graphql" - if (url.toUpperCase().endsWith('/GRAPHQL')) { - url = url.substr(0, url.length - '/graphql'.length) - } - return url - } +/** + * Returns a hydrated octokit ready to use for GitHub Actions + * + * @param token the repo PAT or GITHUB_TOKEN + * @param options other options to set + */ +export function getOctokit( + token: string, + options?: OctokitOptions +): InstanceType { + return new GitHub(getOctokitOptions(token, options)) } diff --git a/packages/github/src/internal/utils.ts b/packages/github/src/internal/utils.ts new file mode 100644 index 00000000..ea5ec382 --- /dev/null +++ b/packages/github/src/internal/utils.ts @@ -0,0 +1,25 @@ +import * as http from 'http' +import * as httpClient from '@actions/http-client' +import {OctokitOptions} from '@octokit/core/dist-types/types' + +export function getAuthString( + token: string, + options: OctokitOptions +): string | undefined { + if (!token && !options.auth) { + throw new Error('Parameter token or opts.auth is required') + } else if (token && options.auth) { + throw new Error('Parameters token and opts.auth may not both be specified') + } + + return typeof options.auth === 'string' ? options.auth : `token ${token}` +} + +export function getProxyAgent(destinationUrl: string): http.Agent { + const hc = new httpClient.HttpClient() + return hc.getAgent(destinationUrl) +} + +export function getApiBaseUrl(): string { + return process.env['GITHUB_API_URL'] || 'https://api.github.com' +} diff --git a/packages/github/src/utils.ts b/packages/github/src/utils.ts new file mode 100644 index 00000000..bbc71c10 --- /dev/null +++ b/packages/github/src/utils.ts @@ -0,0 +1,44 @@ +import * as Context from './context' +import * as Utils from './internal/utils' + +// octokit + plugins +import {Octokit} from '@octokit/core' +import {OctokitOptions} from '@octokit/core/dist-types/types' +import {restEndpointMethods} from '@octokit/plugin-rest-endpoint-methods' +import {paginateRest} from '@octokit/plugin-paginate-rest' + +export const context = new Context.Context() + +const baseUrl = Utils.getApiBaseUrl() +const defaults = { + baseUrl, + request: { + agent: Utils.getProxyAgent(baseUrl) + } +} + +export const GitHub = Octokit.plugin( + restEndpointMethods, + paginateRest +).defaults(defaults) + +/** + * Convience function to correctly format Octokit Options to pass into the constructor. + * + * @param token the repo PAT or GITHUB_TOKEN + * @param options other options to set + */ +export function getOctokitOptions( + token: string, + options?: OctokitOptions +): OctokitOptions { + const opts = Object.assign({}, options || {}) // Shallow clone - don't mutate the object provided by the caller + + // Auth + const auth = Utils.getAuthString(token, opts) + if (auth) { + opts.auth = auth + } + + return opts +}