Skip to content

Commit bec03b8

Browse files
authored
Merge pull request #38 from YagoBorba/feature/26-improve-test-coverage
Feature/26 improve test coverage
2 parents 2484faa + e64777d commit bec03b8

14 files changed

Lines changed: 880 additions & 118 deletions

File tree

.gitignore

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1+
cat <<EOF > .gitignore
12
# Dependencies
2-
/node_modules
3-
/.pnp
3+
node_modules/
4+
.pnp
45
.pnp.js
56
.yarn/install-state.gz
67

78
# Production
8-
/build
9-
/dist
10-
/.out
9+
build/
10+
dist/
11+
.out/
1112

1213
# Misc
1314
.DS_Store
@@ -27,12 +28,13 @@ lerna-debug.log*
2728
.env.production.local
2829

2930
# IDEs and editors
30-
/.vscode/*
31+
.vscode/*
3132
!.vscode/settings.json
3233
!.vscode/tasks.json
3334
!.vscode/launch.json
3435
!.vscode/extensions.json
3536
*.sublime-workspace
3637

3738
# TypeScript
38-
*.tsbuildinfo
39+
*.tsbuildinfo
40+
EOF

package-lock.json

Lines changed: 7 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 102 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,35 @@
1+
// packages/cli/src/commands/config.ts
12
import chalk from 'chalk';
23
import Configstore from 'configstore';
34
import inquirer from 'inquirer';
45
import fs from 'fs/promises';
56
import path from 'path';
67
import { t } from '@stackcode/i18n';
8+
const globalConfig = new Configstore('@stackcode/cli');
9+
/**
10+
* Handles the non-interactive command logic based on provided arguments.
11+
* This function is easily testable in isolation.
12+
* @param argv - The arguments object from yargs.
13+
*/
14+
export async function handleNonInteractiveMode(argv) {
15+
switch (argv.action) {
16+
case 'set':
17+
if (!argv.key || !argv.value) {
18+
console.error(chalk.red(t('config.error.missing_set_args')));
19+
return;
20+
}
21+
globalConfig.set(argv.key, argv.value);
22+
console.log(chalk.green(t('config.success.set', { key: argv.key, value: argv.value })));
23+
break;
24+
// Futuras implementações não-interativas (get, delete, etc.) podem ser adicionadas aqui.
25+
default:
26+
console.error(chalk.yellow(t('config.error.invalid_action', { action: argv.action || 'unknown' })));
27+
break;
28+
}
29+
}
30+
/**
31+
* Finds the project root by looking for a package.json file.
32+
*/
733
const findProjectRoot = async (startPath) => {
834
let currentPath = startPath;
935
while (currentPath !== path.parse(currentPath).root) {
@@ -16,57 +42,87 @@ const findProjectRoot = async (startPath) => {
1642
}
1743
return null;
1844
};
19-
const globalConfig = new Configstore('@stackcode/cli');
20-
export const getConfigCommand = () => ({
21-
command: 'config',
22-
describe: t('config.command_description'),
23-
builder: {},
24-
handler: async () => {
25-
const { choice } = await inquirer.prompt([
45+
/**
46+
* Runs the fully interactive configuration session using inquirer.
47+
*/
48+
export async function runInteractiveMode() {
49+
const { choice } = await inquirer.prompt([
50+
{
51+
type: 'list', name: 'choice', message: t('config.prompt.main'),
52+
choices: [
53+
{ name: t('config.prompt.select_lang'), value: 'lang' },
54+
{ name: t('config.prompt.toggle_validation'), value: 'commitValidation' },
55+
],
56+
}
57+
]);
58+
if (choice === 'lang') {
59+
const { lang } = await inquirer.prompt([
2660
{
27-
type: 'list', name: 'choice', message: t('config.prompt.main'),
28-
choices: [
29-
{ name: t('config.prompt.select_lang'), value: 'lang' },
30-
{ name: t('config.prompt.toggle_validation'), value: 'commitValidation' },
31-
],
61+
type: 'list', name: 'lang', message: t('config.prompt.select_lang'),
62+
choices: [{ name: 'English', value: 'en' }, { name: 'Português', value: 'pt' }],
3263
}
3364
]);
34-
if (choice === 'lang') {
35-
const { lang } = await inquirer.prompt([
36-
{
37-
type: 'list', name: 'lang', message: t('config.prompt.select_lang'),
38-
choices: [{ name: 'English', value: 'en' }, { name: 'Português', value: 'pt' }],
39-
}
40-
]);
41-
globalConfig.set('lang', lang);
42-
console.log(chalk.green(t('config.success.set', { key: 'lang', value: lang })));
65+
globalConfig.set('lang', lang);
66+
console.log(chalk.green(t('config.success.set', { key: 'lang', value: lang })));
67+
}
68+
else if (choice === 'commitValidation') {
69+
const projectRoot = await findProjectRoot(process.cwd());
70+
if (!projectRoot) {
71+
console.error(chalk.red(t('config.error.not_in_project')));
72+
return;
4373
}
44-
else if (choice === 'commitValidation') {
45-
const projectRoot = await findProjectRoot(process.cwd());
46-
if (!projectRoot) {
47-
console.error(chalk.red(t('config.error.not_in_project')));
48-
return;
49-
}
50-
const localConfigPath = path.join(projectRoot, '.stackcoderc.json');
51-
try {
52-
await fs.access(localConfigPath);
53-
}
54-
catch {
55-
console.error(chalk.red(t('config.error.not_in_project')));
56-
return;
74+
const localConfigPath = path.join(projectRoot, '.stackcoderc.json');
75+
try {
76+
await fs.access(localConfigPath);
77+
}
78+
catch {
79+
console.error(chalk.red(t('config.error.no_stackcoderc')));
80+
return;
81+
}
82+
const { enable } = await inquirer.prompt([
83+
{
84+
type: 'confirm', name: 'enable', message: t('config.prompt.toggle_validation'),
85+
default: true,
5786
}
58-
const { enable } = await inquirer.prompt([
59-
{
60-
type: 'confirm', name: 'enable', message: t('config.prompt.toggle_validation'),
61-
default: true,
62-
}
63-
]);
64-
const localConfigContent = await fs.readFile(localConfigPath, 'utf-8');
65-
const localConfig = JSON.parse(localConfigContent);
66-
localConfig.features.commitValidation = enable;
67-
await fs.writeFile(localConfigPath, JSON.stringify(localConfig, null, 2));
68-
const status = enable ? t('config.status.enabled') : t('config.status.disabled');
69-
console.log(chalk.green(t('config.success.set_validation', { status })));
87+
]);
88+
const localConfigContent = await fs.readFile(localConfigPath, 'utf-8');
89+
const localConfig = JSON.parse(localConfigContent);
90+
localConfig.features.commitValidation = enable;
91+
await fs.writeFile(localConfigPath, JSON.stringify(localConfig, null, 2));
92+
const status = enable ? t('config.status.enabled') : t('config.status.disabled');
93+
console.log(chalk.green(t('config.success.set_validation', { status })));
94+
}
95+
}
96+
/**
97+
* Defines the 'config' command, its arguments, and the handler logic.
98+
*/
99+
export const getConfigCommand = () => ({
100+
command: 'config [action] [key] [value]',
101+
describe: t('config.command_description'),
102+
builder: (yargs) => {
103+
return yargs
104+
.positional('action', {
105+
describe: t('config.args.action_description'),
106+
type: 'string',
107+
choices: ['set'], // Apenas 'set' está implementado no modo não-interativo por enquanto
108+
})
109+
.positional('key', {
110+
describe: t('config.args.key_description'),
111+
type: 'string',
112+
})
113+
.positional('value', {
114+
describe: t('config.args.value_description'),
115+
type: 'string',
116+
});
117+
},
118+
handler: async (argv) => {
119+
// The handler is now an orchestrator.
120+
const isInteractive = !argv.action;
121+
if (isInteractive) {
122+
await runInteractiveMode();
123+
}
124+
else {
125+
await handleNonInteractiveMode(argv);
70126
}
71127
},
72128
});

packages/cli/dist/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ async function main() {
1515
const locale = getLocale();
1616
yargs(hideBin(process.argv))
1717
.scriptName("stackcode")
18-
.version('1.0.0')
18+
.version('1.0.3')
1919
.alias('h', 'help')
2020
.alias('v', 'version')
2121
.strict()

packages/cli/package.json

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,17 @@
1111
"scripts": {
1212
"clean": "rm -rf dist tsconfig.tsbuildinfo",
1313
"build": "tsc && chmod +x dist/index.js",
14-
"test": "echo \"✅ No tests for this package\""
14+
"test": "vitest run"
1515
},
16-
"keywords": ["cli", "scaffolding", "conventional-commits", "gitflow", "automation", "devops", "typescript"],
16+
"keywords": [
17+
"cli",
18+
"scaffolding",
19+
"conventional-commits",
20+
"gitflow",
21+
"automation",
22+
"devops",
23+
"typescript"
24+
],
1725
"author": "Yago Borba",
1826
"license": "MIT",
1927
"homepage": "https://github.com/YagoBorba/StackCode#readme",
@@ -42,6 +50,7 @@
4250
"@types/open": "^6.1.0",
4351
"@types/semver": "^7.7.0",
4452
"@types/yargs": "^17.0.32",
45-
"typescript": "^5.5.2"
53+
"typescript": "^5.5.2",
54+
"vitest": "^3.2.4"
4655
}
47-
}
56+
}

0 commit comments

Comments
 (0)