Skip to content

Commit 4309a39

Browse files
author
hlambda
authored
Release/0.0.10 (#4)
1 parent 5b566ee commit 4309a39

File tree

13 files changed

+345
-73
lines changed

13 files changed

+345
-73
lines changed

CHANGELOG.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
Release 0.0.10
1+
# Release 0.0.10
22

3-
- [WIP] Tests
4-
- [WIP] Git sync options
5-
- [WIP] Shell command execution
3+
- Tests
4+
- Shell command execution
65

7-
Release 0.0.9
6+
# Release 0.0.9
87

98
- Environments, and env management
109
- Override values from yaml from .env using {{}} pattern
@@ -14,7 +13,7 @@ Release 0.0.9
1413
- Check for new version and updates
1514
- Shell command execution on metadata apply as post apply script
1615

17-
Release 0.0.8
16+
# Release 0.0.8
1817

1918
- New initialization template
2019
- Init command flags, force and force-remove

README.md

Lines changed: 85 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,52 @@ hlambda-cli - CLI tool for managing Hlambda server.
44

55
[![NPM](https://nodei.co/npm/hlambda-cli.png?downloads=true&downloadRank=true&stars=true)](https://npmjs.org/hlambda-cli )
66

7-
## Installation
7+
## 🧰 Install Hlambda CLI
88

9-
### npm
109
```bash
1110
$ npm install -g hlambda-cli
1211
```
1312

14-
This will add Hlambda CLI to your arsenal, now you can use `hl`, `hla` or `hlambda` to check if CLI is working as expected.
13+
This will add Hlambda CLI to your arsenal, now you can use `hl`, `hla` or `hlambda`.
14+
15+
## 📚 Using Hlambda CLI
16+
17+
Check if the console is installed globally, in your terminal you can now run
1518

1619
````console
17-
$ hlambda
20+
$ hl
1821
````
1922

20-
## Example
23+
You can get the snippet for running Hlambda docker image directly from the CLI
24+
25+
````console
26+
$ hl snippets docker
27+
````
2128

22-
First you will need to get hlambda server running, either in docker or locally.
29+
Example output:
30+
31+
```
32+
docker run -d -p 8081:1331 --env HLAMBDA_ADMIN_SECRET=demo --name hlambda-server --restart=always -v hlambda_metadata:/usr/src/app/metadata hlambda/hlambda-core:latest
33+
```
34+
35+
You can even run it directly via additional flag --run
2336

2437
````console
25-
$ hlambda --version
38+
$ hl snip docker --run
2639
````
2740

41+
## 🧙🏻‍♂️ Quich start
42+
43+
Initialize new configuration in the new folder `test`
44+
2845
````console
29-
$ hlambda init my-first-hlambda-app
46+
$ hl i test
3047
````
3148

49+
change working directory to `test`
50+
3251
````console
33-
$ cd my-first-hlambda-app
52+
$ cd test
3453
````
3554

3655
Change the admin_secret in the config.yaml manually or just run
@@ -39,7 +58,8 @@ Change the admin_secret in the config.yaml manually or just run
3958
$ hlambda config save --admin-secret "demo"
4059
````
4160

42-
this will edit the config.yaml file and save admin secret value in that file (please take extra care when commiting config.yaml file to not leak secrets)
61+
this will edit the config.yaml file and save admin secret value in that file (**🧨 please take extra care when commiting `config.yaml` file to not leak secrets**
62+
**, check Environments section for more details but we suggest you to use `env replacer syntax` like `{{ENV_HLAMBDA_ADMIN_SECRET}}` and keeping your secrets in the environemnt variables**)
4363

4464
You can then export the existing metadata from the running server use
4565

@@ -86,3 +106,58 @@ If you want to clear all the metadata from the server
86106
````console
87107
$ hlambda metadata clear
88108
````
109+
110+
## 📦 Environments
111+
112+
If you have multiple deployments of the same app you can now add environments to your hlambda config using `hlambda-cli`
113+
114+
To add `dev` environment use
115+
116+
````console
117+
$ hl env add dev
118+
````
119+
120+
this will add new `dev` folder environment in `./environments/dev` with `config.yaml`
121+
122+
example content of the `./environments/dev/config.yaml`
123+
124+
```
125+
version: 1
126+
endpoint: "{{ENV_DEV_HLAMBDA_ENDPOINT}}"
127+
admin_secret: "{{ENV_DEV_HLAMBDA_ADMIN_SECRET}}"
128+
```
129+
130+
this will be used instead of the values in root `config.yaml` file.
131+
132+
🧨 Important! - You can hardcode but it is the best practice to use `env replacer syntax` `{{ENV_DEV_HLAMBDA_ADMIN_SECRET}}` the value will be the one provided in the `ENV_DEV_HLAMBDA_ADMIN_SECRET` environment variable at the CLI command run-time.
133+
134+
✨ Hlambda cli also supports .env file 😄
135+
so you can create `.env` file in the root
136+
```
137+
ENV_DEV_HLAMBDA_ENDPOINT="http://localhost:8081"
138+
ENV_DEV_HLAMBDA_ADMIN_SECRET="demo"
139+
```
140+
141+
Any hlambda CLI command can now be excuted for different environment, example
142+
143+
````console
144+
$ hl server logs --env dev
145+
````
146+
147+
````console
148+
$ hl metadata apply --env dev
149+
````
150+
151+
to add `custom_name` environemnt use
152+
153+
````console
154+
$ hl env add custom_name
155+
````
156+
157+
to delete environment named "staging"
158+
159+
````console
160+
$ hl env delete staging
161+
````
162+
163+
this will remove the whole environment folder.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "hlambda-cli",
33
"type": "module",
4-
"version": "0.0.9",
4+
"version": "0.0.10",
55
"description": "CLI for hlambda server.",
66
"main": "src/index.js",
77
"bin": {

src/commands/metadata.js

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { errors } from './../errors/index.js';
1111

1212
import CLIErrorHandler from './../utils/CLIErrorHandler.js';
1313
import { loadConfigFromYAML } from './../utils/loadConfigFromYAML.js';
14+
import executeShellCommandClass from './../utils/executeShellCommandClass.js';
1415

1516
export const serverReload = async (options, program) => {
1617
await (async () => {
@@ -159,25 +160,9 @@ export const metadataApply = async (options, program) => {
159160
}
160161
console.log(response.status);
161162

162-
// Check if there are scripts to run after applying
163-
const executeShellCommand = async (command) => {
164-
const headers = {
165-
'x-hlambda-admin-secret': adminSecret,
166-
};
167-
const response = await fetch(`${endpoint}/console/api/v1/command-request`, {
168-
method: 'POST',
169-
body: {
170-
command,
171-
},
172-
headers,
173-
});
174-
175-
if (response.status === 200) {
176-
console.log(`Shell command`.green, `${command}`.red, `executed!`.green);
177-
}
178-
console.log(response.status);
179-
};
163+
const executeShellCommand = executeShellCommandClass(adminSecret, endpoint);
180164

165+
// Check if there are scripts to run after applying
181166
if (metadataPostApplyCommandList.length > 0) {
182167
for (let i = 0; i < metadataPostApplyCommandList.length; i += 1) {
183168
// eslint-disable-next-line no-await-in-loop

src/commands/server.js

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
import path from 'path';
22
import fetch from 'node-fetch';
3-
// import FormData from 'form-data';
3+
import * as readline from 'node:readline/promises';
4+
import { stdin as input, stdout as output } from 'node:process';
5+
46
import { FormData, File } from 'formdata-node';
57

68
import { errors } from './../errors/index.js';
79

810
import CLIErrorHandler from './../utils/CLIErrorHandler.js';
911
import { loadConfigFromYAML } from './../utils/loadConfigFromYAML.js';
12+
import executeShellCommandClass from './../utils/executeShellCommandClass.js';
1013

1114
export const serverGetLogs = async (options, program) => {
1215
await (async () => {
@@ -126,8 +129,68 @@ export const serverShell = async (options, program) => {
126129
const endpoint = configuration?.endpoint ?? 'http://localhost:8081';
127130
const adminSecret = options?.adminSecret ?? configuration?.admin_secret ?? '';
128131

129-
// TODO: Implement this
130-
throw new Error(errors.FUNCTIONALITY_NOT_IMPLEMENTED);
132+
const headers = {
133+
'x-hlambda-admin-secret': adminSecret,
134+
};
135+
const response = await fetch(`${endpoint}/console/api/v1/command-cwd`, {
136+
method: 'GET',
137+
headers,
138+
});
139+
140+
if (response.status === 200) {
141+
console.log('Connection valid!'.green);
142+
} else {
143+
throw new Error(errors.ERROR_INVALID_HLAMBDA_ADMIN_SECRET);
144+
}
145+
console.log(response.status);
146+
const cwdCommandResult = await response.json();
147+
148+
const executeShellCommand = executeShellCommandClass(adminSecret, endpoint, true);
149+
150+
let workingDirectory = cwdCommandResult?.cwd ?? './';
151+
152+
const writePwdConsole = () => {
153+
process.stdout.write(`<${'hlambda-server'}@${endpoint}> ${workingDirectory} # `.yellow);
154+
};
155+
writePwdConsole();
156+
157+
// Register linebyline listener
158+
const rl = readline.createInterface({ input, output });
159+
160+
// const answer = await rl.question('What do you think of Node.js? ');
161+
// console.log(`Thank you for your valuable feedback: ${answer}`);
162+
163+
rl.on('line', async (terminalInput) => {
164+
if (terminalInput === 'exit' || terminalInput === 'quit') {
165+
rl.close();
166+
return;
167+
}
168+
if (terminalInput.toLowerCase().startsWith('cd')) {
169+
// Change working dir for the command...
170+
const t = terminalInput.match(/cd\s(.+)/);
171+
const responseCd = await fetch(`${endpoint}/console/api/v1/command-change-dir`, {
172+
method: 'POST',
173+
headers: {
174+
'x-hlambda-admin-secret': adminSecret,
175+
Accept: 'application/json',
176+
'Content-Type': 'application/json', // Important
177+
},
178+
body: JSON.stringify({
179+
path: t[1],
180+
}),
181+
});
182+
const responseJson = await responseCd.json();
183+
const outputString = responseJson;
184+
// console.log(outputString);
185+
workingDirectory = outputString?.cwd;
186+
writePwdConsole();
187+
return;
188+
}
189+
const result = await executeShellCommand(terminalInput, workingDirectory);
190+
const data = await result.json();
191+
process.stdout.write(data?.data);
192+
writePwdConsole();
193+
});
131194
})()
132195
.then(() => {})
133196
.catch(CLIErrorHandler(program));

src/commands/snippet/docker-compose.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import path from 'path';
2+
import { exec } from 'child_process';
23

34
import CLIErrorHandler from './../../utils/CLIErrorHandler.js';
45

@@ -9,7 +10,26 @@ export const dockerComposeSnippet = async (options, program) => {
910
const cwd = path.resolve(process.cwd());
1011
console.log('Executing in cwd:'.green, `${cwd}`.yellow);
1112

12-
console.log(dockerComposeInstallSnippet.yellow);
13+
if (options.run) {
14+
const command = dockerComposeInstallSnippet(true);
15+
const childPid = exec(command);
16+
17+
childPid.stdout.on('data', (data) => {
18+
console.log(`${data.toString()}`);
19+
});
20+
21+
childPid.stderr.on('data', (data) => {
22+
console.log(`${data.toString()}`);
23+
});
24+
25+
childPid.on('exit', (code) => {
26+
console.log(`Process exited with code ${code.toString()}`);
27+
});
28+
} else if (options.clean) {
29+
console.log(dockerComposeInstallSnippet(true));
30+
} else {
31+
console.log(dockerComposeInstallSnippet().yellow);
32+
}
1333
})()
1434
.then(() => {})
1535
.catch(CLIErrorHandler(program));

src/commands/snippet/docker.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import path from 'path';
2+
import { exec } from 'child_process';
23

34
import CLIErrorHandler from './../../utils/CLIErrorHandler.js';
45

@@ -9,7 +10,26 @@ export const dockerSnippet = async (options, program) => {
910
const cwd = path.resolve(process.cwd());
1011
console.log('Executing in cwd:'.green, `${cwd}`.yellow);
1112

12-
console.log(dockerInstallSnippet.yellow);
13+
if (options.run) {
14+
const command = dockerInstallSnippet(true);
15+
const childPid = exec(command);
16+
17+
childPid.stdout.on('data', (data) => {
18+
console.log(`${data.toString()}`);
19+
});
20+
21+
childPid.stderr.on('data', (data) => {
22+
console.log(`${data.toString()}`);
23+
});
24+
25+
childPid.on('exit', (code) => {
26+
console.log(`Process exited with code ${code.toString()}`);
27+
});
28+
} else if (options.clean) {
29+
console.log(dockerInstallSnippet(true));
30+
} else {
31+
console.log(dockerInstallSnippet().yellow);
32+
}
1333
})()
1434
.then(() => {})
1535
.catch(CLIErrorHandler(program));

0 commit comments

Comments
 (0)