diff --git a/package.json b/package.json index ead621009a99..46e2eb5d735d 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,8 @@ "preinstall": "node ./tools/npm/check-npm.js", "format:ts": "git-clang-format HEAD $(git diff HEAD --name-only | grep -v \"\\.d\\.ts\")", "format:bazel": "yarn -s bazel:buildifier --lint=fix --mode=fix", - "format": "yarn -s format:ts && yarn -s format:bazel" + "format": "yarn -s format:ts && yarn -s format:bazel", + "cherry-pick-patch": "ts-node --project tools/cherry-pick-patch/ tools/cherry-pick-patch/cherry-pick-patch.ts" }, "version": "8.1.1", "requiredAngularVersion": "^8.0.0 || ^9.0.0-0", @@ -71,7 +72,7 @@ "@bazel/karma": "0.32.2", "@bazel/typescript": "0.32.2", "@firebase/app-types": "^0.3.2", - "@octokit/rest": "^15.9.4", + "@octokit/rest": "^16.28.7", "@schematics/angular": "^8.0.3", "@types/browser-sync": "^0.0.42", "@types/chalk": "^0.4.31", diff --git a/tools/cherry-pick-patch/cherry-pick-patch.ts b/tools/cherry-pick-patch/cherry-pick-patch.ts new file mode 100644 index 000000000000..08a23c2601dc --- /dev/null +++ b/tools/cherry-pick-patch/cherry-pick-patch.ts @@ -0,0 +1,53 @@ +import {GitHub} from './github'; +import {outputResults} from './output-results'; +import { + requestLatestCherryPickedCommitSha, + requestPatchBranch, + verifyLatestCherryPickedCommit +} from './prompt'; + + +/** + * Task to run the script that attempts to produce cherry-pick commands for the patch branch. + */ +class CherryPickPatchTask { + github = new GitHub(); + + async run() { + const patchBranchSuggestion = await this.github.getPatchBranchSuggestion(); + const branch = await requestPatchBranch(patchBranchSuggestion); + const sha = await this.getLatestCherryPickedCommitSha(branch); + + const commit = await this.github.getCommit(sha); + const pullRequests = await this.github.getPatchPullRequestsSince(commit.commit.author.date); + + outputResults(pullRequests); + } + + /** Returns the commit SHA of the last cherry-picked commit on master. */ + async getLatestCherryPickedCommitSha(branch: any): Promise { + const commits = await this.github.listCommits(branch); + + /** Gets the SHA from the string: "(cherry picked from commit 4c6eeb9aba73d3)" */ + const regexp = new RegExp('cherry picked from commit (.*[^)])'); + const latestShas = commits + .map(d => { + const result = d.commit.message.match(regexp); + return result ? result[1] : null; + }) + .filter(d => !!d); + + const latestSha = latestShas[0]; + if (!latestSha) { + return await requestLatestCherryPickedCommitSha(); + } else { + const commit = await this.github.getCommit(latestSha); + return await verifyLatestCherryPickedCommit(commit); + } + } +} + +/** Entry-point for the script. */ +if (require.main === module) { + new CherryPickPatchTask().run(); +} diff --git a/tools/cherry-pick-patch/get-merged-pull-requests.ts b/tools/cherry-pick-patch/get-merged-pull-requests.ts new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tools/cherry-pick-patch/github.ts b/tools/cherry-pick-patch/github.ts new file mode 100644 index 000000000000..ed04237a4d77 --- /dev/null +++ b/tools/cherry-pick-patch/github.ts @@ -0,0 +1,88 @@ +import * as OctokitApi from '@octokit/rest'; + +// TODO: Consider using local git information for the data to avoid worrying about rate limits. */ +/** Class to act as an interface to the GitHub API. */ +export class GitHub { + // TODO: Use an authentication token to increase rate limits. + /** Octokit API instance that can be used to make Github API calls. */ + private _api = new OctokitApi(); + + /** Owner of the repository to query. */ + private _owner = 'angular'; + + /** Name of the repository to query. */ + private _name = 'components'; + + /** + * Retrieves merged patch-eligible pull requests that have been merged since the date. + * Results are sorted by merge date. + */ + async getPatchPullRequestsSince(dateSince: string): Promise { + const query = 'base:master is:pr -label:"target: minor" -label:"target: major" is:merged' + + ` merged:>${dateSince}`; + const result = await this._search(query); + + // Load information for each pull request. Waits for each pull request response until loading + // the next pull request to avoid GitHub's abuse detection (too many calls in a short amount + // of time). + const pullRequests: OctokitApi.PullsGetResponse[] = []; + for (let i = 0; i < result.items.length; i++) { + pullRequests.push(await this.loadPullRequest(result.items[i].number)); + } + + // Sort by merge date. + pullRequests.sort((a, b) => (a.merged_at < b.merged_at) ? -1 : 1); + return pullRequests; + } + + /** Loads the information for the provided pull request number. */ + async loadPullRequest(prNumber: number): Promise { + const response = await this._api.pulls.get({ + owner: this._owner, + repo: this._name, + pull_number: prNumber, + }); + return response.data; + } + + /** Gets the commit information for the given SHA. */ + async getCommit(sha: string): Promise { + const response = await this._api.repos.getCommit({ + owner: this._owner, + repo: this._name, + ref: sha, + }); + + return response.data; + } + + /** Retrieves the list of latest commits from the branch. */ + async listCommits(branch: string): Promise { + const response = await this._api.repos.listCommits({ + owner: this._owner, + repo: this._name, + sha: branch, + }); + + return response.data; + } + + // TODO: Handle pagination in case there are more than 100 results. + /** Gets a suggestion for the latest patch branch. */ + async getPatchBranchSuggestion(): Promise { + const response = await this._api.repos.listBranches({owner: this._owner, repo: this._name}); + + // Matches branch names that have two digits separated by period and ends with an x + const patchBranches = + response.data.map(branch => branch.name).filter(name => !!/^\d+\.\d+\.x$/g.exec(name)); + return patchBranches.pop() || ''; + } + + // TODO: Handle pagination in case there are more than 100 results. + /** Searches the repository using the provided query. */ + private async _search(query: string): Promise<{items: any[]}> { + const scopedQuery = `repo:${this._owner}/${this._name} ${query}`; + const result = await this._api.search.issuesAndPullRequests({per_page: 100, q: scopedQuery}); + return result.data; + } +} diff --git a/tools/cherry-pick-patch/output-results.ts b/tools/cherry-pick-patch/output-results.ts new file mode 100644 index 000000000000..4b9944f4d952 --- /dev/null +++ b/tools/cherry-pick-patch/output-results.ts @@ -0,0 +1,34 @@ +import {PullsGetResponse} from '@octokit/rest'; +import {cyan} from 'chalk'; + +/** Outputs the information of the pull requests to be cherry-picked and the commands to run. */ +export function outputResults(pullRequests: PullsGetResponse[]) { + if (!pullRequests.length) { + console.log('No pull requests need to be cherry-picked'); + return; + } + + console.log(); + console.log(cyan('------------------------')); + console.log(cyan(' Results ')); + console.log(cyan('------------------------')); + console.log(); + + pullRequests.forEach(p => { + const data = [p.number, p.merged_at, p.merge_commit_sha, p.html_url, p.title]; + console.log(data.join('\t')); + }); + + console.log(); + console.log(cyan('------------------------')); + console.log(cyan(' Cherry Pick Commands')); + console.log(cyan('------------------------')); + + pullRequests.forEach((pr, index) => { + if (index % 5 === 0) { + console.log(); + } + + console.log(`git cherry-pick -x ${pr.merge_commit_sha};`); + }); +} diff --git a/tools/cherry-pick-patch/prompt.ts b/tools/cherry-pick-patch/prompt.ts new file mode 100644 index 000000000000..92f3cfa4959b --- /dev/null +++ b/tools/cherry-pick-patch/prompt.ts @@ -0,0 +1,43 @@ +import {prompt} from 'inquirer'; +import * as OctokitApi from '@octokit/rest'; + +/** Requests the user to provide the name of the patch branch. */ +export async function requestPatchBranch(suggestion: string): Promise { + const result = await prompt<{branch: string}>([{ + type: 'input', + name: 'branch', + message: `What is the name of the current patch branch?`, + default: suggestion || null, + }]); + + return result.branch; +} + +/** Confirms the latest cherry-picked commit on master; requests one if not confirmed. */ +export async function verifyLatestCherryPickedCommit(commit: OctokitApi.ReposGetCommitResponse) { + console.log(`\nThe last cherry-picked commit on master is "${commit.commit.message}"`); + + const result = await prompt<{confirm: boolean}>([{ + type: 'confirm', + name: 'confirm', + message: `Is this correct?`, + default: true, + }]); + + if (!result.confirm) { + return await requestLatestCherryPickedCommitSha(); + } else { + return commit.sha; + } +} + +/** Requests the SHA of the latest cherry picked commit on master. */ +export async function requestLatestCherryPickedCommitSha(): Promise { + const result = await prompt<{sha: string}>([{ + type: 'input', + name: 'sha', + message: `What is the SHA of the latest cherry-picked commit on master?`, + }]); + + return result.sha; +} diff --git a/tools/cherry-pick-patch/tsconfig.json b/tools/cherry-pick-patch/tsconfig.json new file mode 100644 index 000000000000..7c7dfb5b32d4 --- /dev/null +++ b/tools/cherry-pick-patch/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "lib": ["es2016"], + "types": ["node"], + "strictNullChecks": true + } +} diff --git a/yarn.lock b/yarn.lock index 03bf2b7bb45e..fbd348346d92 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1007,19 +1007,54 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== -"@octokit/rest@^15.9.4": - version "15.18.0" - resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-15.18.0.tgz#e6de702b57dec94c71e806f1cff0ecb9725b3054" - integrity sha512-D1dDJMbvT4dok9++vc8uwCr92ndadwfz6vHK+IklzBHKSsuLlhpv2/dzx97Y4aRlm0t74LeXKDp4j0b4M2vmQw== +"@octokit/endpoint@^5.1.0": + version "5.3.2" + resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-5.3.2.tgz#2deda2d869cac9ba7f370287d55667be2a808d4b" + integrity sha512-gRjteEM9I6f4D8vtwU2iGUTn9RX/AJ0SVXiqBUEuYEWVGGAVjSXdT0oNmghH5lvQNWs8mwt6ZaultuG6yXivNw== + dependencies: + deepmerge "4.0.0" + is-plain-object "^3.0.0" + universal-user-agent "^3.0.0" + url-template "^2.0.8" + +"@octokit/request-error@^1.0.1", "@octokit/request-error@^1.0.2": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-1.0.4.tgz#15e1dc22123ba4a9a4391914d80ec1e5303a23be" + integrity sha512-L4JaJDXn8SGT+5G0uX79rZLv0MNJmfGa4vb4vy1NnpjSnWDLJRy6m90udGwvMmavwsStgbv2QNkPzzTCMmL+ig== + dependencies: + deprecation "^2.0.0" + once "^1.4.0" + +"@octokit/request@^5.0.0": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.0.2.tgz#59a920451f24811c016ddc507adcc41aafb2dca5" + integrity sha512-z1BQr43g4kOL4ZrIVBMHwi68Yg9VbkRUyuAgqCp1rU3vbYa69+2gIld/+gHclw15bJWQnhqqyEb7h5a5EqgZ0A== + dependencies: + "@octokit/endpoint" "^5.1.0" + "@octokit/request-error" "^1.0.1" + deprecation "^2.0.0" + is-plain-object "^3.0.0" + node-fetch "^2.3.0" + once "^1.4.0" + universal-user-agent "^3.0.0" + +"@octokit/rest@^16.28.7": + version "16.28.7" + resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-16.28.7.tgz#a2c2db5b318da84144beba82d19c1a9dbdb1a1fa" + integrity sha512-cznFSLEhh22XD3XeqJw51OLSfyL2fcFKUO+v2Ep9MTAFfFLS1cK1Zwd1yEgQJmJoDnj4/vv3+fGGZweG+xsbIA== dependencies: - before-after-hook "^1.1.0" + "@octokit/request" "^5.0.0" + "@octokit/request-error" "^1.0.2" + atob-lite "^2.0.0" + before-after-hook "^2.0.0" btoa-lite "^1.0.0" - debug "^3.1.0" - http-proxy-agent "^2.1.0" - https-proxy-agent "^2.2.0" - lodash "^4.17.4" - node-fetch "^2.1.1" - universal-user-agent "^2.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 "^3.0.0" url-template "^2.0.8" "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": @@ -1588,7 +1623,7 @@ agent-base@2: extend "~3.0.0" semver "~5.0.1" -agent-base@4, agent-base@^4.1.0: +agent-base@^4.1.0: version "4.2.1" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg== @@ -1992,6 +2027,11 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= +atob-lite@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/atob-lite/-/atob-lite-2.0.0.tgz#0fef5ad46f1bd7a8502c65727f0367d5ee43d696" + integrity sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY= + atob@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" @@ -2140,10 +2180,10 @@ beeper@^1.0.0: resolved "https://registry.yarnpkg.com/beeper/-/beeper-1.1.1.tgz#e6d5ea8c5dad001304a70b22638447f69cb2f809" integrity sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak= -before-after-hook@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-1.2.0.tgz#1079c10312cd4d4ad0d1676d37951ef8bfc3a563" - integrity sha512-wI3QtdLppHNkmM1VgRVLCrlWCKk/YexlPicYbXPs4eYdd1InrUCTFsx5bX1iUQzzMsoRXXPpM1r+p7JEJJydag== +before-after-hook@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.1.0.tgz#b6c03487f44e24200dd30ca5e6a1979c5d2fb635" + integrity sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A== better-assert@~1.0.0: version "1.0.2" @@ -2908,6 +2948,15 @@ cliui@^4.0.0: strip-ansi "^4.0.0" wrap-ansi "^2.0.0" +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + clone-regexp@^2.1.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clone-regexp/-/clone-regexp-2.2.0.tgz#7d65e00885cd8796405c35a737e7a86b7429e36f" @@ -3569,7 +3618,7 @@ debug@2, debug@2.6.9, debug@^2.2.0, debug@^2.3.3: dependencies: ms "2.0.0" -debug@3.1.0, debug@=3.1.0, debug@~3.1.0: +debug@=3.1.0, debug@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== @@ -3637,6 +3686,11 @@ deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= +deepmerge@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.0.0.tgz#3e3110ca29205f120d7cb064960a39c3d2087c09" + integrity sha512-YZ1rOP5+kHor4hMAH+HRQnBQHg+wvS1un1hAOuIcxcBy0hzcUf6Jg2a1w65kpoOUnurOfZbERwjI1TfZxNjcww== + deepmerge@^2.0.1: version "2.2.1" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170" @@ -3726,6 +3780,11 @@ deprecated@^0.0.1: resolved "https://registry.yarnpkg.com/deprecated/-/deprecated-0.0.1.tgz#f9c9af5464afa1e7a971458a8bdef2aa94d5bb19" integrity sha1-+cmvVGSvoeepcUWKi97yqpTVuxk= +deprecation@^2.0.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" + integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== + destroy@^1.0.4, destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" @@ -6007,14 +6066,6 @@ http-parser-js@>=0.4.0: resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.0.tgz#d65edbede84349d0dc30320815a15d39cc3cbbd8" integrity sha512-cZdEF7r4gfRIq7ezX9J0T+kQmJNOub71dWbgAXVHDct80TKP4MCETtZQ31xyv38UwgzkWPYF/Xc0ge55dW9Z9w== -http-proxy-agent@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" - integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg== - dependencies: - agent-base "4" - debug "3.1.0" - http-proxy@1.15.2: version "1.15.2" resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.15.2.tgz#642fdcaffe52d3448d2bda3b0079e9409064da31" @@ -6063,7 +6114,7 @@ https-proxy-agent@1.0.0: debug "2" extend "3" -https-proxy-agent@^2.2.0, https-proxy-agent@^2.2.1: +https-proxy-agent@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" integrity sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ== @@ -6598,6 +6649,13 @@ is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" +is-plain-object@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-3.0.0.tgz#47bfc5da1b5d50d64110806c199359482e75a928" + integrity sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg== + dependencies: + isobject "^4.0.0" + is-posix-bracket@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" @@ -6760,6 +6818,11 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= +isobject@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-4.0.0.tgz#3f1c9155e73b192022a80819bacd0343711697b0" + integrity sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA== + isstream@0.1.x, isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -7456,7 +7519,7 @@ lodash.escape@~2.4.1: lodash._reunescapedhtml "~2.4.1" lodash.keys "~2.4.1" -lodash.get@^4.0.0: +lodash.get@^4.0.0, lodash.get@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= @@ -7571,6 +7634,11 @@ lodash.restparam@^3.0.0: resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU= +lodash.set@^4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" + integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM= + lodash.template@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-2.4.1.tgz#9e611007edf629129a974ab3c48b817b3e1cf20d" @@ -7635,6 +7703,11 @@ lodash.unescape@4.0.1: resolved "https://registry.yarnpkg.com/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c" integrity sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw= +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= + lodash.values@^2.4.1, lodash.values@~2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-2.4.1.tgz#abf514436b3cb705001627978cbcf30b1280eea4" @@ -8418,10 +8491,10 @@ no-case@^2.2.0: dependencies: lower-case "^1.1.1" -node-fetch@^2.1.1: - version "2.3.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.3.0.tgz#1a1d940bbfb916a1d3e0219f037e89e71f8c5fa5" - integrity sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA== +node-fetch@^2.3.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" + integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== node-forge@^0.7.1, node-forge@^0.7.4: version "0.7.6" @@ -8738,6 +8811,11 @@ objectdiff@^1.1.0: resolved "https://registry.yarnpkg.com/objectdiff/-/objectdiff-1.1.0.tgz#8d7a15be6cb8670df8a490cc6be12a4f05ea82f4" integrity sha1-jXoVvmy4Zw34pJDMa+EqTwXqgvQ= +octokit-pagination-methods@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz#cf472edc9d551055f9ef73f6e42b4dbb4c80bea4" + integrity sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ== + on-finished@^2.2.0, on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" @@ -11096,6 +11174,15 @@ string-width@^3.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.0.0" +string-width@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + string-width@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.1.0.tgz#ba846d1daa97c3c596155308063e075ed1c99aff" @@ -11176,7 +11263,7 @@ strip-ansi@^5.0.0: dependencies: ansi-regex "^4.0.0" -strip-ansi@^5.2.0: +strip-ansi@^5.1.0, strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== @@ -12017,10 +12104,10 @@ universal-analytics@^0.4.16: request "^2.88.0" uuid "^3.0.0" -universal-user-agent@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-2.0.2.tgz#b0322da546100c658adcf4965110a56ed238aee6" - integrity sha512-nOwvHWLH3dBazyuzbECPA5uVFNd7AlgviXRHgR4yf48QqitIvpdncRrxMbZNMpPPEfgz30I9ubd1XmiJiqsTrg== +universal-user-agent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-3.0.0.tgz#4cc88d68097bffd7ac42e3b7c903e7481424b4b9" + integrity sha512-T3siHThqoj5X0benA5H0qcDnrKGXzU8TKoX15x/tQHw1hQBvIEBHjxQ2klizYsqBOO/Q+WuxoQUihadeeqDnoA== dependencies: os-name "^3.0.0" @@ -12551,6 +12638,15 @@ wrap-ansi@^2.0.0: string-width "^1.0.1" strip-ansi "^3.0.1" +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -12689,6 +12785,14 @@ yargs-parser@^13.0.0: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@^13.1.1: + version "13.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" + integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + yargs-parser@^4.1.0, yargs-parser@^4.2.0: version "4.2.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c" @@ -12802,6 +12906,22 @@ yargs@^11.0.0: y18n "^3.2.1" yargs-parser "^9.0.2" +yargs@^13.3.0: + version "13.3.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83" + integrity sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.1" + yargs@^3.32.0: version "3.32.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.32.0.tgz#03088e9ebf9e756b69751611d2a5ef591482c995"