Skip to content

Commit

Permalink
feat: secret - dry run (#8)
Browse files Browse the repository at this point in the history
* add dry drun option

* feat add dryrun

* sadly typing changed
  • Loading branch information
buehler authored and virth committed Apr 16, 2019
1 parent b9d685d commit a1bc4f7
Show file tree
Hide file tree
Showing 17 changed files with 1,367 additions and 761 deletions.
1,982 changes: 1,285 additions & 697 deletions package-lock.json

Large diffs are not rendered by default.

42 changes: 21 additions & 21 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,45 +38,45 @@
"access": "public"
},
"dependencies": {
"@kubernetes/client-node": "^0.8.1",
"@kubernetes/client-node": "^0.8.2",
"apache-md5": "^1.1.2",
"chalk": "^2.4.2",
"clipboardy": "^1.2.3",
"clipboardy": "^2.0.0",
"fast-glob": "^2.2.6",
"find-up": "^3.0.0",
"fs-extra": "^7.0.1",
"fuzzy": "^0.1.3",
"got": "^9.6.0",
"inquirer": "^6.2.2",
"inquirer": "^6.3.1",
"inquirer-autocomplete-prompt": "^1.0.1",
"node-machine-id": "^1.1.10",
"ora": "^3.0.0",
"semver": "^5.6.0",
"ora": "^3.4.0",
"semver": "^6.0.0",
"tslib": "^1.9.3",
"yargonaut": "^1.1.4",
"yargs": "^12.0.5"
"yargs": "^13.2.2"
},
"devDependencies": {
"@semantic-release/gitlab": "^3.1.2",
"@semantic-release/npm": "^5.1.4",
"@smartive/tslint-config": "^5.0.0",
"@smartive/tslint-config": "^6.0.0",
"@types/clipboardy": "^1.1.0",
"@types/fs-extra": "^5.0.4",
"@types/got": "^9.4.0",
"@types/inquirer": "0.0.43",
"@types/jest": "^23.3.13",
"@types/node": "^10.12.21",
"@types/semver": "^5.5.0",
"@types/yargs": "^12.0.8",
"@types/fs-extra": "^5.0.5",
"@types/got": "^9.4.1",
"@types/inquirer": "6.0.0",
"@types/jest": "^24.0.11",
"@types/node": "^11.13.4",
"@types/semver": "^6.0.0",
"@types/yargs": "^13.0.0",
"del-cli": "^1.1.0",
"jest": "^24.0.0",
"memfs": "^2.15.0",
"mock-fs": "^4.7.0",
"jest": "^24.7.1",
"memfs": "^2.15.2",
"mock-fs": "^4.8.0",
"pkg": "^4.3.7",
"semantic-release": "^15.13.3",
"ts-jest": "^23.10.5",
"tslint": "^5.12.1",
"tsutils": "^3.8.0",
"typescript": "^3.3.1"
"ts-jest": "^24.0.2",
"tslint": "^5.15.0",
"tsutils": "^3.10.0",
"typescript": "^3.4.3"
}
}
8 changes: 7 additions & 1 deletion src/commands/secret/basic-auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const apacheMd5 = require('apache-md5');

type SecretBasicAuthArguments = RootArguments & {
name: string;
dryRun: boolean;
username?: string;
password?: string;
};
Expand All @@ -32,10 +33,15 @@ export const secretBasicAuthCommand: CommandModule<RootArguments, SecretBasicAut
'kuby secret basic-auth my-secret',
'This creates an secret for basic auth and both, the user and the password, will be asked.',
)
.option('dry-run', {
boolean: true,
default: false,
description: "Don't create secret on server. Log it to console instead.",
})
.positional('name', {
description: 'Name of the secret to create',
type: 'string',
}) as Argv<SecretBasicAuthArguments>,
}) as unknown as Argv<SecretBasicAuthArguments>,

