Skip to content

Commit 063aa94

Browse files
authored
Merge pull request #476 from benleibowitz/master
feat(config): add 'describe' mode to config command for detailed parameter info
2 parents bc514f8 + b5fca31 commit 063aa94

File tree

2 files changed

+198
-5
lines changed

2 files changed

+198
-5
lines changed

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ OCO_TOKENS_MAX_INPUT=<max model token limit (default: 4096)>
114114
OCO_TOKENS_MAX_OUTPUT=<max response tokens (default: 500)>
115115
OCO_DESCRIPTION=<postface a message with ~3 sentences description of the changes>
116116
OCO_EMOJI=<boolean, add GitMoji>
117-
OCO_MODEL=<either 'gpt-4o', 'gpt-4', 'gpt-4-turbo', 'gpt-3.5-turbo' (default), 'gpt-3.5-turbo-0125', 'gpt-4-1106-preview', 'gpt-4-turbo-preview' or 'gpt-4-0125-preview' or any Anthropic or Ollama model or any string basically, but it should be a valid model name>
117+
OCO_MODEL=<either 'gpt-4o-mini' (default), 'gpt-4o', 'gpt-4', 'gpt-4-turbo', 'gpt-3.5-turbo', 'gpt-3.5-turbo-0125', 'gpt-4-1106-preview', 'gpt-4-turbo-preview' or 'gpt-4-0125-preview' or any Anthropic or Ollama model or any string basically, but it should be a valid model name>
118118
OCO_LANGUAGE=<locale, scroll to the bottom to see options>
119119
OCO_MESSAGE_TEMPLATE_PLACEHOLDER=<message template placeholder, default: '$msg'>
120120
OCO_PROMPT_MODULE=<either conventional-commit or @commitlint, default: conventional-commit>
@@ -133,6 +133,18 @@ Simply set any of the variables above like this:
133133
oco config set OCO_MODEL=gpt-4o-mini
134134
```
135135

136+
To see all available configuration parameters and their accepted values:
137+
138+
```sh
139+
oco config describe
140+
```
141+
142+
To see details for a specific parameter:
143+
144+
```sh
145+
oco config describe OCO_MODEL
146+
```
147+
136148
Configure [GitMoji](https://gitmoji.dev/) to preface a message.
137149

138150
```sh

src/commands/config.ts

