Skip to content

Commit

Permalink
feat: alias set working (needs DRYing)
Browse files Browse the repository at this point in the history
  • Loading branch information
iowillhoit committed Sep 22, 2022
1 parent bd95f85 commit d89d967
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 69 deletions.
6 changes: 6 additions & 0 deletions command-snapshot.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
"flags": ["json"],
"alias": []
},
{
"command": "alias:set",
"plugin": "@salesforce/plugin-settings",
"flags": ["json", "name"],
"alias": []
},
{
"command": "config:get",
"plugin": "@salesforce/plugin-settings",
Expand Down
40 changes: 40 additions & 0 deletions messages/alias.set.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# summary

Set one or more aliases.

# description

You can associate an alias with only one value at a time. If you’ve set an alias multiple times, the alias points to the most recent value.

# flags.name.summary

Description of a flag.

# examples

- <%= config.bin %> <%= command.id %>

- Set an alias for a scratch org username:
<%= config.bin %> <%= command.id %> my-alias=[email protected]

- Set multiple aliases with a single command:
<%= config.bin %> <%= command.id %> my-alias=[email protected] my-other-alias=[email protected]

- Single aliases can be set without an equal sign
<%= config.bin %> <%= command.id %> my-alias [email protected]

# error.InvalidArgumentFormat

Set aliases with this format: key=value or key="value with spaces". Use the --help flag to see more examples.

# error.DuplicateArgument

Found duplicate argument '%s'. You can only specify an alias one time in a single command execution. Remove the duplicate and try again.

# error.ArgumentsRequired

You must provide one or more aliases to set. Use the --help flag to see more examples.

# error.ValueRequired

You must provide a value when setting an alias. Use `sf alias unset my-alias-name` to remove existing aliases.
3 changes: 3 additions & 0 deletions messages/config.set.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ Run "sf config list" to see the configuration variables you've already set and t

<%= config.bin %> <%= command.id %> --global target-org=my-scratch-org

- Single config values can be set without an equal sign
<%= config.bin %> <%= command.id %> target-org [email protected]

# flags.global.summary

Set the configuration variables globally, so they can be used from any directory.
Expand Down
60 changes: 0 additions & 60 deletions src/alias.ts

This file was deleted.

26 changes: 17 additions & 9 deletions src/commands/alias/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,35 @@
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/

import { SfCommand } from '@salesforce/sf-plugins-core';
import { Nullable } from '@salesforce/ts-types';
import { StateAggregator, Messages } from '@salesforce/core';
import { AliasCommand, AliasResult, Command } from '../../alias';

Messages.importMessagesDirectory(__dirname);
const messages = Messages.load('@salesforce/plugin-settings', 'alias.list', ['summary', 'description', 'examples']);

export default class AliasList extends AliasCommand<AliasResult[]> {
type AliasListResult = {
alias: string;
value?: Nullable<string>;
};

export default class AliasList extends SfCommand<AliasListResult[]> {
public static summary = messages.getMessage('summary');
public static description = messages.getMessage('description');
public static examples = messages.getMessages('examples');

public async run(): Promise<AliasResult[]> {
public async run(): Promise<AliasListResult[]> {
const stateAggregator = await StateAggregator.getInstance();
const keys = stateAggregator.aliases.getAll() || {};
const aliases = stateAggregator.aliases.getAll() || {};

const results = Object.keys(aliases).map((key) => ({ alias: key, value: aliases[key] }));

const results = Object.keys(keys).map((alias) => ({
alias,
value: keys[alias],
}));
const columns = {
alias: { header: 'Alias' },
value: { header: 'Value' },
};

this.output(Command.List, results);
this.table(results, columns, { title: 'List Aliases' });

return results;
}
Expand Down
107 changes: 107 additions & 0 deletions src/commands/alias/set.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* Copyright (c) 2022, salesforce.com, inc.
* All rights reserved.
* Licensed under the BSD 3-Clause license.
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/

import { SfCommand } from '@salesforce/sf-plugins-core';
import { Nullable } from '@salesforce/ts-types';
import { StateAggregator, Messages } from '@salesforce/core';

Messages.importMessagesDirectory(__dirname);
const messages = Messages.load('@salesforce/plugin-settings', 'alias.set', [
'summary',
'description',
'examples',
'error.ArgumentsRequired',
'error.DuplicateArgument',
'error.InvalidArgumentFormat',
'error.ValueRequired',
]);

type AliasSetResult = {
alias: string;
value?: Nullable<string>;
};

export default class AliasSet extends SfCommand<AliasSetResult[]> {
public static summary = messages.getMessage('summary');
public static description = messages.getMessage('description');
public static examples = messages.getMessages('examples');

// This allows varargs
public static readonly strict = false;

public async run(): Promise<AliasSetResult[]> {
const stateAggregator = await StateAggregator.getInstance();
// TODO: add success: true ?
// TODO: add example of `alias set foo bar` to both alias and config
// TODO: add error to `config:set`
const args = await this.parseConfigKeysAndValues();

const results = Object.keys(args).map((key) => {
const value = args[key];
stateAggregator.aliases.set(key, value ?? 'undefined');
return { alias: key, value };
});

await stateAggregator.aliases.write();

const columns = {
alias: { header: 'Alias' },
value: { header: 'Value' },
};

this.table(results, columns, { title: 'Set Aliases' });

return results;
}

// TODO: DRY this up! A good portion of this code is used in config:set
protected async resolveArguments(): Promise<string[]> {
// Filter out arguments that are defined in `static args = {}`
// This is future proofing in case defined args are added later
const { args, argv } = await this.parse(AliasSet);

const argValues = Object.values(args);
return argv.filter((val) => !argValues.includes(val));
}

protected async parseConfigKeysAndValues(): Promise<{ [index: string]: string }> {
const configs: { [index: string]: string } = {};
const args = await this.resolveArguments();

if (!args.length) {
throw messages.createError('error.ArgumentsRequired');
}

// Support `config set key value`
if (args.length === 2 && !args[0].includes('=')) {
return { [args[0]]: args[1] };
}

// Ensure that all args are in the right format (e.g. key=value key1=value1)
args.forEach((arg) => {
const split = arg.split('=');

if (split.length !== 2) {
throw messages.createError('error.InvalidArgumentFormat', [arg]);
}

const [name, value] = split;

if (configs[name]) {
throw messages.createError('error.DuplicateArgument', [name]);
}

if (value === '') {
throw messages.createError('error.ValueRequired', [name]);
}

configs[name] = value || undefined;
});

return configs;
}
}

0 comments on commit d89d967

Please sign in to comment.