diff --git a/docs/configuration.md b/docs/configuration.md index 6dd9c69b..84c5bf14 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -27,10 +27,8 @@ Access tokens can be created here: https://github.com/settings/tokens/new Please select the necessary access scopes: -- _repo:status (required for private repos)_ -- _repo_deployment (required for private repos)_ -- **public_repo (required)** -- _repo:invite (required for private repos)_ +- `repo` (for public and private repos) +- `public_repo` (for public repos only) CLI: `--accessToken myAccessToken` diff --git a/src/index.ts b/src/index.ts index f88aa363..f5cebb4f 100755 --- a/src/index.ts +++ b/src/index.ts @@ -6,7 +6,7 @@ import { getOptions } from './options/options'; async function init() { try { const options = await getOptions(process.argv); - return initSteps(options); + return await initSteps(options); } catch (e) { if (e.name === 'HandledError') { console.error(e.message); diff --git a/src/services/github.ts b/src/services/github.ts index 11234ae9..e01d0252 100644 --- a/src/services/github.ts +++ b/src/services/github.ts @@ -151,6 +151,44 @@ export async function addLabelsToPullRequest( } } +export async function verifyAccessToken( + owner: string, + repoName: string, + accessToken: string +) { + try { + return await axios.head( + `https://api.github.com/repos/${owner}/${repoName}?access_token=${accessToken}` + ); + } catch (e) { + const error = e as GithubApiError; + const statusCode = error.response && error.response.status; + + const grantedScopes = get(error, 'response.headers["x-oauth-scopes"]'); + const requiredScopes = get( + error, + 'response.headers["x-accepted-oauth-scopes"]' + ); + + switch (statusCode) { + case 401: + throw new HandledError( + `Please check your access token and make sure it is valid` + ); + default: + if (grantedScopes === requiredScopes) { + throw new HandledError( + `The repository "${owner}/${repoName}" doesn't exist` + ); + } + + throw new HandledError( + `You do not have access to the repository "${owner}/${repoName}". Please make sure your access token has the required scopes.\n\nRequired scopes: ${requiredScopes}\nAccess token scopes: ${grantedScopes}` + ); + } + } +} + export function setAccessToken(token: string) { accessToken = token; } diff --git a/src/steps/steps.ts b/src/steps/steps.ts index 99dc8536..e583132d 100755 --- a/src/steps/steps.ts +++ b/src/steps/steps.ts @@ -1,4 +1,4 @@ -import { setAccessToken } from '../services/github'; +import { setAccessToken, verifyAccessToken } from '../services/github'; import { doBackportVersions } from './doBackportVersions'; import { BackportOptions } from '../options/options'; import { getCommits } from './getCommits'; @@ -7,6 +7,7 @@ import { maybeSetupRepo } from './maybeSetupRepo'; export async function initSteps(options: BackportOptions) { const [owner, repoName] = options.upstream.split('/'); + await verifyAccessToken(owner, repoName, options.accessToken); setAccessToken(options.accessToken); const commits = await getCommits(options); diff --git a/test/steps/__snapshots__/steps.test.ts.snap b/test/steps/__snapshots__/steps.test.ts.snap index 966bfc1d..2626cc7d 100644 --- a/test/steps/__snapshots__/steps.test.ts.snap +++ b/test/steps/__snapshots__/steps.test.ts.snap @@ -228,7 +228,27 @@ Object { "xsrfHeaderName": "X-XSRF-TOKEN", }, ], - "head": Array [], + "head": Array [ + Object { + "data": undefined, + "headers": Object { + "Accept": "application/json, text/plain, */*", + }, + "maxContentLength": -1, + "method": "head", + "timeout": 0, + "transformRequest": Object { + "0": [Function], + }, + "transformResponse": Object { + "0": [Function], + }, + "url": "https://api.github.com/repos/elastic/kibana?access_token=myAccessToken", + "validateStatus": [Function], + "xsrfCookieName": "XSRF-TOKEN", + "xsrfHeaderName": "X-XSRF-TOKEN", + }, + ], "list": Array [], "options": Array [], "patch": Array [], diff --git a/test/steps/steps.test.ts b/test/steps/steps.test.ts index 7e106f9d..b7f36527 100644 --- a/test/steps/steps.test.ts +++ b/test/steps/steps.test.ts @@ -27,6 +27,19 @@ function mockGetPullRequest( }); } +function mockVerifyAccessToken( + axiosMock: MockAdapter, + owner: string, + repoName: string, + accessToken: string +) { + return axiosMock + .onHead( + `https://api.github.com/repos/${owner}/${repoName}?access_token=${accessToken}` + ) + .reply(200); +} + function mockGetCommits( axiosMock: MockAdapter, { @@ -111,6 +124,9 @@ describe('run through steps', () => { }); axiosMock = new MockAdapter(axios); + + mockVerifyAccessToken(axiosMock, owner, repoName, accessToken); + mockGetCommits(axiosMock, { owner, repoName,