auto-deploy-sh 1.0.1 → 2.0.0
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/LICENSE +4 -11
- package/README.md +121 -63
- package/dist/bin/config.js +43 -6
- package/dist/bin/deploy.d.ts +2 -0
- package/dist/bin/deploy.js +70 -29
- package/dist/bin/index.d.ts +1 -1
- package/dist/bin/index.js +8 -10
- package/dist/bin/type/types.d.ts +5 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +27 -0
- package/package.json +82 -83
package/LICENSE
CHANGED
|
@@ -1,15 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
MIT License
|
|
2
2
|
|
|
3
3
|
Copyright (c) 2025 yotomum_ml
|
|
4
4
|
|
|
5
|
-
Permission to use, copy, modify, and/or
|
|
6
|
-
|
|
7
|
-
copyright notice and this permission notice appear in all copies.
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copyof this software and associated documentation files (the "Software"), to dealin the Software without restriction, including without limitation the rightsto use, copy, modify, merge, publish, distribute, sublicense, and/or sellcopies of the Software, and to permit persons to whom the Software isfurnished to do so, subject to the following conditions:
|
|
6
|
+
The above copyright notice and this permission notice shall be included in allcopies or substantial portions of the Software.
|
|
8
7
|
|
|
9
|
-
THE SOFTWARE IS PROVIDED "AS IS" AND THE
|
|
10
|
-
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
11
|
-
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
12
|
-
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
13
|
-
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
14
|
-
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
15
|
-
PERFORMANCE OF THIS SOFTWARE.
|
|
8
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ORIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THEAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHERLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,63 +1,121 @@
|
|
|
1
|
-
# Auto-deploy-sh
|
|
2
|
-
|
|
3
|
-
English|[简体中文](README_zh_CN.md)
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
1
|
+
# Auto-deploy-sh
|
|
2
|
+
|
|
3
|
+
English|[简体中文](README_zh_CN.md)
|
|
4
|
+
|
|
5
|
+
This project aims to lower deployment barriers by providing an ultra-simple configuration and minimal dependency automated Docker deployment workflow. It helps developers quickly deploy applications to cloud servers without complex environment setups.
|
|
6
|
+
|
|
7
|
+
## Deployment Commands
|
|
8
|
+
|
|
9
|
+
### Project-Specific Configuration
|
|
10
|
+
|
|
11
|
+
**Install:**
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install auto-deploy-sh -D
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
**Run:**
|
|
18
|
+
|
|
19
|
+
- Add to `package.json`:
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
"scripts": {
|
|
23
|
+
"deploy": "auto-deploy-sh"
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
2. Execute in terminal:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm run deploy
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Global Configuration
|
|
34
|
+
|
|
35
|
+
**Install:**
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm install auto-deploy-sh -g
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Run** (in the root directory of the project to deploy):
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
auto-deploy-sh
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Advanced Usage
|
|
48
|
+
|
|
49
|
+
Run with a **custom configuration file**:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
auto-deploy <config-path>
|
|
53
|
+
# OR
|
|
54
|
+
auto-deploy -f <config-path>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Useful for multi-environment deployment (e.g., development, staging, production).
|
|
58
|
+
|
|
59
|
+
## Configuration File Reference
|
|
60
|
+
|
|
61
|
+
The configuration file is **fixed as `deploy-config.json`**. If missing, the tool will **guide you to create it** (stored in the command execution directory by default) and automatically add `deploy-config.json` to `.gitignore` to **prevent accidental commits of sensitive data**.
|
|
62
|
+
|
|
63
|
+
> ⚠️ **Critical Note**: The configuration file contains sensitive information (e.g., passwords). If creating manually, ensure `deploy-config.json` is added to `.gitignore`.
|
|
64
|
+
|
|
65
|
+
### Configuration Properties
|
|
66
|
+
|
|
67
|
+
- `host`: Remote server IP address or domain name.
|
|
68
|
+
- `port`: SSH port number.
|
|
69
|
+
- `user`: SSH username for the remote server.
|
|
70
|
+
- `password`: Password for the SSH user.
|
|
71
|
+
- `beforLaunch`: **Pre-deployment commands** (array of strings) to execute locally before starting the deployment (e.g., `["npm run build"]`).
|
|
72
|
+
- `Dockerfile`: **Optional**. If omitted: 1. Check `dockerBuildFiles` for a file named `Dockerfile`; 2. If not found, search for `Dockerfile` in the **first-level directory of the current execution environment**.
|
|
73
|
+
- `dockerBuildFiles`: Files/directories to include in the Docker build context (required for Dockerfile execution).
|
|
74
|
+
- `imageTag`: Docker image tag, formatted as `[registry-url/][username/project-name]:[tag]` (e.g., `my-registry.com/user/my-app:v1.0`).
|
|
75
|
+
- `containerName`: Unique name for the running container (ensures no conflicts with existing containers).
|
|
76
|
+
- `BindPorts`: Port mapping, formatted as `<host-port>:<container-port>` (e.g., `"8080:80"`).
|
|
77
|
+
- `Options`: **Optional** advanced settings (all sub-properties are optional)
|
|
78
|
+
- `volumes`: Volume mappings (array of strings), formatted as `[host-path/volume-name]:[container-path]:[optional-flags]` (e.g., `["/host/data:/container/data:ro"]`).
|
|
79
|
+
- `networks`: Connect the container to a custom Docker network (created via `docker network create <network-name>`) for inter-container communication.
|
|
80
|
+
|
|
81
|
+
### Format Introduction
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"host": "string",
|
|
86
|
+
"port": "number | string",
|
|
87
|
+
"user": "string",
|
|
88
|
+
"password": "string",
|
|
89
|
+
"beforLaunch": "string[]",
|
|
90
|
+
"Dockerfile": "string",
|
|
91
|
+
"dockerBuildFiles": "string[]",
|
|
92
|
+
"imageTag": "string",
|
|
93
|
+
"containerName": "string",
|
|
94
|
+
"BindPorts": "string",
|
|
95
|
+
"Options": {
|
|
96
|
+
"volumes": "string[]",
|
|
97
|
+
"networks": "string"
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Full Configuration Example
|
|
103
|
+
|
|
104
|
+
```json
|
|
105
|
+
{
|
|
106
|
+
"host": "your-server-ip",
|
|
107
|
+
"port": 22,
|
|
108
|
+
"user": "ssh-username",
|
|
109
|
+
"password": "ssh-password",
|
|
110
|
+
"beforLaunch": ["npm run build"],
|
|
111
|
+
"Dockerfile": "./Dockerfile",
|
|
112
|
+
"dockerBuildFiles": ["./dist", "./package.json"],
|
|
113
|
+
"imageTag": "my-app:latest",
|
|
114
|
+
"containerName": "my-app-container",
|
|
115
|
+
"BindPorts": "80:80",
|
|
116
|
+
"Options": {
|
|
117
|
+
"volumes": ["/host/logs:/app/logs:rw"],
|
|
118
|
+
"networks": "my-custom-network"
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
package/dist/bin/config.js
CHANGED
|
@@ -3,28 +3,32 @@ import path from 'path';
|
|
|
3
3
|
const configMethod = {
|
|
4
4
|
host: {
|
|
5
5
|
type: 'input',
|
|
6
|
-
message: '
|
|
6
|
+
message: 'Remote server IP or domain name: ',
|
|
7
7
|
},
|
|
8
8
|
port: {
|
|
9
9
|
type: 'number',
|
|
10
|
-
message: 'SSH
|
|
10
|
+
message: 'SSH port: ',
|
|
11
11
|
},
|
|
12
12
|
user: {
|
|
13
13
|
type: 'input',
|
|
14
|
-
message: '
|
|
14
|
+
message: 'username: ',
|
|
15
15
|
},
|
|
16
16
|
password: {
|
|
17
17
|
type: 'input',
|
|
18
|
-
message: '
|
|
18
|
+
message: 'password: ',
|
|
19
19
|
},
|
|
20
20
|
beforLaunch: {
|
|
21
21
|
type: 'input',
|
|
22
|
-
message: '
|
|
22
|
+
message: 'Before launch (multiple commands separated by , ): ',
|
|
23
23
|
handleFn: (value) => value.split(','),
|
|
24
24
|
},
|
|
25
|
+
Dockerfile: {
|
|
26
|
+
type: 'input',
|
|
27
|
+
message: 'Select the Dockerfile you need to execute.',
|
|
28
|
+
},
|
|
25
29
|
dockerBuildFiles: {
|
|
26
30
|
type: 'input',
|
|
27
|
-
message: '
|
|
31
|
+
message: 'Path to the file relative to the root directory required for Docker build (separated by , ): ',
|
|
28
32
|
handleFn: (value) => value.split(','),
|
|
29
33
|
},
|
|
30
34
|
imageTag: {
|
|
@@ -40,6 +44,17 @@ const configMethod = {
|
|
|
40
44
|
message: 'Bind Ports(such as 8080:8080): ',
|
|
41
45
|
},
|
|
42
46
|
};
|
|
47
|
+
const optionsMethod = {
|
|
48
|
+
volumes: {
|
|
49
|
+
type: 'input',
|
|
50
|
+
message: 'Multiple volumes are divided into by , : ',
|
|
51
|
+
handleFn: (value) => value.split(','),
|
|
52
|
+
},
|
|
53
|
+
networks: {
|
|
54
|
+
type: 'input',
|
|
55
|
+
message: 'Bound network: ',
|
|
56
|
+
},
|
|
57
|
+
};
|
|
43
58
|
export async function createConfig(rootPath) {
|
|
44
59
|
const config = {};
|
|
45
60
|
const keys = Object.keys(configMethod);
|
|
@@ -56,6 +71,28 @@ export async function createConfig(rootPath) {
|
|
|
56
71
|
const value = (await inquirer.invoke(configMethod[key]));
|
|
57
72
|
config[key] = fn(value);
|
|
58
73
|
}
|
|
74
|
+
const options = await inquirer.invoke({
|
|
75
|
+
type: 'checkbox',
|
|
76
|
+
message: 'Select other options as needed.',
|
|
77
|
+
choices: [
|
|
78
|
+
{ name: 'Volumes', value: 'volumes' },
|
|
79
|
+
{ name: 'Networks', value: 'networks' },
|
|
80
|
+
],
|
|
81
|
+
});
|
|
82
|
+
config['Options'] = {};
|
|
83
|
+
for (let i = 0; i < options.length; ++i) {
|
|
84
|
+
const key = options[i];
|
|
85
|
+
const fn = Object.hasOwn(optionsMethod[key], 'handleFn')
|
|
86
|
+
? optionsMethod[key].handleFn
|
|
87
|
+
: (value) => {
|
|
88
|
+
if (typeof value === 'string')
|
|
89
|
+
return value.trim();
|
|
90
|
+
else
|
|
91
|
+
return value;
|
|
92
|
+
};
|
|
93
|
+
const value = (await inquirer.invoke(optionsMethod[key]));
|
|
94
|
+
config['Options'][key] = fn(value);
|
|
95
|
+
}
|
|
59
96
|
await fs.writeFileSync(path.resolve(rootPath, 'deploy-config.json'), JSON.stringify(config, null, 2));
|
|
60
97
|
const gitIgnorePath = path.resolve(rootPath, '.gitignore');
|
|
61
98
|
let contain = '';
|
package/dist/bin/deploy.d.ts
CHANGED
|
@@ -27,5 +27,7 @@ export declare class Deploy {
|
|
|
27
27
|
errMsg?: string;
|
|
28
28
|
}, command: string): Promise<void>;
|
|
29
29
|
dockcerImageBuild(ssh: NodeSSH): Promise<void>;
|
|
30
|
+
buildDocker(ssh: NodeSSH, IMAGE_TAG: string, REMOTEAPPPATH: string, TARGET_DIR: string, CONTAINER_NAME: string): Promise<void>;
|
|
31
|
+
runDocker(ssh: NodeSSH, CONTAINER_NAME: string): Promise<void>;
|
|
30
32
|
clear(ssh: NodeSSH): Promise<void>;
|
|
31
33
|
}
|
package/dist/bin/deploy.js
CHANGED
|
@@ -59,6 +59,10 @@ export class Deploy {
|
|
|
59
59
|
const files = [];
|
|
60
60
|
if (this.config.dockerBuildFiles && this.config.dockerBuildFiles.length > 0) {
|
|
61
61
|
let dockerfileFlag = false, dockerignoreFlag = false;
|
|
62
|
+
if (this.config.Dockerfile && this.config.Dockerfile.length > 0) {
|
|
63
|
+
dockerfileFlag = true;
|
|
64
|
+
this.config.dockerBuildFiles.push(this.config.Dockerfile);
|
|
65
|
+
}
|
|
62
66
|
for (let i = 0; i < this.config.dockerBuildFiles.length; ++i) {
|
|
63
67
|
const file = this.config.dockerBuildFiles[i];
|
|
64
68
|
if (/\bDockerfile\b/.test(file)) {
|
|
@@ -76,6 +80,7 @@ export class Deploy {
|
|
|
76
80
|
if (!dockerignoreFlag && fs._.existsSync(path.resolve(this.context, '.dockerignore'))) {
|
|
77
81
|
this.config.dockerBuildFiles.push('.dockerignore');
|
|
78
82
|
}
|
|
83
|
+
let isEmptyFile = false;
|
|
79
84
|
this.config.dockerBuildFiles.forEach(async (file) => {
|
|
80
85
|
const fullPath = path.resolve(this.context, file);
|
|
81
86
|
if (fs._.existsSync(fullPath)) {
|
|
@@ -83,9 +88,11 @@ export class Deploy {
|
|
|
83
88
|
}
|
|
84
89
|
else {
|
|
85
90
|
log.error(`The file name is ${file}, and the file does not exist`);
|
|
86
|
-
|
|
91
|
+
isEmptyFile = true;
|
|
87
92
|
}
|
|
88
93
|
});
|
|
94
|
+
if (isEmptyFile)
|
|
95
|
+
throw new Error();
|
|
89
96
|
}
|
|
90
97
|
else {
|
|
91
98
|
log.error(`The file to build the image cannot be empty. Please check whether dockerBuildFiles is set correctly`);
|
|
@@ -112,6 +119,10 @@ export class Deploy {
|
|
|
112
119
|
archive.directory(file, fileName);
|
|
113
120
|
}
|
|
114
121
|
else {
|
|
122
|
+
if (this.config.Dockerfile && fileName === path.basename(this.config.Dockerfile)) {
|
|
123
|
+
archive.file(file, { name: 'Dockerfile' });
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
115
126
|
archive.file(file, { name: fileName });
|
|
116
127
|
}
|
|
117
128
|
}
|
|
@@ -124,11 +135,11 @@ export class Deploy {
|
|
|
124
135
|
if (await fs.exist(uploadPath)) {
|
|
125
136
|
const state = await fs.getFileStat(uploadPath);
|
|
126
137
|
const localSize = state.size;
|
|
127
|
-
await ora.start('📤
|
|
138
|
+
await ora.start('📤 Start uploading...', async () => {
|
|
128
139
|
await ssh.putFile(uploadPath, this.remotePath);
|
|
129
140
|
}, status => {
|
|
130
141
|
if (status)
|
|
131
|
-
return
|
|
142
|
+
return `File upload complete.`;
|
|
132
143
|
else {
|
|
133
144
|
exit(1);
|
|
134
145
|
return chalk.error(`exit code: 1`);
|
|
@@ -136,17 +147,17 @@ export class Deploy {
|
|
|
136
147
|
});
|
|
137
148
|
const exists = await ssh.execCommand(`test -f "${this.remotePath}" && echo "yes" || echo "no"`);
|
|
138
149
|
if (exists.stdout.trim() !== 'yes') {
|
|
139
|
-
log.error('
|
|
150
|
+
log.error('File upload failed.');
|
|
140
151
|
throw new Error();
|
|
141
152
|
}
|
|
142
153
|
const sizeResult = await ssh.execCommand(`stat -c %s "${this.remotePath}"`);
|
|
143
154
|
const remoteSize = parseInt(sizeResult.stdout.trim(), 10);
|
|
144
155
|
if (isNaN(remoteSize)) {
|
|
145
|
-
log.error('
|
|
156
|
+
log.error('Unable to obtain remote file size');
|
|
146
157
|
throw new Error();
|
|
147
158
|
}
|
|
148
159
|
if (remoteSize !== localSize && remoteSize < localSize - 10) {
|
|
149
|
-
log.error(
|
|
160
|
+
log.error(`File size mismatch: local=${localSize}, remote=${remoteSize}`);
|
|
150
161
|
throw new Error();
|
|
151
162
|
}
|
|
152
163
|
}
|
|
@@ -186,43 +197,73 @@ export class Deploy {
|
|
|
186
197
|
mkdir -p "${TARGET_DIR}"
|
|
187
198
|
|
|
188
199
|
if [ ! -f "${REMOTE_PATH}" ]; then
|
|
189
|
-
echo "❌
|
|
200
|
+
echo "❌ Error: Compressed file does not exist.: ${REMOTE_PATH}";
|
|
190
201
|
exit 1
|
|
191
202
|
fi
|
|
192
203
|
tar -xzf "${REMOTE_PATH}" -C "${TARGET_DIR}";
|
|
193
204
|
`);
|
|
194
|
-
await this.
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
205
|
+
await this.buildDocker(ssh, IMAGE_TAG, REMOTEAPPPATH, TARGET_DIR, CONTAINER_NAME);
|
|
206
|
+
await this.runDocker(ssh, CONTAINER_NAME);
|
|
207
|
+
log.done('✔ Deployment completed.');
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
log.error('✖ Deployment failed.');
|
|
211
|
+
}
|
|
212
|
+
finally {
|
|
213
|
+
await this.clear(ssh);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
async buildDocker(ssh, IMAGE_TAG, REMOTEAPPPATH, TARGET_DIR, CONTAINER_NAME) {
|
|
217
|
+
await this.execCommand(ssh, {
|
|
218
|
+
startMsg: `🐳 Build image: ${IMAGE_TAG}...`,
|
|
219
|
+
succMsg: `🐳 Build image: ${IMAGE_TAG} success.`,
|
|
220
|
+
}, `
|
|
198
221
|
cd "${REMOTEAPPPATH}"
|
|
199
222
|
docker build -t ${IMAGE_TAG} ${TARGET_DIR}
|
|
200
223
|
`);
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
224
|
+
await this.execCommand(ssh, {
|
|
225
|
+
startMsg: `🔄 Stop and clean the old container.: ${CONTAINER_NAME}...`,
|
|
226
|
+
succMsg: `The old container has been successfully cleaned.`,
|
|
227
|
+
}, `
|
|
205
228
|
if docker inspect "${CONTAINER_NAME}" >/dev/null 2>&1; then
|
|
206
229
|
docker stop "${CONTAINER_NAME}";
|
|
207
230
|
docker rm "${CONTAINER_NAME}";
|
|
208
231
|
else
|
|
209
|
-
echo "ℹ️
|
|
232
|
+
echo "ℹ️ container ${CONTAINER_NAME}. Does not exist, skip cleaning.";
|
|
210
233
|
fi
|
|
211
234
|
`);
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
235
|
+
}
|
|
236
|
+
async runDocker(ssh, CONTAINER_NAME) {
|
|
237
|
+
let optionsCLI = `--name ${CONTAINER_NAME} -p ${this.config.BindPorts}`;
|
|
238
|
+
const options = this.config.Options;
|
|
239
|
+
if (options) {
|
|
240
|
+
const optionsKeys = Object.keys(options);
|
|
241
|
+
if (optionsKeys.length > 0) {
|
|
242
|
+
for (let i = 0; i < optionsKeys.length; ++i) {
|
|
243
|
+
const key = optionsKeys[i];
|
|
244
|
+
switch (key) {
|
|
245
|
+
case 'volumes': {
|
|
246
|
+
let volumes = options.volumes.map(volume => `-v ${volume}`).join(' ');
|
|
247
|
+
optionsCLI += ' ' + volumes;
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
case 'networks': {
|
|
251
|
+
optionsCLI += ` --network ${options.networks}`;
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
default:
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
225
259
|
}
|
|
260
|
+
optionsCLI += ` ${this.config.imageTag}`;
|
|
261
|
+
await this.execCommand(ssh, {
|
|
262
|
+
startMsg: `🐳 Start container: ${CONTAINER_NAME}...`,
|
|
263
|
+
succMsg: `🐳 Container started successfully.`,
|
|
264
|
+
}, `
|
|
265
|
+
docker run -d ${optionsCLI}
|
|
266
|
+
`);
|
|
226
267
|
}
|
|
227
268
|
async clear(ssh) {
|
|
228
269
|
await ssh.execCommand(`rm -f ${this.remotePath}`);
|
package/dist/bin/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export declare function deploySSH(configFile?: string): Promise<void>;
|
package/dist/bin/index.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
1
|
import path from 'path';
|
|
3
2
|
import { NodeSSH } from 'node-ssh';
|
|
4
3
|
import { log, ora, exit, chalk, fs } from "./utils/index.js";
|
|
5
4
|
import { Deploy } from "./deploy.js";
|
|
6
5
|
import { createConfig } from "./config.js";
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
6
|
+
export async function deploySSH(configFile = 'deploy-config.json') {
|
|
7
|
+
const ssh = new NodeSSH();
|
|
8
|
+
const CONFIG_FILE = configFile ?? 'deploy-config.json';
|
|
9
|
+
const CONFIG_FILE_PATH = path.resolve(process.cwd(), CONFIG_FILE);
|
|
11
10
|
if (await fs.exist(CONFIG_FILE_PATH)) {
|
|
12
11
|
let config = JSON.parse((await fs.readDirOrFile(CONFIG_FILE_PATH, { encoding: 'utf-8' })));
|
|
13
12
|
if (!config.BindPorts.includes(':')) {
|
|
@@ -21,9 +20,9 @@ async function deploySSH() {
|
|
|
21
20
|
password: config.password,
|
|
22
21
|
}), status => {
|
|
23
22
|
if (status)
|
|
24
|
-
return `SSH
|
|
23
|
+
return `SSH connection successful!`;
|
|
25
24
|
else {
|
|
26
|
-
log.error('SSH
|
|
25
|
+
log.error('SSH connection failed!');
|
|
27
26
|
exit(1);
|
|
28
27
|
return chalk.error(`exit code: 1`);
|
|
29
28
|
}
|
|
@@ -34,17 +33,16 @@ async function deploySSH() {
|
|
|
34
33
|
await deploy.dockcerImageBuild(ssh);
|
|
35
34
|
}
|
|
36
35
|
catch {
|
|
37
|
-
exit(1);
|
|
38
36
|
}
|
|
39
37
|
finally {
|
|
40
38
|
fs.removeSync(path.resolve(process.cwd(), deploy.uploadFileName));
|
|
41
39
|
ssh.dispose();
|
|
40
|
+
exit(1);
|
|
42
41
|
}
|
|
43
42
|
}
|
|
44
43
|
else {
|
|
45
|
-
log.error(`⚠️
|
|
44
|
+
log.error(`⚠️ No configuration file found in the root directory ${CONFIG_FILE}. Will guide the creation... `);
|
|
46
45
|
await createConfig(process.cwd());
|
|
47
46
|
deploySSH();
|
|
48
47
|
}
|
|
49
48
|
}
|
|
50
|
-
deploySSH();
|
package/dist/bin/type/types.d.ts
CHANGED
|
@@ -5,10 +5,15 @@ export type sshConfig = {
|
|
|
5
5
|
user: string;
|
|
6
6
|
password: string;
|
|
7
7
|
beforLaunch: string[];
|
|
8
|
+
Dockerfile: string;
|
|
8
9
|
dockerBuildFiles: string[];
|
|
9
10
|
imageTag: string;
|
|
10
11
|
containerName: string;
|
|
11
12
|
BindPorts: string;
|
|
13
|
+
Options: {
|
|
14
|
+
volumes: string[];
|
|
15
|
+
networks: string;
|
|
16
|
+
};
|
|
12
17
|
};
|
|
13
18
|
export type fileData = string | NodeJS.ArrayBufferView;
|
|
14
19
|
import type { promises } from 'fs';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { program } from 'commander';
|
|
3
|
+
import { fs } from "../bin/utils/fse.js";
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import { deploySSH } from "../bin/index.js";
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
let pkgPath = path.join(__dirname, '../package.json');
|
|
10
|
+
if (!(await fs.exist(pkgPath))) {
|
|
11
|
+
pkgPath = path.join(__dirname, '../../package.json');
|
|
12
|
+
}
|
|
13
|
+
const packageJson = JSON.parse((await fs.readDirOrFile(pkgPath, { encoding: 'utf-8' })));
|
|
14
|
+
program
|
|
15
|
+
.name(packageJson.name)
|
|
16
|
+
.description(packageJson.description)
|
|
17
|
+
.version(`v${packageJson.version}`)
|
|
18
|
+
.argument('[path]', 'deployment configuration file')
|
|
19
|
+
.option('-f, --file <path>', 'set deployment configuration file', 'deploy-config.json')
|
|
20
|
+
.action((path, options) => {
|
|
21
|
+
const targetPath = path ?? options.file;
|
|
22
|
+
if (typeof targetPath !== 'string' || targetPath.trim() === '') {
|
|
23
|
+
throw new Error(`Invalid path: ${targetPath}, path must be a non-empty string`);
|
|
24
|
+
}
|
|
25
|
+
deploySSH(targetPath);
|
|
26
|
+
})
|
|
27
|
+
.parse();
|
package/package.json
CHANGED
|
@@ -1,83 +1,82 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "auto-deploy-sh",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Automated Docker deployment tool",
|
|
5
|
-
"bin": {
|
|
6
|
-
"auto-deploy-sh": "./dist/
|
|
7
|
-
},
|
|
8
|
-
"files": [
|
|
9
|
-
"dist",
|
|
10
|
-
"package.json",
|
|
11
|
-
"README.md"
|
|
12
|
-
],
|
|
13
|
-
"type": "module",
|
|
14
|
-
"main": "./dist/
|
|
15
|
-
"scripts": {
|
|
16
|
-
"build": "npm run clean && tsc -p tsconfig.bulid.json",
|
|
17
|
-
"clean": "rimraf dist build",
|
|
18
|
-
"deploy": "node
|
|
19
|
-
"lint:doc": "prettier **/*.md --check",
|
|
20
|
-
"lint:doc:fix": "prettier **/*.md --write",
|
|
21
|
-
"lint:eslint": "eslint --cache --ext .ts,.vue,.js,.jsx,.tsx,.json",
|
|
22
|
-
"lint:eslint:fix": "eslint --cache --ext .ts,.vue,.js,.jsx,.tsx,.json --fix",
|
|
23
|
-
"prepare": "husky",
|
|
24
|
-
"prepack": "npm run build",
|
|
25
|
-
"postbuild": "node ./postbuild.js"
|
|
26
|
-
},
|
|
27
|
-
"keywords": [
|
|
28
|
-
"Automated",
|
|
29
|
-
"Lower deployment threshold",
|
|
30
|
-
"deployment",
|
|
31
|
-
"Minimalist configuration"
|
|
32
|
-
],
|
|
33
|
-
"repository": {
|
|
34
|
-
"type": "git",
|
|
35
|
-
"url": "https://github.com/yotomum-ml/auto-deploy-sh.git"
|
|
36
|
-
},
|
|
37
|
-
"author": "yotomum_ml",
|
|
38
|
-
"license": "ISC",
|
|
39
|
-
"lint-staged": {
|
|
40
|
-
"*.{js,ts,jsx,tsx,vue,css,json}": [
|
|
41
|
-
"eslint --no-warn-ignored"
|
|
42
|
-
],
|
|
43
|
-
"*.md": [
|
|
44
|
-
"prettier --check --no-warn-ignored"
|
|
45
|
-
]
|
|
46
|
-
},
|
|
47
|
-
"dependencies": {
|
|
48
|
-
"archiver": "^7.0.1",
|
|
49
|
-
"chalk": "^5.6.2",
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"ssh2": "^1.17.0",
|
|
57
|
-
"ts-node": "^10.9.2"
|
|
58
|
-
},
|
|
59
|
-
"engines": {
|
|
60
|
-
"node": ">=18.0.0"
|
|
61
|
-
},
|
|
62
|
-
"devDependencies": {
|
|
63
|
-
"@commitlint/cli": "^19.8.1",
|
|
64
|
-
"@commitlint/config-conventional": "^19.8.1",
|
|
65
|
-
"@eslint/css": "^0.8.1",
|
|
66
|
-
"@eslint/js": "^9.29.0",
|
|
67
|
-
"@eslint/json": "^0.12.0",
|
|
68
|
-
"@stylistic/eslint-plugin": "^4.4.1",
|
|
69
|
-
"@types/archiver": "^6.0.3",
|
|
70
|
-
"@types/fs-extra": "^11.0.4",
|
|
71
|
-
"
|
|
72
|
-
"eslint": "^
|
|
73
|
-
"eslint-
|
|
74
|
-
"eslint-plugin-
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
"typescript": "^
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "auto-deploy-sh",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Automated Docker deployment tool",
|
|
5
|
+
"bin": {
|
|
6
|
+
"auto-deploy-sh": "./dist/cli/index.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"package.json",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"type": "module",
|
|
14
|
+
"main": "./dist/cli/index.js",
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "npm run clean && tsc -p tsconfig.bulid.json",
|
|
17
|
+
"clean": "rimraf dist build",
|
|
18
|
+
"deploy": "node --loader ts-node/esm cli/index.ts",
|
|
19
|
+
"lint:doc": "prettier **/*.md --check",
|
|
20
|
+
"lint:doc:fix": "prettier **/*.md --write",
|
|
21
|
+
"lint:eslint": "eslint --cache --ext .ts,.vue,.js,.jsx,.tsx,.json",
|
|
22
|
+
"lint:eslint:fix": "eslint --cache --ext .ts,.vue,.js,.jsx,.tsx,.json --fix",
|
|
23
|
+
"prepare": "husky",
|
|
24
|
+
"prepack": "npm run build",
|
|
25
|
+
"postbuild": "node ./postbuild.js"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"Automated",
|
|
29
|
+
"Lower deployment threshold",
|
|
30
|
+
"deployment",
|
|
31
|
+
"Minimalist configuration"
|
|
32
|
+
],
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "https://github.com/yotomum-ml/auto-deploy-sh.git"
|
|
36
|
+
},
|
|
37
|
+
"author": "yotomum_ml",
|
|
38
|
+
"license": "ISC",
|
|
39
|
+
"lint-staged": {
|
|
40
|
+
"*.{js,ts,jsx,tsx,vue,css,json}": [
|
|
41
|
+
"eslint --no-warn-ignored"
|
|
42
|
+
],
|
|
43
|
+
"*.md": [
|
|
44
|
+
"prettier --check --no-warn-ignored"
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"archiver": "^7.0.1",
|
|
49
|
+
"chalk": "^5.6.2",
|
|
50
|
+
"commander": "^13.1.0",
|
|
51
|
+
"execa": "^9.6.0",
|
|
52
|
+
"fs-extra": "^11.3.1",
|
|
53
|
+
"inquirer": "^12.9.6",
|
|
54
|
+
"node-ssh": "^13.2.1",
|
|
55
|
+
"ora": "^8.2.0",
|
|
56
|
+
"ssh2": "^1.17.0",
|
|
57
|
+
"ts-node": "^10.9.2"
|
|
58
|
+
},
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=18.0.0"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@commitlint/cli": "^19.8.1",
|
|
64
|
+
"@commitlint/config-conventional": "^19.8.1",
|
|
65
|
+
"@eslint/css": "^0.8.1",
|
|
66
|
+
"@eslint/js": "^9.29.0",
|
|
67
|
+
"@eslint/json": "^0.12.0",
|
|
68
|
+
"@stylistic/eslint-plugin": "^4.4.1",
|
|
69
|
+
"@types/archiver": "^6.0.3",
|
|
70
|
+
"@types/fs-extra": "^11.0.4",
|
|
71
|
+
"eslint": "^9.27.0",
|
|
72
|
+
"eslint-config-prettier": "^10.1.5",
|
|
73
|
+
"eslint-plugin-prettier": "^5.4.1",
|
|
74
|
+
"eslint-plugin-vue": "^10.2.0",
|
|
75
|
+
"husky": "^9.1.7",
|
|
76
|
+
"lint-staged": "^15.5.2",
|
|
77
|
+
"node-notifier": "^10.0.1",
|
|
78
|
+
"rimraf": "^5.0.10",
|
|
79
|
+
"typescript": "^5.8.3",
|
|
80
|
+
"typescript-eslint": "^8.34.1"
|
|
81
|
+
}
|
|
82
|
+
}
|