cdd-cli 3.1.0 → 3.1.2
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/.github/ISSUE_TEMPLATE/bug_report.md +30 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +19 -0
- package/.github/PULL_REQUEST_TEMPLATE/pull_request.md +14 -0
- package/CHANGELOG.md +7 -0
- package/README.md +16 -0
- package/fix-imports.cjs +3 -0
- package/package.json +1 -1
- package/src/App.jsx +0 -2
- package/src/components/ContainerList.jsx +1 -3
- package/src/components/ContainerRow.jsx +1 -1
- package/src/helpers/actionHelpers.js +13 -0
- package/src/helpers/dockerService/serviceComponents/containerActions.js +30 -0
- package/src/helpers/dockerService/serviceComponents/containerList.js +5 -1
- package/src/helpers/dockerService/serviceComponents/containerLogs.js +8 -0
- package/src/helpers/dockerService/serviceComponents/containerStats.js +6 -0
- package/src/helpers/dockerService/serviceComponents/imageUtils.js +10 -0
- package/src/helpers/exitWithMessage.js +10 -0
- package/src/hooks/useContainers.js +1 -3
- package/src/hooks/useControls.js +24 -1
- package/src/hooks/useLogsStream.js +5 -0
- package/src/index.js +1 -5
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: Create a report to help us improve
|
|
4
|
+
title: ''
|
|
5
|
+
labels: bug
|
|
6
|
+
assignees: ''
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
**Describe the bug**
|
|
10
|
+
A clear and concise description of what the bug is.
|
|
11
|
+
|
|
12
|
+
**To Reproduce**
|
|
13
|
+
Steps to reproduce the behavior:
|
|
14
|
+
1. Go to '...'
|
|
15
|
+
2. Run '...'
|
|
16
|
+
3. See error
|
|
17
|
+
|
|
18
|
+
**Expected behavior**
|
|
19
|
+
A clear and concise description of what you expected to happen.
|
|
20
|
+
|
|
21
|
+
**Screenshots or logs**
|
|
22
|
+
If applicable, add screenshots or logs to help explain your problem.
|
|
23
|
+
|
|
24
|
+
**Environment (please complete the following information):**
|
|
25
|
+
- OS: (e.g. Ubuntu 22.04)
|
|
26
|
+
- Node version: (e.g. 18.x)
|
|
27
|
+
- cdd-cli version: (e.g. 3.1.0)
|
|
28
|
+
|
|
29
|
+
**Additional context**
|
|
30
|
+
Add any other context about the problem here.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature request
|
|
3
|
+
about: Suggest an idea for this project
|
|
4
|
+
title: ''
|
|
5
|
+
labels: enhancement
|
|
6
|
+
assignees: ''
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
**Is your feature request related to a problem? Please describe.**
|
|
10
|
+
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
|
11
|
+
|
|
12
|
+
**Describe the solution you'd like**
|
|
13
|
+
A clear and concise description of what you want to happen.
|
|
14
|
+
|
|
15
|
+
**Describe alternatives you've considered**
|
|
16
|
+
A clear and concise description of any alternative solutions or features you've considered.
|
|
17
|
+
|
|
18
|
+
**Additional context**
|
|
19
|
+
Add any other context or screenshots about the feature request here.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<!-- Please replace the placeholders and remove this comment -->
|
|
2
|
+
## Summary
|
|
3
|
+
|
|
4
|
+
What does this PR change and why?
|
|
5
|
+
|
|
6
|
+
## Checklist
|
|
7
|
+
|
|
8
|
+
- [ ] I have read the contributing guidelines
|
|
9
|
+
- [ ] Tests added / updated
|
|
10
|
+
- [ ] Documentation updated
|
|
11
|
+
|
|
12
|
+
## Related issues
|
|
13
|
+
|
|
14
|
+
Closes: # (issue)
|
package/CHANGELOG.md
CHANGED
|
@@ -25,3 +25,10 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
|
25
25
|
## [Unreleased]
|
|
26
26
|
|
|
27
27
|
- Incoming fixes and smaller tests / docs updates
|
|
28
|
+
|
|
29
|
+
## [3.1.1] - 2025-10-16
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- Minor docs typo fixes and README global install note added.
|
|
34
|
+
|
package/README.md
CHANGED
|
@@ -53,6 +53,22 @@ The dashboard auto-refreshes container list every few seconds.
|
|
|
53
53
|
|
|
54
54
|
---
|
|
55
55
|
|
|
56
|
+
## Install globally
|
|
57
|
+
|
|
58
|
+
To install the CLI globally so you can run `cdd` from any terminal, use:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm install -g cdd-cli
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
After installing globally, run the CLI with:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
cdd
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
56
72
|
## Development
|
|
57
73
|
|
|
58
74
|
- Node.js >= 18 is recommended.
|
package/fix-imports.cjs
CHANGED
|
@@ -7,6 +7,9 @@ function addJsExtensionToImports(filePath) {
|
|
|
7
7
|
// Reemplaza imports relativos sin extensión por .js
|
|
8
8
|
code = code.replace(/(import\s+[^'";]+['"])(\.\/[^'".]+)(['"])/g, '$1$2.js$3');
|
|
9
9
|
code = code.replace(/(from\s+['"])(\.{1,2}\/[^'".]+)(['"])/g, '$1$2.js$3');
|
|
10
|
+
// También reemplaza importaciones que apunten a archivos .jsx por .js
|
|
11
|
+
code = code.replace(/(from\s+['"])(\.{1,2}\/[^'"\s]+)\.jsx(['"])/g, '$1$2.js$3');
|
|
12
|
+
code = code.replace(/(import\s+[^'";]+['"])(\.{1,2}\/[^'"\s]+)\.jsx(['"])/g, '$1$2.js$3');
|
|
10
13
|
fs.writeFileSync(filePath, code, 'utf8');
|
|
11
14
|
}
|
|
12
15
|
|
package/package.json
CHANGED
package/src/App.jsx
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Main React component for the CDD CLI UI.
|
|
3
|
-
* Componente principal de React para la UI del CLI CDD.
|
|
4
3
|
*
|
|
5
4
|
* @component
|
|
6
5
|
* @returns {JSX.Element} The rendered app / La app renderizada
|
|
7
6
|
* @example
|
|
8
7
|
* // EN: Render the app
|
|
9
|
-
* // ES: Renderizar la app
|
|
10
8
|
* <App />
|
|
11
9
|
*/
|
|
12
10
|
import React from "react";
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* List component for Docker containers.
|
|
3
|
-
* Componente de lista para contenedores Docker.
|
|
4
3
|
*
|
|
5
4
|
* @component
|
|
6
5
|
* @param {Object} props - Component props / Props del componente
|
|
7
6
|
* @param {Array} props.containers - Containers to display / Contenedores a mostrar
|
|
8
7
|
* @returns {JSX.Element} Rendered list / Lista renderizada
|
|
9
8
|
* @example
|
|
10
|
-
* //
|
|
11
|
-
* // ES: Renderizar con contenedores
|
|
9
|
+
* // Render with containers
|
|
12
10
|
* <ContainerList containers={containers} />
|
|
13
11
|
*/
|
|
14
12
|
import React from "react";
|
|
@@ -18,7 +18,7 @@ export default function ContainerRow({ container }) {
|
|
|
18
18
|
netIO: { rx: 0, tx: 0 },
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
//
|
|
21
|
+
// Format ports for display
|
|
22
22
|
const formatPorts = (ports) => {
|
|
23
23
|
if (!ports || ports.length === 0) return "";
|
|
24
24
|
if (Array.isArray(ports)) {
|
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic helper to perform a container action with user feedback.
|
|
3
|
+
*
|
|
4
|
+
* @param {Object} params
|
|
5
|
+
* @param {Array} params.containers - Array of container objects
|
|
6
|
+
* @param {number} params.selected - Index of the selected container
|
|
7
|
+
* @param {Function} params.actionFn - Async function that performs the action (receives container id)
|
|
8
|
+
* @param {string} params.actionLabel - Label used in feedback messages (e.g. 'Starting')
|
|
9
|
+
* @param {Function} params.setMessage - Setter for feedback message
|
|
10
|
+
* @param {Function} params.setMessageColor - Setter for feedback color
|
|
11
|
+
* @param {Function} [params.stateCheck] - Optional function that validates container state before action
|
|
12
|
+
* @returns {Promise<void>}
|
|
13
|
+
*/
|
|
1
14
|
export async function handleAction({
|
|
2
15
|
containers,
|
|
3
16
|
selected,
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remove (delete) a container by id. Force removal so running containers are stopped first.
|
|
3
|
+
*
|
|
4
|
+
* @param {string} containerId - Docker container id
|
|
5
|
+
* @returns {Promise<void>} Resolves when removal completes
|
|
6
|
+
* @throws {Error} If Docker reports an error
|
|
7
|
+
*/
|
|
1
8
|
export async function removeContainer(containerId) {
|
|
2
9
|
const container = docker.getContainer(containerId);
|
|
3
10
|
try {
|
|
@@ -9,6 +16,14 @@ export async function removeContainer(containerId) {
|
|
|
9
16
|
import { docker } from "../dockerService";
|
|
10
17
|
import { imageExists, pullImage } from "./imageUtils.js";
|
|
11
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Create a new container from an image. If the image is missing locally, it will be pulled.
|
|
21
|
+
*
|
|
22
|
+
* @param {string} imageName - Image name (e.g. 'nginx:alpine')
|
|
23
|
+
* @param {Object} [options] - Docker create options (Env, ExposedPorts, HostConfig, name, etc.)
|
|
24
|
+
* @returns {Promise<string>} The created container id
|
|
25
|
+
* @throws {Error} If image listing/pull or creation fails
|
|
26
|
+
*/
|
|
12
27
|
export async function createContainer(imageName, options = {}) {
|
|
13
28
|
let exists;
|
|
14
29
|
try {
|
|
@@ -36,16 +51,31 @@ export async function createContainer(imageName, options = {}) {
|
|
|
36
51
|
}
|
|
37
52
|
}
|
|
38
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Start a container by id.
|
|
56
|
+
* @param {string} containerId - Docker container id
|
|
57
|
+
* @returns {Promise<void>}
|
|
58
|
+
*/
|
|
39
59
|
export async function startContainer(containerId) {
|
|
40
60
|
const container = docker.getContainer(containerId);
|
|
41
61
|
await container.start();
|
|
42
62
|
}
|
|
43
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Stop a container by id.
|
|
66
|
+
* @param {string} containerId - Docker container id
|
|
67
|
+
* @returns {Promise<void>}
|
|
68
|
+
*/
|
|
44
69
|
export async function stopContainer(containerId) {
|
|
45
70
|
const container = docker.getContainer(containerId);
|
|
46
71
|
await container.stop();
|
|
47
72
|
}
|
|
48
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Restart a container by id.
|
|
76
|
+
* @param {string} containerId - Docker container id
|
|
77
|
+
* @returns {Promise<void>}
|
|
78
|
+
*/
|
|
49
79
|
export async function restartContainer(containerId) {
|
|
50
80
|
const container = docker.getContainer(containerId);
|
|
51
81
|
await container.restart();
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { docker } from "../dockerService";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Return a list of containers with normalized fields for the UI.
|
|
5
|
+
* @returns {Promise<Array<Object>>}
|
|
6
|
+
*/
|
|
3
7
|
export async function getContainers() {
|
|
4
8
|
const containers = await docker.listContainers({ all: true });
|
|
5
9
|
return containers.map((container) => ({
|
|
@@ -16,7 +20,7 @@ export async function getContainers() {
|
|
|
16
20
|
if (publicPorts.length > 0) {
|
|
17
21
|
return [...new Set(publicPorts)];
|
|
18
22
|
}
|
|
19
|
-
|
|
23
|
+
// If there are no public ports, show private exposed ports
|
|
20
24
|
const privatePorts = container.Ports.filter((port) => port.PrivatePort).map(
|
|
21
25
|
(port) => `:${port.PrivatePort}`
|
|
22
26
|
);
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { docker } from "../dockerService";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Return a stream of logs from a container and call callbacks for events.
|
|
5
|
+
*
|
|
6
|
+
* @param {string} containerId - Docker container id
|
|
7
|
+
* @param {Function} onData - Called with chunk string when data arrives
|
|
8
|
+
* @param {Function} onEnd - Called when stream ends
|
|
9
|
+
* @param {Function} onError - Called on error
|
|
10
|
+
*/
|
|
3
11
|
export function getLogsStream(containerId, onData, onEnd, onError) {
|
|
4
12
|
const container = docker.getContainer(containerId);
|
|
5
13
|
container.logs({
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { docker } from "../dockerService";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Retrieve a snapshot of container resource usage (CPU, memory, network).
|
|
5
|
+
*
|
|
6
|
+
* @param {string} containerId - Docker container id
|
|
7
|
+
* @returns {Promise<Object>} Object with cpuPercent, memPercent and netIO {rx,tx}
|
|
8
|
+
*/
|
|
3
9
|
export async function getStats(containerId) {
|
|
4
10
|
const container = docker.getContainer(containerId);
|
|
5
11
|
const stream = await container.stats({ stream: false });
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { docker } from "../dockerService";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Check whether an image exists locally.
|
|
5
|
+
* @param {string} imageName - Image name or tag
|
|
6
|
+
* @returns {Promise<boolean>}
|
|
7
|
+
*/
|
|
3
8
|
export async function imageExists(imageName) {
|
|
4
9
|
const images = await docker.listImages();
|
|
5
10
|
return images.some(img =>
|
|
@@ -8,6 +13,11 @@ export async function imageExists(imageName) {
|
|
|
8
13
|
);
|
|
9
14
|
}
|
|
10
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Pull an image from the registry.
|
|
18
|
+
* @param {string} imageName - Image name to pull
|
|
19
|
+
* @returns {Promise<void>}
|
|
20
|
+
*/
|
|
11
21
|
export async function pullImage(imageName) {
|
|
12
22
|
await new Promise((resolve, reject) => {
|
|
13
23
|
docker.pull(imageName, (err, stream) => {
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import { spawn } from "child_process";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Show an exit message using provided setters, clear the terminal and exit after a delay.
|
|
5
|
+
*
|
|
6
|
+
* @param {Object} params
|
|
7
|
+
* @param {Function} params.setMessage - Setter for message text
|
|
8
|
+
* @param {Function} params.setMessageColor - Setter for message color
|
|
9
|
+
* @param {string} [params.message] - Message to display
|
|
10
|
+
* @param {string} [params.color] - Color for the message
|
|
11
|
+
* @param {number} [params.delay] - Delay in milliseconds before exiting
|
|
12
|
+
*/
|
|
3
13
|
export function exitWithMessage({ setMessage, setMessageColor, message = "Exiting...", color = "yellow", delay = 1500 }) {
|
|
4
14
|
setMessage(message);
|
|
5
15
|
setMessageColor(color);
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* React hook to manage Docker containers state.
|
|
3
|
-
* Hook de React para gestionar el estado de contenedores Docker.
|
|
4
3
|
*
|
|
5
4
|
* @returns {[Array, Function]} [containers, refresh] / [contenedores, refrescar]
|
|
6
5
|
* @example
|
|
7
|
-
* //
|
|
8
|
-
* // ES: Usar en un componente
|
|
6
|
+
* // Use in a component
|
|
9
7
|
* const [containers, refresh] = useContainers();
|
|
10
8
|
*/
|
|
11
9
|
import React, { useState, useEffect } from "react";
|
package/src/hooks/useControls.js
CHANGED
|
@@ -7,6 +7,29 @@ import { getLogsStream } from "../helpers/dockerService/serviceComponents/contai
|
|
|
7
7
|
import { createContainer as svcCreateContainer } from "../helpers/dockerService/serviceComponents/containerActions.js";
|
|
8
8
|
|
|
9
9
|
// Principal hook to manage user inputs and control the app state
|
|
10
|
+
/**
|
|
11
|
+
* Main hook that wires user input, creation, actions and logs viewing.
|
|
12
|
+
* It coordinates the modular hooks and exposes a compact API consumed by the App.
|
|
13
|
+
*
|
|
14
|
+
* @param {Array<Object>} containers - Current list of Docker containers
|
|
15
|
+
* @returns {Object} controls - API for the App component
|
|
16
|
+
* @property {number} selected - Index of the currently selected container
|
|
17
|
+
* @property {function} setSelected - Setter for selected index
|
|
18
|
+
* @property {string} message - Current feedback message (creation or actions)
|
|
19
|
+
* @property {string} messageColor - Color to show for the feedback message
|
|
20
|
+
* @property {boolean} showLogs - Whether the logs viewer is active
|
|
21
|
+
* @property {Array<string>} logs - Array of log lines currently collected
|
|
22
|
+
* @property {function} exitLogs - Helper to close the logs viewer
|
|
23
|
+
* @property {boolean} creatingContainer - Whether the create-container prompt is open
|
|
24
|
+
* @property {number} creationStep - Current step in the creation flow
|
|
25
|
+
* @property {string} imageNameInput - Current value of the image name field
|
|
26
|
+
* @property {string} containerNameInput - Current value of the container name field
|
|
27
|
+
* @property {string} portInput - Current value of the port input field
|
|
28
|
+
* @property {string} envInput - Current value of the env input field
|
|
29
|
+
* @property {Object} creation - The creation hook API (setters and helpers)
|
|
30
|
+
* @property {Object} actions - The actions hook API (helpers to start/stop/remove)
|
|
31
|
+
* @property {Object} logsViewer - The logs viewer hook API
|
|
32
|
+
*/
|
|
10
33
|
export function useControls(containers = []) {
|
|
11
34
|
const [selected, setSelected] = React.useState(0);
|
|
12
35
|
const [creatingContainer, setCreatingContainer] = React.useState(false);
|
|
@@ -61,7 +84,7 @@ export function useControls(containers = []) {
|
|
|
61
84
|
const exitLogs = logsViewer.closeLogs;
|
|
62
85
|
|
|
63
86
|
useInput((input, key) => {
|
|
64
|
-
|
|
87
|
+
// Erase confirmation
|
|
65
88
|
if (confirmErase) {
|
|
66
89
|
if (input === "y" || input === "Y") {
|
|
67
90
|
actions.handleAction({
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import React, { useRef, useCallback } from "react";
|
|
2
2
|
import { getLogsStream } from "../helpers/dockerService/serviceComponents/containerLogs";
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Hook that manages opening and closing a logs stream for a container.
|
|
6
|
+
*
|
|
7
|
+
* @returns {Object} { openLogs, closeLogs }
|
|
8
|
+
*/
|
|
4
9
|
export function useLogsStream() {
|
|
5
10
|
const logsStreamRef = useRef(null);
|
|
6
11
|
|
package/src/index.js
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
2
|
/**
|
|
4
3
|
* Entry point for the CDD CLI application.
|
|
5
|
-
* Punto de entrada para la aplicación CLI de CDD.
|
|
6
4
|
*
|
|
7
5
|
* @module index
|
|
8
6
|
* @example
|
|
9
|
-
* //
|
|
10
|
-
* // ES: Ejecutar el CLI
|
|
7
|
+
* // Run the CLI
|
|
11
8
|
* node index.js
|
|
12
9
|
*/
|
|
13
10
|
|
|
14
|
-
|
|
15
11
|
import React from "react";
|
|
16
12
|
import { render } from "ink";
|
|
17
13
|
import App from './App';
|