Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
9 changes: 8 additions & 1 deletion docs/HUB.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,12 +161,19 @@ dc-cli hub clean

### add

Saves a hub configuration for later use. A hub configuration consists of:
Saves a hub configuration for later use. A hub configuration consists of either:

- client id
- client secret
- hub id

or:

- PAT token
- hub id

Once you enter the `dc-cli hub add` command you will be prompted with a yes/no choice question as to whether you would like to use a PAT Token or not.

These can subsequently be used with `dc-cli hub use`.

```
Expand Down
50 changes: 50 additions & 0 deletions src/common/hub-manager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import HubManager from '../common/hub-manager';
import * as sdk from 'dc-management-sdk-js';
import * as configure from '../commands/configure';
import fs from 'fs-extra';
import * as questionHelpers from '../common/question-helpers'; // Adjust the path as needed

// eslint-disable-next-line
const enquirer = require('enquirer');
Expand All @@ -13,6 +14,12 @@ const DummyHub = {
name: 'dummy-hub'
};

const DummyHubWithPAT = {
patToken: 'amp-pat',
hubId: 'hub-id',
name: 'dummy-hub'
};

jest.mock('dc-management-sdk-js', () => ({
...jest.requireActual('dc-management-sdk-js'),
DynamicContent: jest.fn()
Expand All @@ -25,6 +32,8 @@ jest.mock('enquirer', () => ({
Password: jest.fn()
}));

jest.mock('../common/question-helpers');

describe('hub manager', function () {
const hubGetMock = jest.fn();
const autocompleteRun = jest.fn();
Expand Down Expand Up @@ -101,10 +110,25 @@ describe('hub manager', function () {

const mockedWriteFileSync = jest.spyOn(fs, 'writeFileSync');
jest.spyOn(fs, 'existsSync').mockReturnValueOnce(true);

(questionHelpers.asyncQuestion as jest.Mock).mockResolvedValue(false);

await HubManager.addHub({ ...yargArgs, ...DummyHub });
expect(mockedWriteFileSync).toHaveBeenCalled();
});

it('should save hub with PAT token', async () => {
mockEmptyConfig(2);

const mockedWriteFileSync = jest.spyOn(fs, 'writeFileSync');
jest.spyOn(fs, 'existsSync').mockReturnValueOnce(true);

(questionHelpers.asyncQuestion as jest.Mock).mockResolvedValue(true);

await HubManager.addHub({ ...yargArgs, ...DummyHubWithPAT });
expect(mockedWriteFileSync).toHaveBeenCalled();
});

it('should save hub from user input', async () => {
const inputRun = jest.fn().mockResolvedValueOnce('client-id').mockResolvedValueOnce('hub-id');
const passwordRun = jest.fn().mockResolvedValueOnce('client-secret');
Expand All @@ -121,17 +145,43 @@ describe('hub manager', function () {

const mockedWriteFileSync = jest.spyOn(fs, 'writeFileSync');
jest.spyOn(fs, 'existsSync').mockReturnValueOnce(true);
(questionHelpers.asyncQuestion as jest.Mock).mockResolvedValue(false);
await HubManager.addHub({ ...yargArgs });
expect(mockedWriteFileSync).toHaveBeenCalled();

expect(inputRun).toHaveBeenCalledTimes(2);
expect(passwordRun).toHaveBeenCalledTimes(1);
});

it('should save hub from user input using PAT token', async () => {
const inputRun = jest.fn().mockResolvedValueOnce('hub-id');
const passwordRun = jest.fn().mockResolvedValueOnce('amp-pat');

(enquirer.Input as jest.Mock).mockReturnValue({
run: inputRun
});

(enquirer.Password as jest.Mock).mockReturnValue({
run: passwordRun
});

mockEmptyConfig(2);

const mockedWriteFileSync = jest.spyOn(fs, 'writeFileSync');
jest.spyOn(fs, 'existsSync').mockReturnValueOnce(true);
(questionHelpers.asyncQuestion as jest.Mock).mockResolvedValue(true);
await HubManager.addHub({ ...yargArgs });
expect(mockedWriteFileSync).toHaveBeenCalled();

expect(inputRun).toHaveBeenCalledTimes(1);
expect(passwordRun).toHaveBeenCalledTimes(1);
});

it('should fail to save a duplicate hub', async () => {
mockDefaultConfig();

jest.spyOn(fs, 'existsSync').mockReturnValueOnce(true);
(questionHelpers.asyncQuestion as jest.Mock).mockResolvedValue(false);
await expect(HubManager.addHub({ ...yargArgs, ...DummyHub })).rejects.toThrow(`config already exists`);
});

Expand Down
40 changes: 27 additions & 13 deletions src/common/hub-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import chalk from 'chalk';
import { handler as configure, CONFIG_FILENAME } from '../commands/configure';
import { Arguments } from 'yargs';
import dynamicContentClientFactory from '../services/dynamic-content-client-factory';
import { asyncQuestion } from './question-helpers';

// eslint-disable-next-line
const { AutoComplete, Input, Password } = require('enquirer');
Expand All @@ -20,6 +21,7 @@ export type HubConfiguration = {
hubId: string;
name?: string;
isActive?: boolean;
patToken?: string;
};

export const validateHub = async (creds: HubConfiguration): Promise<HubConfiguration> => {
Expand All @@ -40,17 +42,18 @@ const getHubs = (): HubConfiguration[] => {
}

const hubs = fs.readJSONSync(CONFIG_PATH, { encoding: 'utf-8' });
return hubs.map((hub: HubConfiguration) => ({
...hub,
isActive:
activeHub.clientId === hub.clientId &&
activeHub.clientSecret === hub.clientSecret &&
activeHub.hubId === hub.hubId
}));
return hubs.map((hub: HubConfiguration) => {
const obj = {
...hub,
isActive: activeHub.hubId === hub.hubId
};

return obj;
});
};

const saveHub = (hub: HubConfiguration): void => {
const hubs = [hub, ...getHubs().filter(h => h.hubId !== hub.hubId && h.clientId !== hub.clientId)];
const hubs = [hub, ...getHubs().filter(h => h.hubId !== hub.hubId)];
fs.writeFileSync(CONFIG_PATH, JSON.stringify(hubs, undefined, 4), { encoding: 'utf-8' });
};

Expand Down Expand Up @@ -78,21 +81,32 @@ const credentialsHelpText = helpTag('credentials assigned by Amplience support')
const hubIdHelpText = helpTag('found in hub settings -> properties');

export const addHub = async (
args: Arguments<{ clientId?: string; clientSecret?: string; hubId?: string }>
args: Arguments<{ clientId?: string; clientSecret?: string; hubId?: string; patToken?: string }>
): Promise<void> => {
// dc config
sectionHeader(`${dcTag} configuration ${credentialsHelpText}`);

// novadev-693 allow id, secret, and hub id to be passed via command line
args.clientId = args.clientId || (await ask(`client ${chalk.magenta('id')}:`));
args.clientSecret = args.clientSecret || (await secureAsk(`client ${chalk.magenta('secret')}:`));
const usePAT = await asyncQuestion('Would you like to use a PAT Token? (y/n)\n');

if (usePAT) {
args.patToken = args.patToken || (await secureAsk(`PAT ${chalk.magenta('token')}:`));
} else {
// novadev-693 allow id, secret, and hub id to be passed via command line
args.clientId = args.clientId || (await ask(`client ${chalk.magenta('id')}:`));
args.clientSecret = args.clientSecret || (await secureAsk(`client ${chalk.magenta('secret')}:`));
}

args.hubId = args.hubId || (await ask(`hub id ${hubIdHelpText}:`));

// unique key for a hub is clientId/hubId
if (getHubs().find(hub => args.clientId === hub.clientId && args.hubId === hub.hubId)) {
if (args.clientId && getHubs().find(hub => args.clientId === hub.clientId && args.hubId === hub.hubId)) {
throw new Error(`config already exists for client id [ ${args.clientId} ] and hub id [ ${args.hubId} ]`);
}

if (usePAT && getHubs().find(hub => args.patToken === hub.patToken && args.hubId === hub.hubId)) {
throw new Error(`config already exists for PAT Token and hub id [ ${args.hubId} ]`);
}

const validated = await validateHub(args as HubConfiguration);
if (validated && validated.name) {
saveHub(validated);
Expand Down