Lines changed: 185 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ export enum CONFIG_KEYS {
3232

3333
export enum CONFIG_MODES {
3434
get = 'get',
35-
set = 'set'
35+
set = 'set',
36+
describe = 'describe'
3637
}
3738

3839
export const MODEL_LIST = {
@@ -622,28 +623,208 @@ export const setConfig = (
622623
outro(`${chalk.green('✔')} config successfully set`);
623624
};
624625

626+
// --- HELP MESSAGE GENERATION ---
627+
function getConfigKeyDetails(key) {
628+
switch (key) {
629+
case CONFIG_KEYS.OCO_MODEL:
630+
return {
631+
description: 'The AI model to use for generating commit messages',
632+
values: MODEL_LIST
633+
};
634+
case CONFIG_KEYS.OCO_AI_PROVIDER:
635+
return {
636+
description: 'The AI provider to use',
637+
values: Object.values(OCO_AI_PROVIDER_ENUM)
638+
};
639+
case CONFIG_KEYS.OCO_PROMPT_MODULE:
640+
return {
641+
description: 'The prompt module to use for commit message generation',
642+
values: Object.values(OCO_PROMPT_MODULE_ENUM)
643+
};
644+
case CONFIG_KEYS.OCO_LANGUAGE:
645+
return {
646+
description: 'The locale to use for commit messages',
647+
values: Object.keys(i18n)
648+
};
649+
case CONFIG_KEYS.OCO_TEST_MOCK_TYPE:
650+
return {
651+
description: 'The type of test mock to use',
652+
values: ['commit-message', 'prompt-module-commitlint-config']
653+
};
654+
case CONFIG_KEYS.OCO_ONE_LINE_COMMIT:
655+
return {
656+
description: 'One line commit message',
657+
values: ['true', 'false']
658+
};
659+
case CONFIG_KEYS.OCO_DESCRIPTION:
660+
return {
661+
description: 'Postface a message with ~3 sentences description of the changes',
662+
values: ['true', 'false']
663+
};
664+
case CONFIG_KEYS.OCO_EMOJI:
665+
return {
666+
description: 'Preface a message with GitMoji',
667+
values: ['true', 'false']
668+
};
669+
case CONFIG_KEYS.OCO_WHY:
670+
return {
671+
description: 'Output a short description of why the changes were done after the commit message (default: false)',
672+
values: ['true', 'false']
673+
}
674+
case CONFIG_KEYS.OCO_OMIT_SCOPE:
675+
return {
676+
description: 'Do not include a scope in the commit message',
677+
values: ['true', 'false']
678+
};
679+
case CONFIG_KEYS.OCO_GITPUSH:
680+
return {
681+
description: 'Push to git after commit (deprecated). If false, oco will exit after committing',
682+
values: ['true', 'false']
683+
};
684+
case CONFIG_KEYS.OCO_TOKENS_MAX_INPUT:
685+
return {
686+
description: 'Max model token limit',
687+
values: ['Any positive integer']
688+
};
689+
case CONFIG_KEYS.OCO_TOKENS_MAX_OUTPUT:
690+
return {
691+
description: 'Max response tokens',
692+
values: ['Any positive integer']
693+
};
694+
case CONFIG_KEYS.OCO_API_KEY:
695+
return {
696+
description: 'API key for the selected provider',
697+
values: ['String (required for most providers)']
698+
};
699+
case CONFIG_KEYS.OCO_API_URL:
700+
return {
701+
description: 'Custom API URL - may be used to set proxy path to OpenAI API',
702+
values: ["URL string (must start with 'http://' or 'https://')"]
703+
};
704+
case CONFIG_KEYS.OCO_MESSAGE_TEMPLATE_PLACEHOLDER:
705+
return {
706+
description: 'Message template placeholder',
707+
values: ["String (must start with $)"]
708+
};
709+
default:
710+
return {
711+
description: 'String value',
712+
values: ['Any string']
713+
};
714+
}
715+
}
716+
717+
function printConfigKeyHelp(param) {
718+
if (!Object.values(CONFIG_KEYS).includes(param)) {
719+
console.log(chalk.red(`Unknown config parameter: ${param}`));
720+
return;
721+
}
722+
723+
const details = getConfigKeyDetails(param as CONFIG_KEYS);
724+
725+
let desc = details.description;
726+
let defaultValue = undefined;
727+
if (param in DEFAULT_CONFIG) {
728+
defaultValue = DEFAULT_CONFIG[param];
729+
}
730+
731+
732+
console.log(chalk.bold(`\n${param}:`));
733+
console.log(chalk.gray(` Description: ${desc}`));
734+
if (defaultValue !== undefined) {
735+
// Print booleans and numbers as-is, strings without quotes
736+
if (typeof defaultValue === 'string') {
737+
console.log(chalk.gray(` Default: ${defaultValue}`));
738+
} else {
739+
console.log(chalk.gray(` Default: ${defaultValue}`));
740+
}
741+
}
742+
743+
if (Array.isArray(details.values)) {
744+
console.log(chalk.gray(' Accepted values:'));
745+
details.values.forEach(value => {
746+
console.log(chalk.gray(` - ${value}`));
747+
});
748+
} else {
749+
console.log(chalk.gray(' Accepted values by provider:'));
750+
Object.entries(details.values).forEach(([provider, values]) => {
751+
console.log(chalk.gray(` ${provider}:`));
752+
(values as string[]).forEach(value => {
753+
console.log(chalk.gray(` - ${value}`));
754+
});
755+
});
756+
}
757+
}
758+
759+
function printAllConfigHelp() {
760+
console.log(chalk.bold('Available config parameters:'));
761+
for (const key of Object.values(CONFIG_KEYS).sort()) {
762+
const details = getConfigKeyDetails(key);
763+
// Try to get the default value from DEFAULT_CONFIG
764+
let defaultValue = undefined;
765+
if (key in DEFAULT_CONFIG) {
766+
defaultValue = DEFAULT_CONFIG[key];
767+
}
768+
769+
console.log(chalk.bold(`\n${key}:`));
770+
console.log(chalk.gray(` Description: ${details.description}`));
771+
if (defaultValue !== undefined) {
772+
if (typeof defaultValue === 'string') {
773+
console.log(chalk.gray(` Default: ${defaultValue}`));
774+
} else {
775+
console.log(chalk.gray(` Default: ${defaultValue}`));
776+
}
777+
}
778+
}
779+
console.log(chalk.yellow('\nUse "oco config describe [PARAMETER]" to see accepted values and more details for a specific config parameter.'));
780+
}
781+
625782
export const configCommand = command(
626783
{
627784
name: COMMANDS.config,
628-
parameters: ['<mode>', '<key=values...>']
785+
parameters: ['<mode>', '[key=values...]'],
786+
help: {
787+
description: 'Configure opencommit settings',
788+
examples: [
789+
'Describe all config parameters: oco config describe',
790+
'Describe a specific parameter: oco config describe OCO_MODEL',
791+
'Get a config value: oco config get OCO_MODEL',
792+
'Set a config value: oco config set OCO_MODEL=gpt-4'
793+
]
794+
}
629795
},
630796
async (argv) => {
631797
try {
632798
const { mode, keyValues } = argv._;
633799
intro(`COMMAND: config ${mode} ${keyValues}`);
634800

635-
if (mode === CONFIG_MODES.get) {
801+
if (mode === CONFIG_MODES.describe) {
802+
if (!keyValues || keyValues.length === 0) {
803+
printAllConfigHelp();
804+
} else {
805+
for (const key of keyValues) {
806+
printConfigKeyHelp(key);
807+
}
808+
}
809+
process.exit(0);
810+
} else if (mode === CONFIG_MODES.get) {
811+
if (!keyValues || keyValues.length === 0) {
812+
throw new Error('No config keys specified for get mode');
813+
}
636814
const config = getConfig() || {};
637815
for (const key of keyValues) {
638816
outro(`${key}=${config[key as keyof typeof config]}`);
639817
}
640818
} else if (mode === CONFIG_MODES.set) {
819+
if (!keyValues || keyValues.length === 0) {
820+
throw new Error('No config keys specified for set mode');
821+
}
641822
await setConfig(
642823
keyValues.map((keyValue) => keyValue.split('=') as [string, string])
643824
);
644825
} else {
645826
throw new Error(
646-
`Unsupported mode: ${mode}. Valid modes are: "set" and "get"`
827+
`Unsupported mode: ${mode}. Valid modes are: "set", "get", and "describe"`
647828
);
648829
}
649830
} catch (error) {

0 commit comments

Comments
 (0)