Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/adapters/base-class.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import BaseClass from './base-class';
import { cliux as ux, ContentstackClient } from '@contentstack/cli-utilities';
import config from '../config';
import exp from 'constants';

jest.mock('@contentstack/cli-utilities', () => ({
cliux: {
Expand Down
30 changes: 1 addition & 29 deletions src/adapters/base-class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { ApolloClient } from '@apollo/client/core';
import { writeFileSync, existsSync, readFileSync } from 'fs';
import { cliux as ux, ContentstackClient } from '@contentstack/cli-utilities';

import config from '../config';
import { print, GraphqlApiClient, LogPolling, getOrganizations } from '../util';
import {
branchesQuery,
Expand All @@ -31,7 +30,6 @@ import {
import {
LogFn,
ExitFn,
Providers,
ConfigType,
AdapterConstructorInputs,
EmitMessage,
Expand Down Expand Up @@ -148,31 +146,6 @@ export default class BaseClass {
await this.initApolloClient();
}

/**
* @method selectProjectType - select project type/provider/adapter
*
* @return {*} {Promise<void>}
* @memberof BaseClass
*/
async selectProjectType(): Promise<void> {
const choices = [
...map(config.supportedAdapters, (provider) => ({
value: provider,
name: `Continue with ${provider}`,
})),
{ value: 'FileUpload', name: 'Continue with FileUpload' },
];

const selectedProvider: Providers = await ux.inquire({
choices: choices,
type: 'search-list',
name: 'projectType',
message: 'Choose a project type to proceed',
});

this.config.provider = selectedProvider;
}

/**
* @method detectFramework - detect the project framework
*
Expand Down Expand Up @@ -427,7 +400,6 @@ export default class BaseClass {
* @memberof BaseClass
*/
async connectToAdapterOnUi(emit = true): Promise<void> {
await this.selectProjectType();

if (includes(this.config.supportedAdapters, this.config.provider)) {
const baseUrl = this.config.host.startsWith('http') ? this.config.host : `https://${this.config.host}`;
Expand Down Expand Up @@ -862,4 +834,4 @@ export default class BaseClass {
});
}
}
}
}
177 changes: 151 additions & 26 deletions src/adapters/github.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
import GitHub from './github';
import { getRemoteUrls } from '../util/create-git-meta';
import { repositoriesQuery } from '../graphql';
import { repositoriesQuery, userConnectionsQuery } from '../graphql';
import BaseClass from './base-class';
import { existsSync } from 'fs';

jest.mock('../util/create-git-meta');
jest.mock('fs', () => ({
...jest.requireActual('fs'),
existsSync: jest.fn(),
}));

const userConnections = [
{
__typename: 'UserConnection',
userUid: 'testuser1',
provider: 'GitHub',
},
];
const repositories = [
{
__typename: 'GitRepository',
Expand Down Expand Up @@ -33,24 +45,70 @@ const repositories = [
];

describe('GitHub Adapter', () => {
describe('checkGitRemoteAvailableAndValid', () => {
const repositoriesResponse = { data: { repositories } };
let logMock: jest.Mock;
let exitMock: jest.Mock;
let logMock: jest.Mock;
let exitMock: jest.Mock;

beforeEach(() => {
logMock = jest.fn();
exitMock = jest.fn().mockImplementationOnce(() => {
throw new Error('1');
});
beforeEach(() => {
logMock = jest.fn();
exitMock = jest.fn().mockImplementationOnce(() => {
throw new Error('1');
});
});

afterEach(() => {
jest.resetAllMocks();
});

describe('checkGitHubConnected', () => {
it('should return true if GitHub is connected', async () => {
const userConnectionResponse = { data: { userConnections } };
const apolloClient = {
query: jest.fn().mockResolvedValueOnce(userConnectionResponse),
} as any;
const githubAdapterInstance = new GitHub({
config: { projectBasePath: '/home/project1', provider: 'GitHub' },
apolloClient: apolloClient,
log: logMock,
} as any);
const connectToAdapterOnUiMock = jest
.spyOn(BaseClass.prototype, 'connectToAdapterOnUi')
.mockResolvedValueOnce(undefined);

await githubAdapterInstance.checkGitHubConnected();

expect(apolloClient.query).toHaveBeenCalledWith({ query: userConnectionsQuery });
expect(logMock).toHaveBeenCalledWith('GitHub connection identified!', 'info');
expect(githubAdapterInstance.config.userConnection).toEqual(userConnections[0]);
expect(connectToAdapterOnUiMock).not.toHaveBeenCalled();
});

it('should log an error and exit if GitHub is not connected', async () => {
const userConnectionResponse = { data: { userConnections: [] } };
const connectToAdapterOnUiMock = jest.spyOn(BaseClass.prototype, 'connectToAdapterOnUi').mockResolvedValueOnce();
const apolloClient = {
query: jest.fn().mockResolvedValueOnce(userConnectionResponse),
} as any;
const githubAdapterInstance = new GitHub({
config: { projectBasePath: '/home/project1' },
apolloClient: apolloClient,
log: logMock,
} as any);

await githubAdapterInstance.checkGitHubConnected();

afterEach(() => {
jest.resetAllMocks();
expect(apolloClient.query).toHaveBeenCalledWith({ query: userConnectionsQuery });
expect(logMock).toHaveBeenCalledWith('GitHub connection not found!', 'error');
expect(connectToAdapterOnUiMock).toHaveBeenCalled();
expect(githubAdapterInstance.config.userConnection).toEqual(undefined);
});
});

describe('checkGitRemoteAvailableAndValid', () => {
const repositoriesResponse = { data: { repositories } };

it(`should successfully check if the git remote is available and valid
when the github remote URL is HTTPS based`, async () => {
(existsSync as jest.Mock).mockReturnValueOnce(true);
(getRemoteUrls as jest.Mock).mockResolvedValueOnce({
origin: 'https://github.com/test-user/eleventy-sample.git',
});
Expand All @@ -64,6 +122,7 @@ describe('GitHub Adapter', () => {

const result = await githubAdapterInstance.checkGitRemoteAvailableAndValid();

expect(existsSync).toHaveBeenCalledWith('/home/project1/.git');
expect(getRemoteUrls as jest.Mock).toHaveBeenCalledWith('/home/project1/.git/config');
expect(apolloClient.query).toHaveBeenCalledWith({ query: repositoriesQuery });
expect(githubAdapterInstance.config.repository).toEqual({
Expand All @@ -79,6 +138,7 @@ describe('GitHub Adapter', () => {

it(`should successfully check if the git remote is available and valid
when the github remote URL is SSH based`, async () => {
(existsSync as jest.Mock).mockReturnValueOnce(true);
(getRemoteUrls as jest.Mock).mockResolvedValueOnce({
origin: 'git@github.com:test-user/eleventy-sample.git',
});
Expand All @@ -92,6 +152,7 @@ describe('GitHub Adapter', () => {

const result = await githubAdapterInstance.checkGitRemoteAvailableAndValid();

expect(existsSync).toHaveBeenCalledWith('/home/project1/.git');
expect(getRemoteUrls as jest.Mock).toHaveBeenCalledWith('/home/project1/.git/config');
expect(apolloClient.query).toHaveBeenCalledWith({ query: repositoriesQuery });
expect(githubAdapterInstance.config.repository).toEqual({
Expand All @@ -105,15 +166,39 @@ describe('GitHub Adapter', () => {
expect(result).toBe(true);
});

it(`should log an error and proceed to connection via UI
if git repo remote url is unavailable and exit`, async () => {
it('should log an error and exit if git config file does not exists', async () => {
(existsSync as jest.Mock).mockReturnValueOnce(false);
const githubAdapterInstance = new GitHub({
config: { projectBasePath: '/home/project1' },
log: logMock,
exit: exitMock,
} as any);
let err;

try {
await githubAdapterInstance.checkGitRemoteAvailableAndValid();
} catch (error: any) {
err = error;
}

expect(getRemoteUrls as jest.Mock).not.toHaveBeenCalled();
expect(logMock).toHaveBeenCalledWith('No Git repository configuration found at /home/project1.', 'error');
expect(logMock).toHaveBeenCalledWith(
'Please initialize a Git repository and try again, or use the File Upload option.',
'error',
);
expect(exitMock).toHaveBeenCalledWith(1);
expect(err).toEqual(new Error('1'));
});

it(`should log an error if git repo remote url
is unavailable and exit`, async () => {
(existsSync as jest.Mock).mockReturnValueOnce(true);
(getRemoteUrls as jest.Mock).mockResolvedValueOnce(undefined);
const connectToAdapterOnUiMock
= jest.spyOn(BaseClass.prototype, 'connectToAdapterOnUi').mockResolvedValueOnce(undefined);
const githubAdapterInstance = new GitHub({
config: { projectBasePath: '/home/project1' },
log: logMock,
exit: exitMock
const githubAdapterInstance = new GitHub({
config: { projectBasePath: '/home/project1' },
log: logMock,
exit: exitMock,
} as any);
let err;

Expand All @@ -123,25 +208,61 @@ describe('GitHub Adapter', () => {
err = error;
}

expect(existsSync).toHaveBeenCalledWith('/home/project1/.git');
expect(getRemoteUrls as jest.Mock).toHaveBeenCalledWith('/home/project1/.git/config');
expect(logMock).toHaveBeenCalledWith(
`No Git remote origin URL found for the repository at /home/project1.
Please add a git remote origin url and try again`,
'error',
);
expect(exitMock).toHaveBeenCalledWith(1);
expect(err).toEqual(new Error('1'));
expect(githubAdapterInstance.config.repository).toBeUndefined();
});

it('should log an error and exit if GitHub app is uninstalled', async () => {
(existsSync as jest.Mock).mockReturnValueOnce(true);
(getRemoteUrls as jest.Mock).mockResolvedValueOnce({
origin: 'https://github.com/test-user/eleventy-sample.git',
});
const apolloClient = {
query: jest.fn().mockRejectedValue(new Error('GitHub app error')),
} as any;
const connectToAdapterOnUiMock = jest.spyOn(BaseClass.prototype, 'connectToAdapterOnUi').mockResolvedValueOnce();
const githubAdapterInstance = new GitHub({
config: { projectBasePath: '/home/project1' },
apolloClient: apolloClient,
log: logMock,
exit: exitMock,
} as any);
let err;

try {
await githubAdapterInstance.checkGitRemoteAvailableAndValid();
} catch (error: any) {
err = error;
}

expect(existsSync).toHaveBeenCalledWith('/home/project1/.git');
expect(getRemoteUrls as jest.Mock).toHaveBeenCalledWith('/home/project1/.git/config');
expect(logMock).toHaveBeenCalledWith('GitHub project not identified!', 'error');
expect(apolloClient.query).toHaveBeenCalled();
expect(connectToAdapterOnUiMock).toHaveBeenCalled();
expect(logMock).toHaveBeenCalledWith('GitHub app uninstalled. Please reconnect the app and try again', 'error');
expect(exitMock).toHaveBeenCalledWith(1);
expect(err).toEqual(new Error('1'));
expect(githubAdapterInstance.config.repository).toBeUndefined();
});

it('should log an error and exit if repository is not found in the list of available repositories', async () => {
(existsSync as jest.Mock).mockReturnValueOnce(true);
(getRemoteUrls as jest.Mock).mockResolvedValueOnce({
origin: 'https://github.com/test-user/test-repo-2.git',
});
const apolloClient = {
query: jest.fn().mockResolvedValueOnce(repositoriesResponse),
} as any;
const githubAdapterInstance = new GitHub({
config: { projectBasePath: '/home/project1' },
log: logMock,
const githubAdapterInstance = new GitHub({
config: { projectBasePath: '/home/project1' },
log: logMock,
exit: exitMock,
apolloClient: apolloClient,
} as any);
Expand All @@ -153,9 +274,13 @@ describe('GitHub Adapter', () => {
err = error;
}

expect(existsSync).toHaveBeenCalledWith('/home/project1/.git');
expect(getRemoteUrls as jest.Mock).toHaveBeenCalledWith('/home/project1/.git/config');
expect(apolloClient.query).toHaveBeenCalledWith({ query: repositoriesQuery });
expect(logMock).toHaveBeenCalledWith('Repository not found in the list!', 'error');
expect(logMock).toHaveBeenCalledWith(
'Repository not added to the GitHub app. Please add it to the app’s repository access list and try again.',
'error',
);
expect(exitMock).toHaveBeenCalledWith(1);
expect(err).toEqual(new Error('1'));
expect(githubAdapterInstance.config.repository).toBeUndefined();
Expand Down
Loading