@tertium/hlpr 0.4.0 → 0.5.1

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/README.md CHANGED
@@ -196,7 +196,7 @@ git clone https://github.com/tertiumnon/hlpr.git
196
196
  npm install
197
197
 
198
198
  # Build the project
199
- npm run build
199
+ bun run build
200
200
 
201
201
  # Link for local development
202
202
  npm link
@@ -0,0 +1,41 @@
1
+ #!/bin/bash
2
+ # @description Deploy application to remote server with environment variables
3
+
4
+ SKIP_BUILD="{{SKIP_BUILD}}"
5
+ DEPLOY_USER="{{DEPLOY_USER}}"
6
+ DEPLOY_HOST="{{DEPLOY_HOST}}"
7
+ DEPLOY_PATH="{{DEPLOY_PATH}}"
8
+ APP_NAME="{{APP_NAME}}"
9
+
10
+ echo "Deploying to $DEPLOY_HOST:$DEPLOY_PATH"
11
+ echo "=========================================="
12
+
13
+ # Build phase (unless skip-build is set)
14
+ if [ "$SKIP_BUILD" != "true" ]; then
15
+ echo "Building..."
16
+ bun run build
17
+ if [ $? -ne 0 ]; then
18
+ echo "✗ Build failed"
19
+ exit 1
20
+ fi
21
+ fi
22
+
23
+ # Deploy phase
24
+ echo ""
25
+ echo "Copying files to remote server..."
26
+ scp -r dist/ $DEPLOY_USER@$DEPLOY_HOST:$DEPLOY_PATH/
27
+ if [ $? -ne 0 ]; then
28
+ echo "✗ SCP failed"
29
+ exit 1
30
+ fi
31
+
32
+ echo ""
33
+ echo "Installing dependencies and restarting service..."
34
+ ssh $DEPLOY_USER@$DEPLOY_HOST "cd $DEPLOY_PATH && bun install --production && pm2 restart $APP_NAME --update-env"
35
+ if [ $? -ne 0 ]; then
36
+ echo "✗ Remote deployment failed"
37
+ exit 1
38
+ fi
39
+
40
+ echo ""
41
+ echo "✓ Deployment complete!"
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/commands/deploy/deploy.ts
4
+ import { execSync } from "child_process";
5
+ import { existsSync, readFileSync } from "fs";
6
+ import * as path from "path";
7
+ import { fileURLToPath } from "url";
8
+ var __filename2 = fileURLToPath(import.meta.url);
9
+ var __dirname2 = path.dirname(__filename2);
10
+ function loadEnv(projectDir) {
11
+ const envPath = path.join(projectDir, ".env");
12
+ if (!existsSync(envPath)) {
13
+ console.error("Error: .env file not found");
14
+ console.error(`Please copy .env.example to .env in ${projectDir}`);
15
+ process.exit(1);
16
+ }
17
+ const env = {};
18
+ const content = readFileSync(envPath, "utf-8");
19
+ content.split(`
20
+ `).forEach((line) => {
21
+ const trimmed = line.trim();
22
+ if (!trimmed || trimmed.startsWith("#"))
23
+ return;
24
+ const [key, ...valueParts] = trimmed.split("=");
25
+ if (key && valueParts.length > 0) {
26
+ env[key.trim()] = valueParts.join("=").trim();
27
+ }
28
+ });
29
+ return env;
30
+ }
31
+ function validate(env) {
32
+ const required = ["DEPLOY_USER", "DEPLOY_HOST", "DEPLOY_PATH", "APP_NAME"];
33
+ const missing = required.filter((key) => !env[key]);
34
+ if (missing.length > 0) {
35
+ console.error(`Error: Missing environment variables: ${missing.join(", ")}`);
36
+ process.exit(1);
37
+ }
38
+ }
39
+ function executeScript(scriptContent, variables, cwd) {
40
+ let script = scriptContent;
41
+ for (const [key, value] of Object.entries(variables)) {
42
+ script = script.replace(new RegExp(`{{${key}}}`, "g"), value);
43
+ }
44
+ const lines = script.split(`
45
+ `);
46
+ for (const line of lines) {
47
+ const trimmed = line.trim();
48
+ if (!trimmed || trimmed.startsWith("#") || trimmed.startsWith("#!/"))
49
+ continue;
50
+ if (/^[A-Z_][A-Z0-9_]*=/.test(trimmed))
51
+ continue;
52
+ try {
53
+ console.log(`→ ${trimmed}`);
54
+ execSync(trimmed, {
55
+ stdio: "inherit",
56
+ cwd,
57
+ shell: true
58
+ });
59
+ } catch (error) {
60
+ console.error(`
61
+ ✗ Command failed: ${trimmed}
62
+ `);
63
+ process.exit(1);
64
+ }
65
+ }
66
+ }
67
+ function deploy() {
68
+ const skipBuild = process.argv[2] === "skip-build";
69
+ const projectDir = process.cwd();
70
+ const env = loadEnv(projectDir);
71
+ validate(env);
72
+ const scriptPath = path.join(__dirname2, "deploy.sh");
73
+ if (!existsSync(scriptPath)) {
74
+ console.error(`Error: Deploy script not found at ${scriptPath}`);
75
+ process.exit(1);
76
+ }
77
+ const scriptContent = readFileSync(scriptPath, "utf-8");
78
+ const variables = {
79
+ ...env,
80
+ SKIP_BUILD: skipBuild ? "true" : "false"
81
+ };
82
+ console.log(`
83
+ Deploying to ${env.DEPLOY_HOST}:${env.DEPLOY_PATH}`);
84
+ console.log(`==========================================
85
+ `);
86
+ try {
87
+ executeScript(scriptContent, variables, projectDir);
88
+ } catch (error) {
89
+ console.error(`
90
+ ✗ Deployment failed: ${error.message}
91
+ `);
92
+ process.exit(1);
93
+ }
94
+ }
95
+ deploy();
@@ -0,0 +1,111 @@
1
+ // src/commands/deploy/deploy.service.ts
2
+ import { execSync } from "node:child_process";
3
+ import * as fs from "node:fs";
4
+
5
+ class DeployService {
6
+ config;
7
+ constructor(config) {
8
+ this.config = config;
9
+ }
10
+ log(message) {
11
+ console.log(`[${new Date().toISOString()}] ${message}`);
12
+ }
13
+ async copyToServer() {
14
+ this.log("Copying dist folder to remote server...");
15
+ const { remoteHost, remoteUser, deployPath, localDist, envFile } = this.config;
16
+ if (!fs.existsSync(localDist)) {
17
+ throw new Error(`Local dist folder not found: ${localDist}`);
18
+ }
19
+ const sshHost = `${remoteUser}@${remoteHost}`;
20
+ const tempPath = `${deployPath}_tmp`;
21
+ try {
22
+ this.log(`Creating temp directory on remote: ${tempPath}`);
23
+ execSync(`ssh ${sshHost} "mkdir -p ${tempPath} && rm -rf ${tempPath}/*"`, { stdio: "inherit" });
24
+ this.log(`Copying ${localDist} to ${sshHost}:${tempPath}/`);
25
+ execSync(`scp -r "${localDist}" ${sshHost}:${tempPath}/dist`, {
26
+ stdio: "inherit"
27
+ });
28
+ if (envFile && fs.existsSync(envFile)) {
29
+ this.log(`Copying ${envFile} to remote`);
30
+ execSync(`scp "${envFile}" ${sshHost}:${tempPath}/.env`, {
31
+ stdio: "inherit"
32
+ });
33
+ }
34
+ if (fs.existsSync("package.json")) {
35
+ this.log("Copying package.json to remote");
36
+ execSync(`scp package.json ${sshHost}:${tempPath}/`, {
37
+ stdio: "inherit"
38
+ });
39
+ }
40
+ this.log(`Moving files from temp to deploy path...`);
41
+ const moveCmd = `rm -rf ${deployPath}/dist && ` + `mv ${tempPath}/dist ${deployPath}/ && ` + `[ -f ${tempPath}/.env ] && mv ${tempPath}/.env ${deployPath}/.env || true && ` + `[ -f ${tempPath}/package.json ] && mv ${tempPath}/package.json ${deployPath}/ || true && ` + `rm -rf ${tempPath}`;
42
+ execSync(`ssh ${sshHost} "${moveCmd}"`, { stdio: "inherit" });
43
+ this.log("✓ Files copied successfully");
44
+ } catch (error) {
45
+ throw new Error(`Failed to copy files: ${error instanceof Error ? error.message : String(error)}`);
46
+ }
47
+ }
48
+ async installDependencies() {
49
+ if (this.config.skipInstall) {
50
+ this.log("Skipping dependency installation");
51
+ return;
52
+ }
53
+ this.log("Installing dependencies on server...");
54
+ const { remoteHost, remoteUser, deployPath } = this.config;
55
+ const sshHost = `${remoteUser}@${remoteHost}`;
56
+ try {
57
+ const cmd = `cd ${deployPath} && bun install --production`;
58
+ execSync(`ssh ${sshHost} "${cmd}"`, { stdio: "inherit" });
59
+ this.log("✓ Dependencies installed");
60
+ } catch (error) {
61
+ this.log("⚠ Dependency installation skipped or failed");
62
+ }
63
+ }
64
+ async restartProcess() {
65
+ if (this.config.skipRestart) {
66
+ this.log("Skipping process restart");
67
+ return;
68
+ }
69
+ this.log("Restarting application via PM2...");
70
+ const { remoteHost, remoteUser, deployPath, appName, port } = this.config;
71
+ const sshHost = `${remoteUser}@${remoteHost}`;
72
+ try {
73
+ const portOpt = port ? ` --env PORT=${port}` : "";
74
+ const cmd = `cd ${deployPath} && ` + `(pm2 restart ${appName} --update-env 2>/dev/null || ` + `pm2 start dist/index.js --name ${appName}${portOpt} 2>/dev/null) && ` + `pm2 save 2>/dev/null || true`;
75
+ execSync(`ssh ${sshHost} "bash -l -c '${cmd}'"`, { stdio: "inherit" });
76
+ this.log("✓ Process restart attempted");
77
+ } catch (error) {
78
+ this.log("⚠ PM2 restart skipped - may need manual setup");
79
+ }
80
+ }
81
+ async deploy() {
82
+ const startTime = new Date().toISOString();
83
+ try {
84
+ this.log("Starting deployment...");
85
+ await this.copyToServer();
86
+ await this.installDependencies();
87
+ await this.restartProcess();
88
+ this.log("✅ Deployment completed successfully");
89
+ return {
90
+ success: true,
91
+ message: "Deployment completed successfully",
92
+ timestamp: startTime
93
+ };
94
+ } catch (error) {
95
+ const message = error instanceof Error ? error.message : "Unknown error";
96
+ this.log(`❌ Deployment failed: ${message}`);
97
+ return {
98
+ success: false,
99
+ message,
100
+ timestamp: startTime
101
+ };
102
+ }
103
+ }
104
+ }
105
+ async function createDeployService(config) {
106
+ return new DeployService(config);
107
+ }
108
+ export {
109
+ createDeployService,
110
+ DeployService
111
+ };
@@ -0,0 +1,41 @@
1
+ #!/bin/bash
2
+ # @description Deploy application to remote server with environment variables
3
+
4
+ SKIP_BUILD="{{SKIP_BUILD}}"
5
+ DEPLOY_USER="{{DEPLOY_USER}}"
6
+ DEPLOY_HOST="{{DEPLOY_HOST}}"
7
+ DEPLOY_PATH="{{DEPLOY_PATH}}"
8
+ APP_NAME="{{APP_NAME}}"
9
+
10
+ echo "Deploying to $DEPLOY_HOST:$DEPLOY_PATH"
11
+ echo "=========================================="
12
+
13
+ # Build phase (unless skip-build is set)
14
+ if [ "$SKIP_BUILD" != "true" ]; then
15
+ echo "Building..."
16
+ bun run build
17
+ if [ $? -ne 0 ]; then
18
+ echo "✗ Build failed"
19
+ exit 1
20
+ fi
21
+ fi
22
+
23
+ # Deploy phase
24
+ echo ""
25
+ echo "Copying files to remote server..."
26
+ scp -r dist/ $DEPLOY_USER@$DEPLOY_HOST:$DEPLOY_PATH/
27
+ if [ $? -ne 0 ]; then
28
+ echo "✗ SCP failed"
29
+ exit 1
30
+ fi
31
+
32
+ echo ""
33
+ echo "Installing dependencies and restarting service..."
34
+ ssh $DEPLOY_USER@$DEPLOY_HOST "cd $DEPLOY_PATH && bun install --production && pm2 restart $APP_NAME --update-env"
35
+ if [ $? -ne 0 ]; then
36
+ echo "✗ Remote deployment failed"
37
+ exit 1
38
+ fi
39
+
40
+ echo ""
41
+ echo "✓ Deployment complete!"
File without changes
File without changes
package/bin/index.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tertium/hlpr",
3
- "version": "0.4.0",
3
+ "version": "0.5.1",
4
4
  "description": "Windows and *Nix utility for typical programming activity",
5
5
  "author": "Vitalii Balabanov",
6
6
  "email": "tertiumnon@gmail.com",
@@ -12,7 +12,7 @@
12
12
  "build": "bun run build:main && bun run build:commands",
13
13
  "test": "bun test",
14
14
  "test:e2e": "node scripts/test-rename-e2e.cjs",
15
- "prepublishOnly": "npm run build",
15
+ "prepublishOnly": "bun run build",
16
16
  "release:minor": "node node_modules/@tertium/js/scripts/release.js minor",
17
17
  "release:patch": "node node_modules/@tertium/js/scripts/release.js patch",
18
18
  "release:major": "node node_modules/@tertium/js/scripts/release.js major",