From 7ef3fcbefbc3e9c2807317ed8afa90bf78bcb0c5 Mon Sep 17 00:00:00 2001 From: Russell Bicknell Date: Mon, 16 Apr 2018 18:16:04 -0700 Subject: [PATCH 1/3] Update 'github' dependency to '@octokit/rest'. --- packages/cli/npm-shrinkwrap.json | 127 ++++++++++++++++++++++++------ packages/cli/package.json | 2 +- packages/cli/src/github/github.ts | 19 +++-- 3 files changed, 111 insertions(+), 37 deletions(-) diff --git a/packages/cli/npm-shrinkwrap.json b/packages/cli/npm-shrinkwrap.json index 07845ca26..59c251a38 100644 --- a/packages/cli/npm-shrinkwrap.json +++ b/packages/cli/npm-shrinkwrap.json @@ -663,6 +663,48 @@ "glob-to-regexp": "0.3.0" } }, + "@octokit/rest": { + "version": "15.2.6", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-15.2.6.tgz", + "integrity": "sha512-KcqG0zjnjzUqn7wczz/fKiueNpTLiAI7erhUG6bXWAsYKJJlqnwYonFSXrMW/nmes5y+qOk4uSyHBh1mdRXdVQ==", + "requires": { + "before-after-hook": "1.1.0", + "btoa-lite": "1.0.0", + "debug": "3.1.0", + "http-proxy-agent": "2.1.0", + "https-proxy-agent": "2.2.1", + "lodash": "4.17.5", + "node-fetch": "2.1.2", + "url-template": "2.0.8" + }, + "dependencies": { + "agent-base": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.0.tgz", + "integrity": "sha512-c+R/U5X+2zz2+UCrCFv6odQzJdoqI+YecuhnAJLa1zYaMc13zPfwMwZrr91Pd1DYNo/yPRbiM4WVf9whgwFsIg==", + "requires": { + "es6-promisify": "5.0.0" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "https-proxy-agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", + "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", + "requires": { + "agent-base": "4.2.0", + "debug": "3.1.0" + } + } + } + }, "@polymer/sinonjs": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@polymer/sinonjs/-/sinonjs-1.17.1.tgz", @@ -1415,6 +1457,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=", + "optional": true, "requires": { "extend": "3.0.1", "semver": "5.0.3" @@ -1423,7 +1466,8 @@ "semver": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", - "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=" + "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=", + "optional": true } } }, @@ -2072,6 +2116,11 @@ "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=" }, + "before-after-hook": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-1.1.0.tgz", + "integrity": "sha512-VOMDtYPwLbIncTxNoSzRyvaMxtXmLWLUqr8k5AfC1BzLk34HvBXaQX8snOwQZ4c0aX8aSERqtJSiI9/m2u5kuA==" + }, "better-assert": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", @@ -2286,6 +2335,11 @@ "https-proxy-agent": "1.0.0" } }, + "btoa-lite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz", + "integrity": "sha1-M3dm2hWAEhD92VbCLpxokaudAzc=" + }, "buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", @@ -3501,6 +3555,14 @@ "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==" }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "requires": { + "es6-promise": "4.2.4" + } + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -4212,15 +4274,6 @@ "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.0.tgz", "integrity": "sha1-Tnmumy6zi/hrO7Vr8+ClaqX8q9c=" }, - "follow-redirects": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-0.0.7.tgz", - "integrity": "sha1-NLkLqyqRGqNHVx2pDyK9NuzYqRk=", - "requires": { - "debug": "2.6.9", - "stream-consume": "0.1.1" - } - }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -5160,17 +5213,6 @@ "is-plain-obj": "1.1.0" } }, - "github": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/github/-/github-7.3.2.tgz", - "integrity": "sha1-/hDN5pZDUsXZHhGnYW0m1f+2+Hs=", - "requires": { - "follow-redirects": "0.0.7", - "https-proxy-agent": "1.0.0", - "mime": "1.6.0", - "netrc": "0.1.4" - } - }, "github-username": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/github-username/-/github-username-3.0.0.tgz", @@ -6084,6 +6126,33 @@ "requires-port": "1.0.0" } }, + "http-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "requires": { + "agent-base": "4.2.0", + "debug": "3.1.0" + }, + "dependencies": { + "agent-base": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.0.tgz", + "integrity": "sha512-c+R/U5X+2zz2+UCrCFv6odQzJdoqI+YecuhnAJLa1zYaMc13zPfwMwZrr91Pd1DYNo/yPRbiM4WVf9whgwFsIg==", + "requires": { + "es6-promisify": "5.0.0" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, "http-proxy-middleware": { "version": "0.17.4", "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.17.4.tgz", @@ -6124,6 +6193,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", + "optional": true, "requires": { "agent-base": "2.1.1", "debug": "2.6.9", @@ -7898,11 +7968,6 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" }, - "netrc": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/netrc/-/netrc-0.1.4.tgz", - "integrity": "sha1-a+lPysqNd63gqWcNxGCRTJRHJEQ=" - }, "nice-try": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz", @@ -7917,6 +7982,11 @@ "lower-case": "1.1.4" } }, + "node-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.1.2.tgz", + "integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U=" + }, "node-status-codes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-status-codes/-/node-status-codes-1.0.0.tgz", @@ -11422,6 +11492,11 @@ "prepend-http": "1.0.4" } }, + "url-template": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", + "integrity": "sha1-/FZaPMy/93MMd19WQflVV5FDnyE=" + }, "use": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/use/-/use-3.1.0.tgz", diff --git a/packages/cli/package.json b/packages/cli/package.json index a8ffb2b3f..39b28f1e2 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -26,6 +26,7 @@ "author": "The Polymer Project Authors", "license": "BSD-3-Clause", "dependencies": { + "@octokit/rest": "^15.2.6", "@types/chalk": "^0.4.31", "@types/del": "^3.0.0", "@types/findup-sync": "^0.3.29", @@ -53,7 +54,6 @@ "command-line-usage": "^3.0.1", "del": "^3.0.0", "findup-sync": "^0.4.2", - "github": "^7.2.1", "globby": "^8.0.1", "gunzip-maybe": "^1.3.1", "inquirer": "^1.0.2", diff --git a/packages/cli/src/github/github.ts b/packages/cli/src/github/github.ts index 19daa2635..7631989d0 100644 --- a/packages/cli/src/github/github.ts +++ b/packages/cli/src/github/github.ts @@ -19,7 +19,7 @@ import * as semver from 'semver'; import request = require('request'); import rimraf = require('rimraf'); -import GitHubApi = require('github'); +import Octokit = require('@octokit/rest'); const gunzip = require('gunzip-maybe'); const tar = require('tar-fs'); @@ -52,14 +52,14 @@ export interface GithubOpts { owner: string; repo: string; githubToken?: string; - githubApi?: GitHubApi; + githubApi?: Octokit; requestApi?: request .RequestAPI; } export class Github { private _token: string|null; - private _github: GitHubApi; + private _github: Octokit; private _request: request .RequestAPI; private _owner: string; @@ -77,9 +77,7 @@ export class Github { this._token = opts.githubToken || Github.tokenFromFile('token'); this._owner = opts.owner; this._repo = opts.repo; - this._github = opts.githubApi || new GitHubApi({ - protocol: 'https', - }); + this._github = opts.githubApi || new Octokit(); if (this._token != null) { this._github.authenticate({ type: 'oauth', @@ -156,21 +154,22 @@ export class Github { * Get all Github releases and match their tag names against the given semver * range. Return the release with the latest possible match. */ - async getSemverRelease(semverRange: string): Promise { + async getSemverRelease(semverRange: string): Promise { // Note that we only see the 100 most recent releases. If we ever release // enough versions that this becomes a concern, we'll need to improve this // call to request multiple pages of results. - const releases: GitHubApi.Release[] = await this._github.repos.getReleases({ + const response: Octokit.AnyResponse = await this._github.repos.getReleases({ owner: this._owner, repo: this._repo, per_page: 100, }); + const releases = response.data; const validReleaseVersions = - releases.filter((r) => semver.valid(r.tag_name)).map((r) => r.tag_name); + releases.filter((r: any) => semver.valid(r.tag_name)).map((r: any) => r.tag_name); const maxSatisfyingReleaseVersion = semver.maxSatisfying(validReleaseVersions, semverRange); const maxSatisfyingRelease = - releases.find((r) => r.tag_name === maxSatisfyingReleaseVersion); + releases.find((r: any) => r.tag_name === maxSatisfyingReleaseVersion); if (!maxSatisfyingRelease) { throw new Error(`${this._owner}/${this._repo} has no releases matching ${ semverRange}.`); From 0d090ca6b2a96a4bef745ba423537538ab8b755c Mon Sep 17 00:00:00 2001 From: Russell Bicknell Date: Tue, 17 Apr 2018 10:52:54 -0700 Subject: [PATCH 2/3] Throw if the response status is not '200 OK'. --- packages/cli/src/github/github.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/cli/src/github/github.ts b/packages/cli/src/github/github.ts index 7631989d0..46a35347b 100644 --- a/packages/cli/src/github/github.ts +++ b/packages/cli/src/github/github.ts @@ -163,7 +163,14 @@ export class Github { repo: this._repo, per_page: 100, }); + + const status = response.meta.status; + if (status !== '200 OK') { + throw new Error(`Failed to retrieve releases from GitHub. (${status})`); + } + const releases = response.data; + const validReleaseVersions = releases.filter((r: any) => semver.valid(r.tag_name)).map((r: any) => r.tag_name); const maxSatisfyingReleaseVersion = From bfdd05911caf6a1b61561edc8bcf166dec807760 Mon Sep 17 00:00:00 2001 From: Russell Bicknell Date: Tue, 17 Apr 2018 11:43:31 -0700 Subject: [PATCH 3/3] Update tests with new response format. Add a test for non-'200 OK' response status. --- .../cli/src/test/unit/github/github_test.ts | 41 ++++++++++++++----- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/packages/cli/src/test/unit/github/github_test.ts b/packages/cli/src/test/unit/github/github_test.ts index 822fc9809..a92bc064c 100644 --- a/packages/cli/src/test/unit/github/github_test.ts +++ b/packages/cli/src/test/unit/github/github_test.ts @@ -129,16 +129,27 @@ suite('github/github', () => { let getReleasesStub: sinon.SinonStub; let github: Github; - const basicReleasesResponse = [ - {tag_name: 'v1.0.0'}, - {tag_name: 'v1.1.0'}, - {tag_name: 'v1.2.1'}, - {tag_name: 'v2.0.0'}, - {tag_name: 'v2.0.0-pre.1'}, - {tag_name: 'v2.0.1'}, - {tag_name: 'v2.1.0'}, - {tag_name: 'TAG_NAME_WITHOUT_VERSION'}, - ]; + const basicReleasesResponse = { + meta: { + status: '200 OK', + }, + data: [ + {tag_name: 'v1.0.0'}, + {tag_name: 'v1.1.0'}, + {tag_name: 'v1.2.1'}, + {tag_name: 'v2.0.0'}, + {tag_name: 'v2.0.0-pre.1'}, + {tag_name: 'v2.0.1'}, + {tag_name: 'v2.1.0'}, + {tag_name: 'TAG_NAME_WITHOUT_VERSION'}, + ], + }; + + const failedReleasesResponse = { + meta: { + status: '500 Internal Server Error', + }, + }; setup(() => { getReleasesStub = sinon.stub(); @@ -200,6 +211,16 @@ suite('github/github', () => { err.message, 'TEST_OWNER/TEST_REPO has no releases matching ^v3.0.0.'); }); + + testName = 'rejects with an error if the status is not "200 OK"'; + test(testName, async () => { + getReleasesStub.returns(Promise.resolve(failedReleasesResponse)); + + const err = await invertPromise(github.getSemverRelease('^v3.0.0')); + assert.equal( + err.message, + 'Failed to retrieve releases from GitHub. (500 Internal Server Error)'); + }); }); });