Skip to content

Commit

Permalink
fix(github-auth): upgrade github client to latest
Browse files Browse the repository at this point in the history
upgrade @octokit/rest to v^16.43.1
use @octokit/auth-basic and @octokit/auth-token for github auth

fix #78
  • Loading branch information
sharvit committed Feb 9, 2020
1 parent da30671 commit c67cfb5
Show file tree
Hide file tree
Showing 8 changed files with 196 additions and 193 deletions.
11 changes: 5 additions & 6 deletions __mocks__/@octokit/rest.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
export const authenticatedUserToken = 'some-token';
export const createAuthorization = jest
export const auth = jest
.fn()
.mockResolvedValue({ data: { token: authenticatedUserToken } });
.mockResolvedValue({ token: authenticatedUserToken });

export const createRepoForAuthenticatedUser = jest.fn();

const mock = jest.fn().mockImplementation(() => ({
export const Octokit = jest.fn().mockImplementation(() => ({
auth,
repos: { createForAuthenticatedUser: createRepoForAuthenticatedUser },
oauthAuthorizations: { createAuthorization },
}));

export default mock;
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@
"app"
],
"dependencies": {
"@octokit/rest": "^16.28.6",
"@octokit/auth-basic": "^1.3.0",
"@octokit/auth-token": "^2.4.0",
"@octokit/rest": "^16.43.1",
"chalk": "^3.0.0",
"command-exists": "^1.2.4",
"find-up": "^4.0.0",
Expand Down
136 changes: 79 additions & 57 deletions src/app/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Github from './lib/github';
jest.mock('./lib/github');
jest.mock('./lib/npm');

Github.use2fa = false;
Github.on2Fa = false;

const runAppGenerator = () => helpers.run(Generator);

Expand Down Expand Up @@ -222,12 +222,12 @@ describe('prompts', () => {
});
});

test('createGithubRepository with token', () => {
test('createGithubRepository with token', async () => {
const name = 'some-project-name';
const description = 'some-description';
const githubToken = 'some-token';

return runAppGenerator()
await runAppGenerator()
.withOptions({
githubToken,
})
Expand All @@ -236,78 +236,100 @@ describe('prompts', () => {
createGithubRepository: true,
projectName: name,
description,
})
.then(() => {
expect(Github).toBeCalledWith({
token: `token ${githubToken}`,
});
expect(Github.prototype.createRepository).toBeCalledWith({
name,
description,
});
});

expect(Github).toBeCalledWith({
token: githubToken,
});
expect(Github.prototype.authenticate).toBeCalled();
expect(Github.prototype.createRepository).toBeCalledWith({
name,
description,
});
});

test('createGithubRepository with username and password', () => {
test('createGithubRepository with username and password', async () => {
const name = 'some-project-name';
const description = 'some-description';
const username = 'some-username';
const password = 'some-password';

return runAppGenerator()
.withPrompts({
...requiredPrompts,
createGithubRepository: true,
projectName: name,
description,
githubUsername: username,
githubPassword: password,
})
.then(() => {
expect(Github).toBeCalledWith({
username,
password,
on2fa: expect.any(Function),
});
expect(Github.prototype.createRepository).toBeCalledWith({
name,
description,
});
});
await runAppGenerator().withPrompts({
...requiredPrompts,
createGithubRepository: true,
projectName: name,
description,
githubUsername: username,
githubPassword: password,
});

expect(Github).toBeCalledWith({
username,
password,
on2Fa: expect.any(Function),
note: expect.stringMatching(
/some-username\/some-project-name\/travis-\w{4}/
),
noteUrl: 'https://github.com/sharvit/generator-node-mdl',
scopes: [
'repo',
'read:org',
'user:email',
'repo_deployment',
'repo:status',
'write:repo_hook',
],
});
expect(Github.prototype.authenticate).toBeCalled();
expect(Github.prototype.createRepository).toBeCalledWith({
name,
description,
});
});

test('createGithubRepository with username, password and 2fa', () => {
Github.use2fa = true;
test('createGithubRepository with username, password and 2fa', async () => {
Github.on2Fa = true;

const name = 'some-project-name';
const description = 'some-description';
const username = 'some-username';
const password = 'some-password';
const github2fa = 'github2fa';

return runAppGenerator()
.withPrompts({
...requiredPrompts,
createGithubRepository: true,
projectName: name,
description,
githubUsername: username,
githubPassword: password,
github2fa,
})
.then(() => {
expect(Github).toBeCalledWith({
username,
password,
on2fa: expect.any(Function),
});
expect(Github.prototype.createRepository).toBeCalledWith({
name,
description,
});
await runAppGenerator().withPrompts({
...requiredPrompts,
createGithubRepository: true,
projectName: name,
description,
githubUsername: username,
githubPassword: password,
github2fa,
});

Github.use2fa = false;
});
expect(Github).toBeCalledWith({
username,
password,
on2Fa: expect.any(Function),
note: expect.stringMatching(
/some-username\/some-project-name\/travis-\w{4}/
),
noteUrl: 'https://github.com/sharvit/generator-node-mdl',
scopes: [
'repo',
'read:org',
'user:email',
'repo_deployment',
'repo:status',
'write:repo_hook',
],
});
expect(Github.prototype.authenticate).toBeCalled();
expect(Github.prototype.createRepository).toBeCalledWith({
name,
description,
});

Github.on2Fa = false;
});

test('no createGithubRepository', () => {
Expand Down
16 changes: 8 additions & 8 deletions src/app/lib/__mocks__/github.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
const Github = jest.fn(function({ on2fa }) {
this._on2fa = function() {
if (Github.use2fa && !this._on2faCalled) {
this._on2faCalled = true;
return on2fa();
const Github = jest.fn(function({ on2Fa }) {
this._on2Fa = function() {
if (Github.use2fa && !this._on2FaCalled) {
this._on2FaCalled = true;
return on2Fa();
}
};
});

Github.use2fa = false;

Github.prototype.createRepository = jest.fn(async function() {
await this._on2fa();
await this._on2Fa();

return {
data: { html_url: 'some-html-url' },
};
});

Github.prototype.createToken = jest.fn(async function(repository) {
await this._on2fa();
Github.prototype.authenticate = jest.fn(async function() {
await this._on2Fa();

return 'some-token';
});
Expand Down
54 changes: 31 additions & 23 deletions src/app/lib/github.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,46 @@
import Octokit from '@octokit/rest';
import { Octokit } from '@octokit/rest';
import { createTokenAuth } from '@octokit/auth-token';
import { createBasicAuth } from '@octokit/auth-basic';

/**
* Github class
*/
export default class Github {
/**
* Github
* @param {string} username github username
* @param {string} password github password
* @param {function} on2fa async function that should return
* two-factor authentication pin (string)
* Create a Github instance
* @param {string} token Set token to login with auth-token
* @param {string} username Set username to login with username and password
* @param {string} password Set password to login with username and password
* @param {Function} on2Fa Set on2Fa to support 2 factor authentication
* @param {string} note Note description for the new token
* @param {string} noteUrl Note url for the new token
* @param {string[]} scopes Auth token scopes
*/
constructor({ token, username, password, on2fa }) {
constructor({ token, username, password, on2Fa, note, noteUrl, scopes }) {
const authStrategy = token ? createTokenAuth : createBasicAuth;
const auth = token || {
username,
password,
on2Fa,
token: { note, scopes, noteUrl },
};

this.githubClient = new Octokit({
auth: token || {
username,
password,
on2fa,
},
auth,
authStrategy,
});
}

async authenticate() {
const { token } = await this.githubClient.auth();

return token;
}

createRepository({ name, description }) {
return this.githubClient.repos.createForAuthenticatedUser({
name,
description,
});
}

async createToken(note, scopes) {
const {
data,
} = await this.githubClient.oauthAuthorizations.createAuthorization({
note,
scopes,
});

return data.token;
}
}
52 changes: 32 additions & 20 deletions src/app/lib/github.test.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,54 @@
import Octokit, {
import {
Octokit,
auth,
createRepoForAuthenticatedUser,
createAuthorization,
authenticatedUserToken,
} from '@octokit/rest';
import { createTokenAuth } from '@octokit/auth-token';
import { createBasicAuth } from '@octokit/auth-basic';
import Github from './github';

describe('Github', () => {
let github;
const username = 'some-username';
const password = 'some-password';
const on2fa = jest.fn();

beforeEach(() => {
Octokit.mockClear();
auth.mockClear();
createRepoForAuthenticatedUser.mockClear();
createAuthorization.mockClear();
});

it('should create a new Github instance with token', () => {
new Github({ token: authenticatedUserToken }); // eslint-disable-line no-new

github = new Github({ username, password, on2fa });
expect(Octokit).toBeCalledWith({
auth: authenticatedUserToken,
authStrategy: createTokenAuth,
});
});

it('should create a new Github instance', () => {
it('should create a new Github instance with basic auth', () => {
const username = 'some-username';
const password = 'some-password';
const on2Fa = jest.fn();
const note = 'some note';
const noteUrl = 'some-note-url';
const scopes = ['some', 'scopes'];

new Github({ username, password, on2Fa, note, noteUrl, scopes }); // eslint-disable-line no-new

expect(Octokit).toBeCalledWith({
auth: {
username,
password,
on2fa,
on2Fa,
token: { note, scopes, noteUrl },
},
authStrategy: createBasicAuth,
});
});

it('should create-repository', () => {
const name = 'some-name';
const description = 'some-description';
const github = new Github({ token: authenticatedUserToken });

github.createRepository({ name, description });

Expand All @@ -41,16 +58,11 @@ describe('Github', () => {
});
});

it('should create-createToken', async () => {
const note = 'some-note';
const scopes = 'some-scopes';

const token = await github.createToken(note, scopes);
it('should authenticate', async () => {
const github = new Github({ token: authenticatedUserToken });
const token = await github.authenticate();

expect(token).toBe(authenticatedUserToken);
expect(createAuthorization).toBeCalledWith({
note,
scopes,
});
expect(auth).toBeCalled();
});
});
Loading

0 comments on commit c67cfb5

Please sign in to comment.