async handler(args: Arguments<SecretBasicAuthArguments>): Promise<void> {
const logger = new Logger('secrets');
Expand Down
26 changes: 19 additions & 7 deletions src/commands/secret/create/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { V1ObjectMeta, V1Secret } from '@kubernetes/client-node';
import { dumpYaml, V1ObjectMeta, V1Secret } from '@kubernetes/client-node';
import { Arguments, Argv, CommandModule } from 'yargs';

import { RootArguments } from '../../../root-arguments';
Expand All @@ -8,6 +8,7 @@ import { Logger } from '../../../utils/logger';

type SecretCreateArguments = RootArguments & {
name: string;
dryRun: boolean;

/**
* Array of already splitted and converted data for the secret.
Expand All @@ -33,6 +34,11 @@ export const secretCreateCommand: CommandModule<RootArguments, SecretCreateArgum
description: 'Name of the secret to create',
type: 'string',
})
.option('dry-run', {
boolean: true,
default: false,
description: "Don't create secret on server. Log it to console instead.",
})
.positional('data', {
description: 'Array of secret data in the form of: key=value key=value key=value',
coerce: (data: string[]) =>
Expand Down Expand Up @@ -61,8 +67,7 @@ export const secretCreateCommand: CommandModule<RootArguments, SecretCreateArgum
logger.info(`Create secret with name "${args.name}".`);
logger.debug(`Add ${args.data.length} data keys.`);
try {
logger.startSpinner('Creating...');
await api.core.createNamespacedSecret(api.currentNamespace, {
const secret = {
...new V1Secret(),
apiVersion: 'v1',
kind: 'Secret',
Expand All @@ -71,15 +76,22 @@ export const secretCreateCommand: CommandModule<RootArguments, SecretCreateArgum
...new V1ObjectMeta(),
name: args.name,
},
stringData: args.data.reduce(
data: args.data.reduce(
(obj, cur) => {
obj[cur.name] = cur.value;
obj[cur.name] = cur.value.base64Encode();
return obj;
},
{} as { [key: string]: string },
),
});
logger.stopSpinner();
};
if (args.dryRun) {
logger.info('Dry run set, only log the secret and return.');
logger.output(`\n\n${dumpYaml(secret)}\n\n`);
} else {
logger.startSpinner('Creating...');
await api.core.createNamespacedSecret(api.currentNamespace, secret);
logger.stopSpinner();
}
logger.success('Secret created.');
} catch ({ body: { message } }) {
logger.stopSpinner();
Expand Down
2 changes: 1 addition & 1 deletion test/commands/apply/apply.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ describe('commands / apply', () => {
},
process.cwd(),
);
(spawn as jest.Mock<number>).mockReturnValue(1);
(spawn as any as jest.Mock<number>).mockReturnValue(1);
await applyCommand.handler({ deployFolder: './deploy' } as any);
expect(process.exit).toHaveBeenCalled();
});
Expand Down
4 changes: 2 additions & 2 deletions test/commands/context/context.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('commands / context', () => {
});

it('should ask the user if no <context> is set', async () => {
(prompt as jest.Mock).mockResolvedValue({ context: 'current' });
(prompt as any as jest.Mock).mockResolvedValue({ context: 'current' });
(exec as jest.Mock).mockResolvedValueOnce('current').mockResolvedValueOnce(`current${EOL}non-current${EOL}third`);

await contextCommand.handler({} as any);
Expand Down Expand Up @@ -54,7 +54,7 @@ describe('commands / context', () => {
});

it('should switch then context if <context> does exist', async () => {
(prompt as jest.Mock).mockResolvedValue({ context: 'current' });
(prompt as any as jest.Mock).mockResolvedValue({ context: 'current' });
(exec as jest.Mock).mockResolvedValueOnce('current').mockResolvedValueOnce(`current${EOL}non-current${EOL}third`);

await contextCommand.handler({ name: 'third' } as any);
Expand Down
2 changes: 1 addition & 1 deletion test/commands/delete/delete.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ describe('commands / delete', () => {

beforeAll(() => {
process.exit = jest.fn() as any;
prepare = jest.spyOn(prepareCommand, 'handler').mockResolvedValue(undefined);
prepare = jest.spyOn<any, any>(prepareCommand, 'handler').mockResolvedValue(undefined);
kubeConfig = jest.spyOn(kubeConfigCommand, 'handler').mockResolvedValue(undefined);
});

Expand Down
4 changes: 2 additions & 2 deletions test/commands/deploy/deploy.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ describe('commands / deploy', () => {

beforeAll(() => {
process.exit = jest.fn() as any;
prepare = jest.spyOn(prepareCommand, 'handler').mockResolvedValue(undefined);
apply = jest.spyOn(applyCommand, 'handler').mockResolvedValue(undefined);
prepare = jest.spyOn<any, any>(prepareCommand, 'handler').mockResolvedValue(undefined);
apply = jest.spyOn<any, any>(applyCommand, 'handler').mockResolvedValue(undefined);
});

afterEach(() => {
Expand Down
2 changes: 1 addition & 1 deletion test/commands/kubectl/kubectl.list.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ describe('commands / kubectl / list', () => {

beforeAll(() => {
process.exit = jest.fn() as any;
versionInfo = jest.spyOn(Version, 'getVersionInfo').mockResolvedValue({
versionInfo = jest.spyOn<any, any>(Version, 'getVersionInfo').mockResolvedValue({
kubectlVersion: 'kubectlversion',
});
localVersions = jest.spyOn(Helpers, 'getLocalVersions').mockResolvedValue([]);
Expand Down
4 changes: 2 additions & 2 deletions test/commands/kubectl/kubectl.remove.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe('commands / kubectl / remove', () => {

beforeAll(() => {
process.exit = jest.fn() as any;
versionInfo = jest.spyOn(Version, 'getVersionInfo').mockResolvedValue({
versionInfo = jest.spyOn<any, any>(Version, 'getVersionInfo').mockResolvedValue({
kubectlVersion: 'kubectlVersion',
});
});
Expand All @@ -39,7 +39,7 @@ describe('commands / kubectl / remove', () => {
});

it('should ask the user if no semver version is provided', async () => {
(prompt as jest.Mock).mockResolvedValue({ version: '1.8.4' });
(prompt as any as jest.Mock).mockResolvedValue({ version: '1.8.4' });
await kubectlRemoveCommand.handler({} as any);
expect(prompt).toHaveBeenCalled();
});
Expand Down
4 changes: 2 additions & 2 deletions test/commands/kubectl/kubectl.use.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ describe('commands / kubectl / use', () => {

beforeAll(() => {
process.exit = jest.fn() as any;
versionInfo = jest.spyOn(Version, 'getVersionInfo').mockResolvedValue({
versionInfo = jest.spyOn<any, any>(Version, 'getVersionInfo').mockResolvedValue({
kubectlVersion: 'kubectlVersion',
});
});
Expand All @@ -40,7 +40,7 @@ describe('commands / kubectl / use', () => {
});

it('should ask the user if no semver version is provided', async () => {
(prompt as jest.Mock).mockResolvedValue({ version: '1.8.4' });
(prompt as any as jest.Mock).mockResolvedValue({ version: '1.8.4' });
await kubectlUseCommand.handler({} as any);
expect(prompt).toHaveBeenCalled();
});
Expand Down
4 changes: 2 additions & 2 deletions test/commands/kubectl/kubectl.utils.kubectl.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ describe('commands / kubectl / utils / kubectl', () => {
let get: jest.Mock;

beforeAll(() => {
get = jest.spyOn(Got, 'get').mockResolvedValue({
get = jest.spyOn<any, any>(Got, 'get').mockResolvedValue({
body: JSON.stringify([
{
tag_name: 'v1.1.1',
Expand Down Expand Up @@ -157,7 +157,7 @@ describe('commands / kubectl / utils / kubectl', () => {
let get: jest.Mock;

beforeAll(() => {
get = jest.spyOn(Got, 'get').mockResolvedValue({
get = jest.spyOn<any, any>(Got, 'get').mockResolvedValue({
body: JSON.stringify([
{
tag_name: 'v1.1.1',
Expand Down
12 changes: 6 additions & 6 deletions test/commands/namespace/namespace.create.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ describe('commands / namespace / create', () => {
currentContext = jest.spyOn(Kubectx, 'getCurrentContext').mockResolvedValue('context');
namespaces = jest.spyOn(Kubens, 'getNamespaces').mockResolvedValue(['ns1', 'ns2']);
confirm = jest.spyOn(Confirm, 'simpleConfirm').mockResolvedValue(true);
kubeConfigCommand = jest.spyOn(namespaceKubeConfigCommand, 'handler').mockResolvedValue(undefined);
kubeConfigCommand = jest.spyOn<any, any>(namespaceKubeConfigCommand, 'handler').mockResolvedValue(undefined);
});

afterEach(() => {
Expand Down Expand Up @@ -52,12 +52,12 @@ describe('commands / namespace / create', () => {
[Filepathes.namespaceDefaultRolePath]: 'foobar',
});
await namespaceCreateCommand.handler({ name: 'ns3' } as any);
expect((prompt as jest.Mock).mock.calls[0][0].map((q: any) => q.default)[2]).toBe('foobar');
expect((prompt as any as jest.Mock).mock.calls[0][0].map((q: any) => q.default)[2]).toBe('foobar');
});

it('should use the default role if no file exists', async () => {
await namespaceCreateCommand.handler({ name: 'ns3' } as any);
expect((prompt as jest.Mock).mock.calls[0][0].map((q: any) => q.default)[2]).toMatch(/kind: Role/g);
expect((prompt as any as jest.Mock).mock.calls[0][0].map((q: any) => q.default)[2]).toMatch(/kind: Role/g);
});

it('should ask the user for certain information', async () => {
Expand All @@ -71,7 +71,7 @@ describe('commands / namespace / create', () => {
});

it('should write the default role file when user selects to save the role', async () => {
(prompt as jest.Mock).mockImplementationOnce(async () => ({
(prompt as any as jest.Mock).mockImplementationOnce(async () => ({
createServiceAccount: true,
serviceAccountName: 'name',
saveRole: true,
Expand Down Expand Up @@ -104,7 +104,7 @@ describe('commands / namespace / create', () => {
});

it('should fail if no role name is provided', async () => {
(prompt as jest.Mock).mockImplementationOnce(async () => ({
(prompt as any as jest.Mock).mockImplementationOnce(async () => ({
createServiceAccount: true,
serviceAccountName: 'name',
saveRole: false,
Expand Down Expand Up @@ -133,5 +133,5 @@ describe('commands / namespace / create', () => {
expect(kubeConfigCommand).toHaveBeenCalled();
});

it.skip('TODO: should call namespace kubeconfig command with --ci mode', async () => {});
it.skip('TODO: should call namespace kubeconfig command with --ci mode', async () => { });
});
6 changes: 3 additions & 3 deletions test/commands/secret/__snapshots__/create.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ Array [
"default",
Object {
"apiVersion": "v1",
"data": Object {
"foo": "YmFy",
},
"kind": "Secret",
"metadata": Object {
"name": "name",
},
"stringData": Object {
"foo": "bar",
},
"type": "Opaque",
},
]
Expand Down
10 changes: 5 additions & 5 deletions test/commands/secret/basic-auth.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe('commands / secret / basic-auth', () => {

beforeAll(() => {
process.exit = jest.fn() as any;
create = jest.spyOn(secretCreateCommand, 'handler').mockResolvedValue(undefined);
create = jest.spyOn<any, any>(secretCreateCommand, 'handler').mockResolvedValue(undefined);
});

afterEach(() => {
Expand All @@ -22,20 +22,20 @@ describe('commands / secret / basic-auth', () => {
});

it('should ask for username when not given', async () => {
(prompt as jest.Mock).mockResolvedValueOnce({
(prompt as any as jest.Mock).mockResolvedValueOnce({
username: 'user',
password: 'pass',
});
await cmd.handler({ name: 'secret' } as any);
expect(prompt as jest.Mock).toHaveBeenCalled();
expect(prompt as any as jest.Mock).toHaveBeenCalled();
});

it('should ask for password when not given', async () => {
(prompt as jest.Mock).mockResolvedValueOnce({
(prompt as any as jest.Mock).mockResolvedValueOnce({
password: 'pass',
});
await cmd.handler({ name: 'secret', username: 'user' } as any);
expect(prompt as jest.Mock).toHaveBeenCalled();
expect(prompt as any as jest.Mock).toHaveBeenCalled();
});

it('should call secret create handler with specific data', async () => {
Expand Down
Loading

0 comments on commit a1bc4f7

Please sign in to comment.