codecrypto-cli 1.0.21 → 1.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/deploy-mcp.d.ts.map +1 -1
- package/dist/commands/deploy-mcp.js +162 -36
- package/dist/commands/deploy-mcp.js.map +1 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +162 -36
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +199 -14
- package/dist/commands/doctor.js.map +1 -1
- package/package.json +1 -1
- package/src/commands/deploy-mcp.ts +187 -42
- package/src/commands/deploy.ts +187 -42
- package/src/commands/doctor.ts +206 -19
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import ora from 'ora';
|
|
4
|
+
import inquirer from 'inquirer';
|
|
4
5
|
import { execSync, spawn } from 'child_process';
|
|
5
6
|
import * as fs from 'fs';
|
|
6
7
|
import * as path from 'path';
|
|
@@ -59,8 +60,8 @@ export const deployMcpCommand = new Command('deploy-mcp')
|
|
|
59
60
|
projectName = path.basename(resolvedProjectPath).toLowerCase().replace(/[^a-z0-9._-]/g, '-');
|
|
60
61
|
}
|
|
61
62
|
|
|
62
|
-
// Obtener el prefijo de imagen desde
|
|
63
|
-
const dockerHubUsername = getDockerHubUsernameFromToken();
|
|
63
|
+
// Obtener el prefijo de imagen desde Docker config o solicitar por teclado
|
|
64
|
+
const dockerHubUsername = await getDockerHubUsernameFromToken();
|
|
64
65
|
const imageBase = `${dockerHubUsername}/${projectName}`;
|
|
65
66
|
const imageName = `${imageBase}:${version}`;
|
|
66
67
|
const imageLatest = `${imageBase}:latest`;
|
|
@@ -458,14 +459,22 @@ echo "✅ Deployment preparation completed inside container"
|
|
|
458
459
|
}
|
|
459
460
|
|
|
460
461
|
// Paso 5: Construir y hacer push
|
|
461
|
-
|
|
462
|
+
// Detectar si estamos en Windows (buildx tiene problemas con ARM en Windows)
|
|
463
|
+
const isWindows = os.platform() === 'win32';
|
|
464
|
+
const platform = isWindows ? 'linux/amd64' : 'linux/amd64,linux/arm64';
|
|
465
|
+
const platformDisplay = isWindows ? 'linux/amd64' : 'linux/amd64, linux/arm64';
|
|
466
|
+
const buildSpinnerText = isWindows
|
|
467
|
+
? 'Building Docker image for linux/amd64...'
|
|
468
|
+
: 'Building Docker image for multiple platforms...';
|
|
469
|
+
|
|
470
|
+
const buildDockerSpinner = ora(buildSpinnerText).start();
|
|
462
471
|
try {
|
|
463
472
|
const tags = shouldPush
|
|
464
473
|
? [`--tag ${imageName}`, `--tag ${imageLatest}`, '--push']
|
|
465
474
|
: [`--tag ${imageName}`, `--tag ${imageLatest}`, '--load'];
|
|
466
475
|
|
|
467
476
|
const buildCommand = `docker buildx build \
|
|
468
|
-
--platform
|
|
477
|
+
--platform ${platform} \
|
|
469
478
|
${tags.join(' \\\n ')} \
|
|
470
479
|
--progress=plain \
|
|
471
480
|
.`;
|
|
@@ -475,7 +484,10 @@ echo "✅ Deployment preparation completed inside container"
|
|
|
475
484
|
console.log(chalk.cyan(buildCommand));
|
|
476
485
|
console.log(chalk.gray('─'.repeat(60)));
|
|
477
486
|
console.log(chalk.gray(`\n Working directory: ${chalk.cyan(resolvedDestFolder)}`));
|
|
478
|
-
console.log(chalk.gray(` Platforms: ${chalk.cyan(
|
|
487
|
+
console.log(chalk.gray(` Platforms: ${chalk.cyan(platformDisplay)}`));
|
|
488
|
+
if (isWindows) {
|
|
489
|
+
console.log(chalk.yellow(` Note: Building only for linux/amd64 on Windows (ARM builds are disabled)`));
|
|
490
|
+
}
|
|
479
491
|
console.log(chalk.gray(` Push to registry: ${shouldPush ? chalk.green('Yes') : chalk.yellow('No')}\n`));
|
|
480
492
|
|
|
481
493
|
execSync(buildCommand, {
|
|
@@ -564,49 +576,182 @@ echo "✅ Deployment preparation completed inside container"
|
|
|
564
576
|
}
|
|
565
577
|
});
|
|
566
578
|
|
|
567
|
-
// Función para obtener el username de Docker Hub desde
|
|
568
|
-
function getDockerHubUsernameFromToken(): string {
|
|
569
|
-
|
|
579
|
+
// Función para obtener el username de Docker Hub desde Docker config o solicitar por teclado
|
|
580
|
+
async function getDockerHubUsernameFromToken(): Promise<string> {
|
|
581
|
+
// Obtener el username desde Docker config (requerido para poder hacer push)
|
|
582
|
+
const dockerConfigPath = path.join(os.homedir(), '.docker', 'config.json');
|
|
570
583
|
|
|
571
|
-
if (!fs.existsSync(
|
|
572
|
-
throw new Error(
|
|
584
|
+
if (!fs.existsSync(dockerConfigPath)) {
|
|
585
|
+
throw new Error(
|
|
586
|
+
'Docker authentication not found. Please login to Docker first.\n' +
|
|
587
|
+
' Run: docker login\n' +
|
|
588
|
+
' This is required to push images to Docker Hub.'
|
|
589
|
+
);
|
|
573
590
|
}
|
|
574
591
|
|
|
575
|
-
let tokenData: any;
|
|
576
592
|
try {
|
|
577
|
-
|
|
593
|
+
const dockerConfig = JSON.parse(fs.readFileSync(dockerConfigPath, 'utf-8'));
|
|
594
|
+
|
|
595
|
+
// Verificar si hay credsStore (las credenciales están en el keychain del sistema)
|
|
596
|
+
const hasCredsStore = dockerConfig.credsStore && dockerConfig.credsStore !== '';
|
|
597
|
+
|
|
598
|
+
// Buscar username en Docker Hub auth
|
|
599
|
+
let dockerHubKeys: string[] = [];
|
|
600
|
+
if (dockerConfig.auths && Object.keys(dockerConfig.auths).length > 0) {
|
|
601
|
+
dockerHubKeys = Object.keys(dockerConfig.auths).filter(reg =>
|
|
602
|
+
reg.includes('docker.io') ||
|
|
603
|
+
reg.includes('hub.docker.com') ||
|
|
604
|
+
reg === 'https://index.docker.io/v1/'
|
|
605
|
+
);
|
|
606
|
+
|
|
607
|
+
// Si hay credsStore, los auths pueden estar vacíos pero las credenciales están en el keychain
|
|
608
|
+
if (hasCredsStore && dockerHubKeys.length > 0) {
|
|
609
|
+
// Intentar obtener username desde docker info
|
|
610
|
+
try {
|
|
611
|
+
const dockerInfo = execSync('docker info', { encoding: 'utf-8', stdio: 'pipe', timeout: 5000 });
|
|
612
|
+
const usernameMatch = dockerInfo.match(/Username:\s*(.+)/i);
|
|
613
|
+
if (usernameMatch && usernameMatch[1]) {
|
|
614
|
+
let username = usernameMatch[1].trim();
|
|
615
|
+
|
|
616
|
+
// Si el username es un email, extraer solo la parte antes del @
|
|
617
|
+
if (username.includes('@')) {
|
|
618
|
+
username = username.split('@')[0];
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// Sanitizar el username para Docker Hub
|
|
622
|
+
username = username.toLowerCase()
|
|
623
|
+
.replace(/[^a-z0-9._-]/g, '-')
|
|
624
|
+
.replace(/^-+|-+$/g, '')
|
|
625
|
+
.replace(/-+/g, '-')
|
|
626
|
+
.replace(/\.+/g, '.')
|
|
627
|
+
.substring(0, 30);
|
|
628
|
+
|
|
629
|
+
if (username) {
|
|
630
|
+
return username;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
} catch (infoError) {
|
|
634
|
+
// Si docker info falla, continuar con otros métodos
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// Si no hay credsStore, buscar username directamente en auths
|
|
639
|
+
if (!hasCredsStore) {
|
|
640
|
+
for (const key of dockerHubKeys) {
|
|
641
|
+
const authData = dockerConfig.auths[key];
|
|
642
|
+
if (authData && authData.username) {
|
|
643
|
+
let username = authData.username;
|
|
644
|
+
|
|
645
|
+
// Si el username es un email, extraer solo la parte antes del @
|
|
646
|
+
if (username.includes('@')) {
|
|
647
|
+
username = username.split('@')[0];
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
// Sanitizar el username para Docker Hub
|
|
651
|
+
username = username.toLowerCase()
|
|
652
|
+
.replace(/[^a-z0-9._-]/g, '-')
|
|
653
|
+
.replace(/^-+|-+$/g, '')
|
|
654
|
+
.replace(/-+/g, '-')
|
|
655
|
+
.replace(/\.+/g, '.')
|
|
656
|
+
.substring(0, 30);
|
|
657
|
+
|
|
658
|
+
if (username) {
|
|
659
|
+
return username;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
// Si hay credsStore pero no encontramos username, intentar con docker info
|
|
667
|
+
if (hasCredsStore) {
|
|
668
|
+
try {
|
|
669
|
+
const dockerInfo = execSync('docker info', { encoding: 'utf-8', stdio: 'pipe', timeout: 5000 });
|
|
670
|
+
const usernameMatch = dockerInfo.match(/Username:\s*(.+)/i);
|
|
671
|
+
if (usernameMatch && usernameMatch[1]) {
|
|
672
|
+
let username = usernameMatch[1].trim();
|
|
673
|
+
|
|
674
|
+
// Si el username es un email, extraer solo la parte antes del @
|
|
675
|
+
if (username.includes('@')) {
|
|
676
|
+
username = username.split('@')[0];
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// Sanitizar el username para Docker Hub
|
|
680
|
+
username = username.toLowerCase()
|
|
681
|
+
.replace(/[^a-z0-9._-]/g, '-')
|
|
682
|
+
.replace(/^-+|-+$/g, '')
|
|
683
|
+
.replace(/-+/g, '-')
|
|
684
|
+
.replace(/\.+/g, '.')
|
|
685
|
+
.substring(0, 30);
|
|
686
|
+
|
|
687
|
+
if (username) {
|
|
688
|
+
return username;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
} catch (infoError) {
|
|
692
|
+
// Continuar con el error
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// Si llegamos aquí, no encontramos el username - solicitar por teclado
|
|
697
|
+
console.log(chalk.yellow('\n⚠️ Could not automatically detect Docker Hub username.'));
|
|
698
|
+
console.log(chalk.gray(' Please enter your Docker Hub username manually.\n'));
|
|
699
|
+
|
|
700
|
+
const answer = await inquirer.prompt([
|
|
701
|
+
{
|
|
702
|
+
type: 'input',
|
|
703
|
+
name: 'username',
|
|
704
|
+
message: 'Docker Hub username:',
|
|
705
|
+
validate: (input: string) => {
|
|
706
|
+
if (!input || input.trim().length === 0) {
|
|
707
|
+
return 'Username is required';
|
|
708
|
+
}
|
|
709
|
+
// Validar formato básico de username Docker Hub
|
|
710
|
+
const sanitized = input.toLowerCase().replace(/[^a-z0-9._-]/g, '');
|
|
711
|
+
if (sanitized !== input.toLowerCase()) {
|
|
712
|
+
return 'Username can only contain lowercase letters, numbers, dots, hyphens, and underscores';
|
|
713
|
+
}
|
|
714
|
+
if (input.length > 30) {
|
|
715
|
+
return 'Username must be 30 characters or less';
|
|
716
|
+
}
|
|
717
|
+
return true;
|
|
718
|
+
},
|
|
719
|
+
filter: (input: string) => {
|
|
720
|
+
// Si el input es un email, extraer solo la parte antes del @
|
|
721
|
+
if (input.includes('@')) {
|
|
722
|
+
return input.split('@')[0].trim();
|
|
723
|
+
}
|
|
724
|
+
return input.trim();
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
]);
|
|
728
|
+
|
|
729
|
+
let username = answer.username.toLowerCase();
|
|
730
|
+
|
|
731
|
+
// Sanitizar el username para Docker Hub
|
|
732
|
+
username = username
|
|
733
|
+
.replace(/[^a-z0-9._-]/g, '-')
|
|
734
|
+
.replace(/^-+|-+$/g, '')
|
|
735
|
+
.replace(/-+/g, '-')
|
|
736
|
+
.replace(/\.+/g, '.')
|
|
737
|
+
.substring(0, 30);
|
|
738
|
+
|
|
739
|
+
if (!username) {
|
|
740
|
+
throw new Error('Invalid username provided');
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
return username;
|
|
578
744
|
} catch (error: any) {
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
// Extraer el username del email (parte antes del @) y sanitizarlo para Docker Hub
|
|
589
|
-
const emailParts = email.split('@');
|
|
590
|
-
if (emailParts.length < 2) {
|
|
591
|
-
throw new Error(`Invalid email format in token.json: ${email}`);
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
let username = emailParts[0].toLowerCase();
|
|
595
|
-
|
|
596
|
-
// Sanitizar el username para Docker Hub
|
|
597
|
-
// Docker Hub permite: letras minúsculas, números, guiones, guiones bajos
|
|
598
|
-
username = username
|
|
599
|
-
.replace(/[^a-z0-9._-]/g, '-') // Reemplazar caracteres inválidos con guiones
|
|
600
|
-
.replace(/^-+|-+$/g, '') // Eliminar guiones al inicio y final
|
|
601
|
-
.replace(/-+/g, '-') // Reemplazar múltiples guiones con uno solo
|
|
602
|
-
.replace(/\.+/g, '.') // Reemplazar múltiples puntos con uno solo
|
|
603
|
-
.substring(0, 30); // Limitar longitud (Docker Hub tiene límites)
|
|
604
|
-
|
|
605
|
-
if (!username) {
|
|
606
|
-
throw new Error(`Could not extract valid username from email: ${email}`);
|
|
745
|
+
// Si el error ya tiene mensaje, relanzarlo
|
|
746
|
+
if (error.message && (error.message.includes('Docker') || error.message.includes('username'))) {
|
|
747
|
+
throw error;
|
|
748
|
+
}
|
|
749
|
+
// Si hay error leyendo Docker config, lanzar error
|
|
750
|
+
throw new Error(
|
|
751
|
+
`Failed to read Docker config: ${error.message || String(error)}\n` +
|
|
752
|
+
' Please ensure you are logged in to Docker: docker login'
|
|
753
|
+
);
|
|
607
754
|
}
|
|
608
|
-
|
|
609
|
-
return username;
|
|
610
755
|
}
|
|
611
756
|
|
|
612
757
|
// Función para leer certificados Docker desde token.json
|
package/src/commands/deploy.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import ora from 'ora';
|
|
4
|
+
import inquirer from 'inquirer';
|
|
4
5
|
import { execSync, spawn } from 'child_process';
|
|
5
6
|
import * as fs from 'fs';
|
|
6
7
|
import * as path from 'path';
|
|
@@ -134,8 +135,8 @@ export const deployCommand = new Command('deploy')
|
|
|
134
135
|
projectName = path.basename(resolvedProjectPath).toLowerCase().replace(/[^a-z0-9._-]/g, '-');
|
|
135
136
|
}
|
|
136
137
|
|
|
137
|
-
// Obtener el prefijo de imagen desde
|
|
138
|
-
const dockerHubUsername = getDockerHubUsernameFromToken();
|
|
138
|
+
// Obtener el prefijo de imagen desde Docker config o solicitar por teclado
|
|
139
|
+
const dockerHubUsername = await getDockerHubUsernameFromToken();
|
|
139
140
|
const imageBase = `${dockerHubUsername}/${projectName}`;
|
|
140
141
|
const imageName = `${imageBase}:${version}`;
|
|
141
142
|
const imageLatest = `${imageBase}:latest`;
|
|
@@ -615,14 +616,22 @@ CMD ${JSON.stringify(startCmd)}
|
|
|
615
616
|
}
|
|
616
617
|
|
|
617
618
|
// Paso 5: Construir y hacer push
|
|
618
|
-
|
|
619
|
+
// Detectar si estamos en Windows (buildx tiene problemas con ARM en Windows)
|
|
620
|
+
const isWindows = os.platform() === 'win32';
|
|
621
|
+
const platform = isWindows ? 'linux/amd64' : 'linux/amd64,linux/arm64';
|
|
622
|
+
const platformDisplay = isWindows ? 'linux/amd64' : 'linux/amd64, linux/arm64';
|
|
623
|
+
const buildSpinnerText = isWindows
|
|
624
|
+
? 'Building Docker image for linux/amd64...'
|
|
625
|
+
: 'Building Docker image for multiple platforms...';
|
|
626
|
+
|
|
627
|
+
const buildDockerSpinner = ora(buildSpinnerText).start();
|
|
619
628
|
try {
|
|
620
629
|
const tags = shouldPush
|
|
621
630
|
? [`--tag ${imageName}`, `--tag ${imageLatest}`, '--push']
|
|
622
631
|
: [`--tag ${imageName}`, `--tag ${imageLatest}`, '--load'];
|
|
623
632
|
|
|
624
633
|
const buildCommand = `docker buildx build \
|
|
625
|
-
--platform
|
|
634
|
+
--platform ${platform} \
|
|
626
635
|
${tags.join(' \\\n ')} \
|
|
627
636
|
--progress=plain \
|
|
628
637
|
.`;
|
|
@@ -632,7 +641,10 @@ CMD ${JSON.stringify(startCmd)}
|
|
|
632
641
|
console.log(chalk.cyan(buildCommand));
|
|
633
642
|
console.log(chalk.gray('─'.repeat(60)));
|
|
634
643
|
console.log(chalk.gray(`\n Working directory: ${chalk.cyan(resolvedDestFolder)}`));
|
|
635
|
-
console.log(chalk.gray(` Platforms: ${chalk.cyan(
|
|
644
|
+
console.log(chalk.gray(` Platforms: ${chalk.cyan(platformDisplay)}`));
|
|
645
|
+
if (isWindows) {
|
|
646
|
+
console.log(chalk.yellow(` Note: Building only for linux/amd64 on Windows (ARM builds are disabled)`));
|
|
647
|
+
}
|
|
636
648
|
console.log(chalk.gray(` Push to registry: ${shouldPush ? chalk.green('Yes') : chalk.yellow('No')}\n`));
|
|
637
649
|
|
|
638
650
|
execSync(buildCommand, {
|
|
@@ -702,49 +714,182 @@ CMD ${JSON.stringify(startCmd)}
|
|
|
702
714
|
}
|
|
703
715
|
});
|
|
704
716
|
|
|
705
|
-
// Función para obtener el username de Docker Hub desde
|
|
706
|
-
function getDockerHubUsernameFromToken(): string {
|
|
707
|
-
|
|
717
|
+
// Función para obtener el username de Docker Hub desde Docker config o solicitar por teclado
|
|
718
|
+
async function getDockerHubUsernameFromToken(): Promise<string> {
|
|
719
|
+
// Obtener el username desde Docker config (requerido para poder hacer push)
|
|
720
|
+
const dockerConfigPath = path.join(os.homedir(), '.docker', 'config.json');
|
|
708
721
|
|
|
709
|
-
if (!fs.existsSync(
|
|
710
|
-
throw new Error(
|
|
722
|
+
if (!fs.existsSync(dockerConfigPath)) {
|
|
723
|
+
throw new Error(
|
|
724
|
+
'Docker authentication not found. Please login to Docker first.\n' +
|
|
725
|
+
' Run: docker login\n' +
|
|
726
|
+
' This is required to push images to Docker Hub.'
|
|
727
|
+
);
|
|
711
728
|
}
|
|
712
729
|
|
|
713
|
-
let tokenData: any;
|
|
714
730
|
try {
|
|
715
|
-
|
|
731
|
+
const dockerConfig = JSON.parse(fs.readFileSync(dockerConfigPath, 'utf-8'));
|
|
732
|
+
|
|
733
|
+
// Verificar si hay credsStore (las credenciales están en el keychain del sistema)
|
|
734
|
+
const hasCredsStore = dockerConfig.credsStore && dockerConfig.credsStore !== '';
|
|
735
|
+
|
|
736
|
+
// Buscar username en Docker Hub auth
|
|
737
|
+
let dockerHubKeys: string[] = [];
|
|
738
|
+
if (dockerConfig.auths && Object.keys(dockerConfig.auths).length > 0) {
|
|
739
|
+
dockerHubKeys = Object.keys(dockerConfig.auths).filter(reg =>
|
|
740
|
+
reg.includes('docker.io') ||
|
|
741
|
+
reg.includes('hub.docker.com') ||
|
|
742
|
+
reg === 'https://index.docker.io/v1/'
|
|
743
|
+
);
|
|
744
|
+
|
|
745
|
+
// Si hay credsStore, los auths pueden estar vacíos pero las credenciales están en el keychain
|
|
746
|
+
if (hasCredsStore && dockerHubKeys.length > 0) {
|
|
747
|
+
// Intentar obtener username desde docker info
|
|
748
|
+
try {
|
|
749
|
+
const dockerInfo = execSync('docker info', { encoding: 'utf-8', stdio: 'pipe', timeout: 5000 });
|
|
750
|
+
const usernameMatch = dockerInfo.match(/Username:\s*(.+)/i);
|
|
751
|
+
if (usernameMatch && usernameMatch[1]) {
|
|
752
|
+
let username = usernameMatch[1].trim();
|
|
753
|
+
|
|
754
|
+
// Si el username es un email, extraer solo la parte antes del @
|
|
755
|
+
if (username.includes('@')) {
|
|
756
|
+
username = username.split('@')[0];
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
// Sanitizar el username para Docker Hub
|
|
760
|
+
username = username.toLowerCase()
|
|
761
|
+
.replace(/[^a-z0-9._-]/g, '-')
|
|
762
|
+
.replace(/^-+|-+$/g, '')
|
|
763
|
+
.replace(/-+/g, '-')
|
|
764
|
+
.replace(/\.+/g, '.')
|
|
765
|
+
.substring(0, 30);
|
|
766
|
+
|
|
767
|
+
if (username) {
|
|
768
|
+
return username;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
} catch (infoError) {
|
|
772
|
+
// Si docker info falla, continuar con otros métodos
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// Si no hay credsStore, buscar username directamente en auths
|
|
777
|
+
if (!hasCredsStore) {
|
|
778
|
+
for (const key of dockerHubKeys) {
|
|
779
|
+
const authData = dockerConfig.auths[key];
|
|
780
|
+
if (authData && authData.username) {
|
|
781
|
+
let username = authData.username;
|
|
782
|
+
|
|
783
|
+
// Si el username es un email, extraer solo la parte antes del @
|
|
784
|
+
if (username.includes('@')) {
|
|
785
|
+
username = username.split('@')[0];
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
// Sanitizar el username para Docker Hub
|
|
789
|
+
username = username.toLowerCase()
|
|
790
|
+
.replace(/[^a-z0-9._-]/g, '-')
|
|
791
|
+
.replace(/^-+|-+$/g, '')
|
|
792
|
+
.replace(/-+/g, '-')
|
|
793
|
+
.replace(/\.+/g, '.')
|
|
794
|
+
.substring(0, 30);
|
|
795
|
+
|
|
796
|
+
if (username) {
|
|
797
|
+
return username;
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
// Si hay credsStore pero no encontramos username, intentar con docker info
|
|
805
|
+
if (hasCredsStore) {
|
|
806
|
+
try {
|
|
807
|
+
const dockerInfo = execSync('docker info', { encoding: 'utf-8', stdio: 'pipe', timeout: 5000 });
|
|
808
|
+
const usernameMatch = dockerInfo.match(/Username:\s*(.+)/i);
|
|
809
|
+
if (usernameMatch && usernameMatch[1]) {
|
|
810
|
+
let username = usernameMatch[1].trim();
|
|
811
|
+
|
|
812
|
+
// Si el username es un email, extraer solo la parte antes del @
|
|
813
|
+
if (username.includes('@')) {
|
|
814
|
+
username = username.split('@')[0];
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
// Sanitizar el username para Docker Hub
|
|
818
|
+
username = username.toLowerCase()
|
|
819
|
+
.replace(/[^a-z0-9._-]/g, '-')
|
|
820
|
+
.replace(/^-+|-+$/g, '')
|
|
821
|
+
.replace(/-+/g, '-')
|
|
822
|
+
.replace(/\.+/g, '.')
|
|
823
|
+
.substring(0, 30);
|
|
824
|
+
|
|
825
|
+
if (username) {
|
|
826
|
+
return username;
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
} catch (infoError) {
|
|
830
|
+
// Continuar con el error
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// Si llegamos aquí, no encontramos el username - solicitar por teclado
|
|
835
|
+
console.log(chalk.yellow('\n⚠️ Could not automatically detect Docker Hub username.'));
|
|
836
|
+
console.log(chalk.gray(' Please enter your Docker Hub username manually.\n'));
|
|
837
|
+
|
|
838
|
+
const answer = await inquirer.prompt([
|
|
839
|
+
{
|
|
840
|
+
type: 'input',
|
|
841
|
+
name: 'username',
|
|
842
|
+
message: 'Docker Hub username:',
|
|
843
|
+
validate: (input: string) => {
|
|
844
|
+
if (!input || input.trim().length === 0) {
|
|
845
|
+
return 'Username is required';
|
|
846
|
+
}
|
|
847
|
+
// Validar formato básico de username Docker Hub
|
|
848
|
+
const sanitized = input.toLowerCase().replace(/[^a-z0-9._-]/g, '');
|
|
849
|
+
if (sanitized !== input.toLowerCase()) {
|
|
850
|
+
return 'Username can only contain lowercase letters, numbers, dots, hyphens, and underscores';
|
|
851
|
+
}
|
|
852
|
+
if (input.length > 30) {
|
|
853
|
+
return 'Username must be 30 characters or less';
|
|
854
|
+
}
|
|
855
|
+
return true;
|
|
856
|
+
},
|
|
857
|
+
filter: (input: string) => {
|
|
858
|
+
// Si el input es un email, extraer solo la parte antes del @
|
|
859
|
+
if (input.includes('@')) {
|
|
860
|
+
return input.split('@')[0].trim();
|
|
861
|
+
}
|
|
862
|
+
return input.trim();
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
]);
|
|
866
|
+
|
|
867
|
+
let username = answer.username.toLowerCase();
|
|
868
|
+
|
|
869
|
+
// Sanitizar el username para Docker Hub
|
|
870
|
+
username = username
|
|
871
|
+
.replace(/[^a-z0-9._-]/g, '-')
|
|
872
|
+
.replace(/^-+|-+$/g, '')
|
|
873
|
+
.replace(/-+/g, '-')
|
|
874
|
+
.replace(/\.+/g, '.')
|
|
875
|
+
.substring(0, 30);
|
|
876
|
+
|
|
877
|
+
if (!username) {
|
|
878
|
+
throw new Error('Invalid username provided');
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
return username;
|
|
716
882
|
} catch (error: any) {
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
// Extraer el username del email (parte antes del @) y sanitizarlo para Docker Hub
|
|
727
|
-
const emailParts = email.split('@');
|
|
728
|
-
if (emailParts.length < 2) {
|
|
729
|
-
throw new Error(`Invalid email format in token.json: ${email}`);
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
let username = emailParts[0].toLowerCase();
|
|
733
|
-
|
|
734
|
-
// Sanitizar el username para Docker Hub
|
|
735
|
-
// Docker Hub permite: letras minúsculas, números, guiones, guiones bajos
|
|
736
|
-
username = username
|
|
737
|
-
.replace(/[^a-z0-9._-]/g, '-') // Reemplazar caracteres inválidos con guiones
|
|
738
|
-
.replace(/^-+|-+$/g, '') // Eliminar guiones al inicio y final
|
|
739
|
-
.replace(/-+/g, '-') // Reemplazar múltiples guiones con uno solo
|
|
740
|
-
.replace(/\.+/g, '.') // Reemplazar múltiples puntos con uno solo
|
|
741
|
-
.substring(0, 30); // Limitar longitud (Docker Hub tiene límites)
|
|
742
|
-
|
|
743
|
-
if (!username) {
|
|
744
|
-
throw new Error(`Could not extract valid username from email: ${email}`);
|
|
883
|
+
// Si el error ya tiene mensaje, relanzarlo
|
|
884
|
+
if (error.message && (error.message.includes('Docker') || error.message.includes('username'))) {
|
|
885
|
+
throw error;
|
|
886
|
+
}
|
|
887
|
+
// Si hay error leyendo Docker config, lanzar error
|
|
888
|
+
throw new Error(
|
|
889
|
+
`Failed to read Docker config: ${error.message || String(error)}\n` +
|
|
890
|
+
' Please ensure you are logged in to Docker: docker login'
|
|
891
|
+
);
|
|
745
892
|
}
|
|
746
|
-
|
|
747
|
-
return username;
|
|
748
893
|
}
|
|
749
894
|
|
|
750
895
|
// Función para leer certificados Docker desde token.json
|