d3ployer 0.0.12 → 0.0.14
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 +52 -12
- package/dist/bin.js +0 -0
- package/dist/cli.js +6 -4
- package/dist/config.d.ts +2 -1
- package/dist/config.js +3 -0
- package/dist/configLoader.d.ts +1 -1
- package/dist/configLoader.js +36 -1
- package/dist/def.d.ts +18 -14
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/runner.d.ts +4 -5
- package/dist/tasks/download.d.ts +2 -2
- package/dist/tasks/download.js +21 -14
- package/dist/tasks/helpers/docker.d.ts +2 -0
- package/dist/tasks/helpers/docker.js +13 -0
- package/dist/tasks/helpers/rsync.d.ts +6 -0
- package/dist/tasks/helpers/rsync.js +38 -0
- package/dist/tasks/index.d.ts +2 -2
- package/dist/tasks/index.js +1 -1
- package/dist/tasks/printLogs.js +1 -1
- package/dist/tasks/setupDocker.d.ts +1 -2
- package/dist/tasks/setupDocker.js +1 -13
- package/dist/tasks/upload.d.ts +1 -5
- package/dist/tasks/upload.js +21 -44
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ export default defineConfig({
|
|
|
25
25
|
},
|
|
26
26
|
},
|
|
27
27
|
files: {
|
|
28
|
-
|
|
28
|
+
localPath: './dist',
|
|
29
29
|
exclude: ['node_modules', '.git'],
|
|
30
30
|
},
|
|
31
31
|
symlinks: [
|
|
@@ -55,16 +55,29 @@ dpl list # list available scenarios, tasks, and serve
|
|
|
55
55
|
## CLI
|
|
56
56
|
|
|
57
57
|
```
|
|
58
|
-
dpl <name> [servers...]
|
|
59
|
-
dpl list
|
|
58
|
+
dpl <name> [servers...] Run a scenario or task
|
|
59
|
+
dpl list List scenarios, tasks, and servers
|
|
60
60
|
|
|
61
61
|
Options:
|
|
62
|
-
-
|
|
63
|
-
--skip <tasks>
|
|
62
|
+
-p, --project <path> Path to deployer.config.ts
|
|
63
|
+
--skip <tasks> Comma-separated list of tasks to skip
|
|
64
|
+
--config <task.key=value...> Override task config values at runtime
|
|
64
65
|
```
|
|
65
66
|
|
|
66
67
|
If `<name>` matches a scenario, it runs all tasks in that scenario sequentially. Otherwise it runs the matching task directly.
|
|
67
68
|
|
|
69
|
+
### Runtime config overrides
|
|
70
|
+
|
|
71
|
+
Use `--config` to override individual task config values without editing `deployer.config.ts`. Values are automatically coerced to `boolean` (`true`/`false`) or `number` where applicable.
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
dpl deploy --config download.dryRun=true
|
|
75
|
+
dpl upload --config upload.delete=false
|
|
76
|
+
dpl deploy --config myTask.someKey=hello --config myTask.retries=3
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The format is `taskName.path.to.key=value`, where `taskName` is the task's key in the config.
|
|
80
|
+
|
|
68
81
|
## Config
|
|
69
82
|
|
|
70
83
|
### `servers`
|
|
@@ -90,12 +103,22 @@ Configure rsync file upload.
|
|
|
90
103
|
|
|
91
104
|
```ts
|
|
92
105
|
files: {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
106
|
+
localPath: './dist', // local directory to sync (relative to rootDir or absolute, default: '.')
|
|
107
|
+
remotePath: 'app', // remote directory (relative to deployPath or absolute, default: deployPath)
|
|
108
|
+
include: ['src/**'], // rsync include patterns
|
|
109
|
+
exclude: ['node_modules'], // rsync exclude patterns
|
|
96
110
|
}
|
|
97
111
|
```
|
|
98
112
|
|
|
113
|
+
Or as an array of entries to sync multiple directories:
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
files: [
|
|
117
|
+
{ localPath: './dist', remotePath: 'app', exclude: ['*.map'] },
|
|
118
|
+
{ localPath: './config', remotePath: 'config' },
|
|
119
|
+
]
|
|
120
|
+
```
|
|
121
|
+
|
|
99
122
|
### `symlinks`
|
|
100
123
|
|
|
101
124
|
Create symlinks on the remote server.
|
|
@@ -175,9 +198,26 @@ tasks: {
|
|
|
175
198
|
}
|
|
176
199
|
```
|
|
177
200
|
|
|
201
|
+
Use `defineTask` for type-safe task definitions with a typed config:
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
import { defineConfig, defineTask } from 'd3ployer';
|
|
205
|
+
|
|
206
|
+
export default defineConfig({
|
|
207
|
+
tasks: {
|
|
208
|
+
myTask: defineTask<{ retries: number }>({
|
|
209
|
+
task: async (ctx) => {
|
|
210
|
+
const retries = ctx.taskConfig!.retries; // typed as number
|
|
211
|
+
},
|
|
212
|
+
config: { retries: 3 },
|
|
213
|
+
}),
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
```
|
|
217
|
+
|
|
178
218
|
Task keys are auto-converted from camelCase to colon:case (e.g. `depInstall` becomes `dep:install`).
|
|
179
219
|
|
|
180
|
-
**TaskContext
|
|
220
|
+
**TaskContext\<C\>** provides:
|
|
181
221
|
- `run(cmd, options?)` - execute a command on the remote server (auto cd's to `deployPath`)
|
|
182
222
|
- `test(cmd)` - execute a command on the remote server, returns `boolean`
|
|
183
223
|
- `runLocal(cmd, options?)` - execute a command locally
|
|
@@ -185,7 +225,7 @@ Task keys are auto-converted from camelCase to colon:case (e.g. `depInstall` bec
|
|
|
185
225
|
- `server` - current server config (includes `name`)
|
|
186
226
|
- `ssh` - SSH2Promise connection
|
|
187
227
|
- `config` - full deployer config
|
|
188
|
-
- `taskConfig` - per-task config from task definition
|
|
228
|
+
- `taskConfig` - per-task config from task definition (typed as `C` when using `defineTask<C>`)
|
|
189
229
|
|
|
190
230
|
**RunOptions** (for `run` and `runLocal`):
|
|
191
231
|
- `printOutput` - print stdout/stderr (default: `true`)
|
|
@@ -221,8 +261,8 @@ scenarios: {
|
|
|
221
261
|
|
|
222
262
|
| Task | Description |
|
|
223
263
|
| ------------------- | -------------------------------------------------------- |
|
|
224
|
-
| `upload` | Rsync files to the remote server
|
|
225
|
-
| `download` | Rsync files from the remote server (uses task config)
|
|
264
|
+
| `upload` | Rsync files to the remote server (supports multiple file entries) |
|
|
265
|
+
| `download` | Rsync files from the remote server (uses task config, supports multiple file entries) |
|
|
226
266
|
| `symlinks` | Create configured symlinks on the remote server |
|
|
227
267
|
| `install:packages` | Install dependencies via npm/yarn/pnpm |
|
|
228
268
|
| `setup:pm2` | Start/restart PM2 processes (auto-detects pm2.config.*) |
|
package/dist/bin.js
CHANGED
|
File without changes
|
package/dist/cli.js
CHANGED
|
@@ -6,15 +6,16 @@ import { runScenario, runTask } from './runner.js';
|
|
|
6
6
|
const program = new Command()
|
|
7
7
|
.name('deployer')
|
|
8
8
|
.description('TypeScript deployment tool')
|
|
9
|
-
.option('-
|
|
10
|
-
.option('--skip <tasks>', 'comma-separated list of tasks to skip')
|
|
9
|
+
.option('-p, --project <path>', 'path to deployer.config.ts')
|
|
10
|
+
.option('--skip <tasks>', 'comma-separated list of tasks to skip')
|
|
11
|
+
.option('-c, --config <taskConfig...>', 'option to override task config (format: path.to.entity=value)');
|
|
11
12
|
program
|
|
12
13
|
.argument('<name>', 'scenario or task name')
|
|
13
14
|
.argument('[servers...]', 'target server(s)')
|
|
14
15
|
.action(async (name, servers) => {
|
|
15
16
|
try {
|
|
16
17
|
const opts = program.opts();
|
|
17
|
-
const config = await loadConfig(opts.config);
|
|
18
|
+
const config = await loadConfig(opts.project, opts.config);
|
|
18
19
|
const serverList = servers.length > 0 ? servers : undefined;
|
|
19
20
|
const skipTasks = opts.skip
|
|
20
21
|
? opts.skip.split(',').map((s) => s.trim()).filter(Boolean)
|
|
@@ -36,7 +37,8 @@ program
|
|
|
36
37
|
.description('list available scenarios, tasks and servers')
|
|
37
38
|
.action(async () => {
|
|
38
39
|
try {
|
|
39
|
-
const
|
|
40
|
+
const opts = program.opts();
|
|
41
|
+
const config = await loadConfig(opts.project, opts.config);
|
|
40
42
|
console.log(chalk.bold('\nScenarios:'));
|
|
41
43
|
const scenarios = config.scenarios ?? {};
|
|
42
44
|
const scenarioKeys = Object.keys(scenarios);
|
package/dist/config.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import type { DeployerConfig, DeployerConfigInput } from './def.js';
|
|
1
|
+
import type { DeployerConfig, DeployerConfigInput, TaskConfigBase } from './def.js';
|
|
2
|
+
export declare function defineTask<C>(input: TaskConfigBase<C>): TaskConfigBase<C>;
|
|
2
3
|
export declare function defineConfig(input: DeployerConfigInput): DeployerConfig;
|
package/dist/config.js
CHANGED
|
@@ -35,6 +35,9 @@ function normalizeScenario(key, input) {
|
|
|
35
35
|
tasks: input.tasks,
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
|
+
export function defineTask(input) {
|
|
39
|
+
return input;
|
|
40
|
+
}
|
|
38
41
|
export function defineConfig(input) {
|
|
39
42
|
const servers = {};
|
|
40
43
|
for (const [name, serverInput] of Object.entries(input.servers)) {
|
package/dist/configLoader.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { DeployerConfig } from './def.js';
|
|
2
2
|
export declare function findConfigFile(startDir?: string): string;
|
|
3
|
-
export declare function loadConfig(configPath?: string): Promise<DeployerConfig>;
|
|
3
|
+
export declare function loadConfig(configPath?: string, configOverrides?: string[]): Promise<DeployerConfig>;
|
package/dist/configLoader.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { set } from 'lodash-es';
|
|
1
2
|
import fs from 'node:fs';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import { Exception } from './utils/Exception.js';
|
|
@@ -15,7 +16,7 @@ export function findConfigFile(startDir = process.cwd()) {
|
|
|
15
16
|
} while (parent !== dir);
|
|
16
17
|
throw new Exception(`Could not find ${CONFIG_FILENAME} in ${startDir} or any parent directory`, 1774741892462);
|
|
17
18
|
}
|
|
18
|
-
export async function loadConfig(configPath) {
|
|
19
|
+
export async function loadConfig(configPath, configOverrides) {
|
|
19
20
|
const resolvedPath = configPath ?? findConfigFile();
|
|
20
21
|
const absolutePath = path.resolve(resolvedPath);
|
|
21
22
|
if (!fs.existsSync(absolutePath)) {
|
|
@@ -27,5 +28,39 @@ export async function loadConfig(configPath) {
|
|
|
27
28
|
if (!config.servers || Object.keys(config.servers).length === 0) {
|
|
28
29
|
throw new Exception('Config must define at least one server', 1774741913430);
|
|
29
30
|
}
|
|
31
|
+
// override task config if provided via CLI
|
|
32
|
+
if (configOverrides) {
|
|
33
|
+
for (const configOverride of configOverrides) {
|
|
34
|
+
const eqIdx = configOverride.indexOf('=');
|
|
35
|
+
if (eqIdx === -1) {
|
|
36
|
+
console.warn(`Invalid task config override (missing '='): ${configOverride}`);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const overrideKey = configOverride.slice(0, eqIdx);
|
|
40
|
+
const rawValue = configOverride.slice(eqIdx + 1);
|
|
41
|
+
const keyParts = overrideKey.split('.');
|
|
42
|
+
if (keyParts.length < 2) {
|
|
43
|
+
console.warn(`Invalid task config override key: ${overrideKey}`);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const [taskName, ...configPathParts] = keyParts;
|
|
47
|
+
const taskDef = config.tasks?.[taskName];
|
|
48
|
+
if (!taskDef) {
|
|
49
|
+
console.warn(`Task not found for config override: ${taskName}`);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (!taskDef.config) {
|
|
53
|
+
taskDef.config = {};
|
|
54
|
+
}
|
|
55
|
+
const value = rawValue === 'true'
|
|
56
|
+
? true
|
|
57
|
+
: rawValue === 'false'
|
|
58
|
+
? false
|
|
59
|
+
: rawValue !== '' && !isNaN(Number(rawValue))
|
|
60
|
+
? Number(rawValue)
|
|
61
|
+
: rawValue;
|
|
62
|
+
set(taskDef.config, configPathParts, value);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
30
65
|
return config;
|
|
31
66
|
}
|
package/dist/def.d.ts
CHANGED
|
@@ -19,11 +19,13 @@ export interface ServerConfig {
|
|
|
19
19
|
initCmd?: string;
|
|
20
20
|
}
|
|
21
21
|
export type ServerConfigInput = Partial<ServerConfig> & Pick<ServerConfig, 'host' | 'deployPath'>;
|
|
22
|
-
export interface
|
|
23
|
-
|
|
22
|
+
export interface FilesConfigBase {
|
|
23
|
+
localPath?: string;
|
|
24
|
+
remotePath?: string;
|
|
24
25
|
include?: string[];
|
|
25
26
|
exclude?: string[];
|
|
26
27
|
}
|
|
28
|
+
export type FilesConfig = FilesConfigBase | FilesConfigBase[];
|
|
27
29
|
export interface SymlinkConfig {
|
|
28
30
|
path: string;
|
|
29
31
|
target: string;
|
|
@@ -40,6 +42,12 @@ export type DockerComposeConfig = {
|
|
|
40
42
|
configFiles: string[];
|
|
41
43
|
logs: ConfigOrDisable<LogsConfig>;
|
|
42
44
|
};
|
|
45
|
+
export interface TaskDef {
|
|
46
|
+
name: string;
|
|
47
|
+
task: TaskFn;
|
|
48
|
+
skip?: TaskSkipFn;
|
|
49
|
+
config?: any;
|
|
50
|
+
}
|
|
43
51
|
export interface DeployerConfig {
|
|
44
52
|
rootDir: string;
|
|
45
53
|
servers: Record<string, ServerConfig>;
|
|
@@ -71,7 +79,7 @@ export type RunOptions = {
|
|
|
71
79
|
printOutput?: boolean;
|
|
72
80
|
ignoreError?: boolean;
|
|
73
81
|
};
|
|
74
|
-
export interface TaskContext {
|
|
82
|
+
export interface TaskContext<C = any> {
|
|
75
83
|
server: ServerConfig & {
|
|
76
84
|
name: string;
|
|
77
85
|
};
|
|
@@ -81,22 +89,18 @@ export interface TaskContext {
|
|
|
81
89
|
testLocal: (cmd: string) => Promise<boolean>;
|
|
82
90
|
run: (cmd: string, options?: RunOptions) => Promise<ExecResult>;
|
|
83
91
|
test: (cmd: string) => Promise<boolean>;
|
|
84
|
-
taskConfig?:
|
|
92
|
+
taskConfig?: C;
|
|
85
93
|
}
|
|
86
|
-
export type TaskFn = (ctx: TaskContext
|
|
94
|
+
export type TaskFn<C = any> = (ctx: TaskContext<C>, ph: Placeholders, task: ListrTaskWrapper<any, any, any>) => Promise<void>;
|
|
87
95
|
export type TaskSkipFn = (ctx: TaskContext, ph: Placeholders) => Promise<boolean | string> | boolean | string;
|
|
88
|
-
export
|
|
89
|
-
name: string;
|
|
90
|
-
task: TaskFn;
|
|
91
|
-
skip?: TaskSkipFn;
|
|
92
|
-
config?: any;
|
|
93
|
-
}
|
|
94
|
-
export type TaskInput = TaskFn | {
|
|
96
|
+
export type TaskConfigBase<C = any> = {
|
|
95
97
|
name?: string;
|
|
96
|
-
task: TaskFn
|
|
98
|
+
task: TaskFn<C>;
|
|
97
99
|
skip?: TaskSkipFn;
|
|
98
|
-
config?:
|
|
100
|
+
config?: C;
|
|
99
101
|
};
|
|
102
|
+
export type TaskConfig<T = any> = T extends TaskFn<infer C> ? TaskConfigBase<C> : TaskConfigBase;
|
|
103
|
+
export type TaskInput<C = any> = TaskFn<C> | TaskConfig<C>;
|
|
100
104
|
export interface ScenarioDef {
|
|
101
105
|
name: string;
|
|
102
106
|
tasks: string[];
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export type { AuthMethod, DeployerConfig, DeployerConfigInput, FilesConfig, LogsConfig, Placeholders, ScenarioDef, ScenarioInput, ServerConfig, ServerConfigInput, SymlinkConfig, TaskContext, TaskDef, TaskFn, TaskInput, TaskSkipFn, } from './def.js';
|
|
2
|
-
export { defineConfig } from './config.js';
|
|
2
|
+
export { defineConfig, defineTask } from './config.js';
|
|
3
3
|
export { runScenario, runTask } from './runner.js';
|
|
4
4
|
export { loadConfig, findConfigFile } from './configLoader.js';
|
|
5
5
|
export { buildRsyncCommand, downloadSkip, downloadTask } from './tasks/index.js';
|
|
6
|
-
export type { RsyncOptions } from './tasks/
|
|
6
|
+
export type { RsyncOptions } from './tasks/index.js';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { defineConfig } from './config.js';
|
|
1
|
+
export { defineConfig, defineTask } from './config.js';
|
|
2
2
|
export { runScenario, runTask } from './runner.js';
|
|
3
3
|
export { loadConfig, findConfigFile } from './configLoader.js';
|
|
4
4
|
export { buildRsyncCommand, downloadSkip, downloadTask } from './tasks/index.js';
|
package/dist/runner.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import type { DeployerConfig, ServerConfig, TaskDef } from './def.js';
|
|
2
2
|
export declare function resolveServers(config: DeployerConfig, serverNames?: string[]): Record<string, ServerConfig>;
|
|
3
3
|
export declare function resolveTaskDefs(taskNames: string[], allTasks: Record<string, TaskDef>): Record<string, TaskDef>;
|
|
4
|
-
export
|
|
4
|
+
export type RunTaskOrScenarioOptions = {
|
|
5
5
|
skip?: string[];
|
|
6
|
-
}
|
|
7
|
-
export declare function
|
|
8
|
-
|
|
9
|
-
}): Promise<void>;
|
|
6
|
+
};
|
|
7
|
+
export declare function runScenario(config: DeployerConfig, scenarioName: string, serverNames?: string[], options?: RunTaskOrScenarioOptions): Promise<void>;
|
|
8
|
+
export declare function runTask(config: DeployerConfig, taskName: string, serverNames?: string[], options?: RunTaskOrScenarioOptions): Promise<void>;
|
package/dist/tasks/download.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { TaskFn, TaskSkipFn } from '../def.js';
|
|
1
|
+
import type { FilesConfig, TaskFn, TaskSkipFn } from '../def.js';
|
|
2
2
|
export declare const downloadSkip: TaskSkipFn;
|
|
3
|
-
export declare const downloadTask: TaskFn
|
|
3
|
+
export declare const downloadTask: TaskFn<FilesConfig>;
|
package/dist/tasks/download.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { Exception } from '../utils/index.js';
|
|
4
|
-
import { buildRsyncCommand } from './
|
|
4
|
+
import { buildRsyncCommand } from './helpers/rsync.js';
|
|
5
5
|
export const downloadSkip = (ctx) => {
|
|
6
6
|
const files = ctx.taskConfig;
|
|
7
7
|
return !files
|
|
@@ -9,19 +9,26 @@ export const downloadSkip = (ctx) => {
|
|
|
9
9
|
: false;
|
|
10
10
|
};
|
|
11
11
|
export const downloadTask = async (ctx, ph) => {
|
|
12
|
-
|
|
13
|
-
if (!files) {
|
|
12
|
+
if (!ctx.taskConfig) {
|
|
14
13
|
throw new Exception('No files configuration provided in task config', 1784523741234);
|
|
15
14
|
}
|
|
16
|
-
const
|
|
17
|
-
?
|
|
18
|
-
:
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
15
|
+
const filesArray = ctx.taskConfig instanceof Array
|
|
16
|
+
? ctx.taskConfig
|
|
17
|
+
: [ctx.taskConfig];
|
|
18
|
+
for (const filesEntry of filesArray) {
|
|
19
|
+
const localBase = filesEntry.localPath?.startsWith('/')
|
|
20
|
+
? filesEntry.localPath
|
|
21
|
+
: path.resolve(ctx.config.rootDir, filesEntry.localPath ?? '.');
|
|
22
|
+
const remotePath = filesEntry.remotePath?.startsWith('/')
|
|
23
|
+
? filesEntry.remotePath
|
|
24
|
+
: path.join(ctx.server.deployPath, filesEntry.remotePath ?? '.');
|
|
25
|
+
const source = `${ctx.server.username}@${ctx.server.host}:${remotePath}/`;
|
|
26
|
+
const dest = localBase.endsWith('/') ? localBase : localBase + '/';
|
|
27
|
+
const command = buildRsyncCommand(ctx.server, source, dest, filesEntry, {
|
|
28
|
+
delete: false,
|
|
29
|
+
...ctx.taskConfig,
|
|
30
|
+
});
|
|
31
|
+
console.log(chalk.grey(command));
|
|
32
|
+
await ctx.runLocal(command);
|
|
33
|
+
}
|
|
27
34
|
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function buildDockerComposeTestCmd(dockerComposeConfig) {
|
|
2
|
+
if (dockerComposeConfig === false) {
|
|
3
|
+
return 'false';
|
|
4
|
+
}
|
|
5
|
+
const configFiles = dockerComposeConfig.configFiles ?? [
|
|
6
|
+
'docker-compose.yml',
|
|
7
|
+
'docker-compose.yaml',
|
|
8
|
+
'compose.yml',
|
|
9
|
+
'compose.yaml',
|
|
10
|
+
];
|
|
11
|
+
const testCmdPart = configFiles.map(f => `-f ${f}`);
|
|
12
|
+
return `test ${testCmdPart.join(' -o ')}`;
|
|
13
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { FilesConfigBase, ServerConfig } from '../../def.js';
|
|
2
|
+
export type RsyncOptions = {
|
|
3
|
+
delete?: boolean;
|
|
4
|
+
dryRun?: boolean;
|
|
5
|
+
};
|
|
6
|
+
export declare function buildRsyncCommand(server: ServerConfig, source: string, dest: string, files: FilesConfigBase, options?: RsyncOptions): string;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export function buildRsyncCommand(server, source, dest, files, options = {}) {
|
|
2
|
+
options = {
|
|
3
|
+
delete: true,
|
|
4
|
+
dryRun: false,
|
|
5
|
+
...options,
|
|
6
|
+
};
|
|
7
|
+
const args = ['rsync', '-avz', '--progress=info2'];
|
|
8
|
+
if (options.delete) {
|
|
9
|
+
args.push('--delete');
|
|
10
|
+
}
|
|
11
|
+
if (options.dryRun) {
|
|
12
|
+
args.push('--dry-run');
|
|
13
|
+
}
|
|
14
|
+
// ssh shell
|
|
15
|
+
const sshParts = ['ssh'];
|
|
16
|
+
if (server.port && server.port !== 22) {
|
|
17
|
+
sshParts.push(`-p ${server.port}`);
|
|
18
|
+
}
|
|
19
|
+
if (server.authMethod === 'key' && server.privateKey) {
|
|
20
|
+
sshParts.push(`-i ${server.privateKey}`);
|
|
21
|
+
}
|
|
22
|
+
sshParts.push('-o StrictHostKeyChecking=no');
|
|
23
|
+
args.push('-e', `"${sshParts.join(' ')}"`);
|
|
24
|
+
// include/exclude
|
|
25
|
+
if (files.exclude) {
|
|
26
|
+
for (const pattern of files.exclude) {
|
|
27
|
+
args.push(`--exclude="${pattern}"`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (files.include) {
|
|
31
|
+
for (const pattern of files.include) {
|
|
32
|
+
args.push(`--include="${pattern}"`);
|
|
33
|
+
}
|
|
34
|
+
args.push('--exclude="*"');
|
|
35
|
+
}
|
|
36
|
+
args.push(source, dest);
|
|
37
|
+
return args.join(' ');
|
|
38
|
+
}
|
package/dist/tasks/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ScenarioDef, TaskDef } from '../def.js';
|
|
2
|
-
export { buildRsyncCommand } from './
|
|
3
|
-
export type { RsyncOptions } from './
|
|
2
|
+
export { buildRsyncCommand } from './helpers/rsync.js';
|
|
3
|
+
export type { RsyncOptions } from './helpers/rsync.js';
|
|
4
4
|
export { downloadSkip, downloadTask } from './download.js';
|
|
5
5
|
export declare const defaultTasks: Record<string, TaskDef>;
|
|
6
6
|
export declare const defaultScenarios: Record<string, ScenarioDef>;
|
package/dist/tasks/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { setupDockerSkip, setupDockerTask } from './setupDocker.js';
|
|
|
7
7
|
import { setupPm2Skip, setupPm2Task } from './setupPm2.js';
|
|
8
8
|
import { symlinksSkip, symlinksTask } from './symlinks.js';
|
|
9
9
|
import { uploadSkip, uploadTask } from './upload.js';
|
|
10
|
-
export { buildRsyncCommand } from './
|
|
10
|
+
export { buildRsyncCommand } from './helpers/rsync.js';
|
|
11
11
|
export { downloadSkip, downloadTask } from './download.js';
|
|
12
12
|
export const defaultTasks = {
|
|
13
13
|
'clear:target': {
|
package/dist/tasks/printLogs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
import { buildDockerComposeTestCmd } from './
|
|
2
|
+
import { buildDockerComposeTestCmd } from './helpers/docker.js';
|
|
3
3
|
export const printLogsPm2Skip = async (ctx) => {
|
|
4
4
|
if (ctx.config.pm2 === false
|
|
5
5
|
|| ctx.config.pm2.logs === false) {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare function buildDockerComposeTestCmd(dockerComposeConfig: DockerComposeConfig | false): string;
|
|
1
|
+
import type { TaskFn, TaskSkipFn } from '../def.js';
|
|
3
2
|
export declare const setupDockerSkip: TaskSkipFn;
|
|
4
3
|
export declare const setupDockerTask: TaskFn;
|
|
@@ -1,16 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
if (dockerComposeConfig === false) {
|
|
3
|
-
return 'false';
|
|
4
|
-
}
|
|
5
|
-
const configFiles = dockerComposeConfig.configFiles ?? [
|
|
6
|
-
'docker-compose.yml',
|
|
7
|
-
'docker-compose.yaml',
|
|
8
|
-
'compose.yml',
|
|
9
|
-
'compose.yaml',
|
|
10
|
-
];
|
|
11
|
-
const testCmdPart = configFiles.map(f => `-f ${f}`);
|
|
12
|
-
return `test ${testCmdPart.join(' -o ')}`;
|
|
13
|
-
}
|
|
1
|
+
import { buildDockerComposeTestCmd } from './helpers/docker.js';
|
|
14
2
|
export const setupDockerSkip = async (ctx) => {
|
|
15
3
|
if (ctx.config.dockerCompose === false) {
|
|
16
4
|
return 'Docker Compose disabled';
|
package/dist/tasks/upload.d.ts
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export type RsyncOptions = {
|
|
3
|
-
delete?: boolean;
|
|
4
|
-
};
|
|
5
|
-
export declare function buildRsyncCommand(server: ServerConfig, source: string, dest: string, files: FilesConfig, options?: RsyncOptions): string;
|
|
1
|
+
import type { TaskFn, TaskSkipFn } from '../def.js';
|
|
6
2
|
export declare const uploadSkip: TaskSkipFn;
|
|
7
3
|
export declare const uploadTask: TaskFn;
|
package/dist/tasks/upload.js
CHANGED
|
@@ -1,36 +1,6 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
|
|
4
|
-
const { delete: useDelete = true, } = options;
|
|
5
|
-
const args = ['rsync', '-avz', '--progress=info2'];
|
|
6
|
-
if (useDelete) {
|
|
7
|
-
args.push('--delete');
|
|
8
|
-
}
|
|
9
|
-
// ssh shell
|
|
10
|
-
const sshParts = ['ssh'];
|
|
11
|
-
if (server.port && server.port !== 22) {
|
|
12
|
-
sshParts.push(`-p ${server.port}`);
|
|
13
|
-
}
|
|
14
|
-
if (server.authMethod === 'key' && server.privateKey) {
|
|
15
|
-
sshParts.push(`-i ${server.privateKey}`);
|
|
16
|
-
}
|
|
17
|
-
sshParts.push('-o StrictHostKeyChecking=no');
|
|
18
|
-
args.push('-e', `"${sshParts.join(' ')}"`);
|
|
19
|
-
// include/exclude
|
|
20
|
-
if (files.exclude) {
|
|
21
|
-
for (const pattern of files.exclude) {
|
|
22
|
-
args.push(`--exclude="${pattern}"`);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
if (files.include) {
|
|
26
|
-
for (const pattern of files.include) {
|
|
27
|
-
args.push(`--include="${pattern}"`);
|
|
28
|
-
}
|
|
29
|
-
args.push('--exclude="*"');
|
|
30
|
-
}
|
|
31
|
-
args.push(source, dest);
|
|
32
|
-
return args.join(' ');
|
|
33
|
-
}
|
|
3
|
+
import { buildRsyncCommand } from './helpers/rsync.js';
|
|
34
4
|
export const uploadSkip = (ctx) => {
|
|
35
5
|
const files = ctx.config.files;
|
|
36
6
|
return !files
|
|
@@ -38,17 +8,24 @@ export const uploadSkip = (ctx) => {
|
|
|
38
8
|
: false;
|
|
39
9
|
};
|
|
40
10
|
export const uploadTask = async (ctx, ph) => {
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
11
|
+
const filesArray = ctx.config.files instanceof Array
|
|
12
|
+
? ctx.config.files
|
|
13
|
+
: [ctx.config.files];
|
|
14
|
+
for (const filesEntry of filesArray) {
|
|
15
|
+
const localBase = filesEntry.localPath?.startsWith('/')
|
|
16
|
+
? filesEntry.localPath
|
|
17
|
+
: path.resolve(ctx.config.rootDir, filesEntry.localPath ?? '.');
|
|
18
|
+
const remotePath = filesEntry.remotePath?.startsWith('/')
|
|
19
|
+
? filesEntry.remotePath
|
|
20
|
+
: path.join(ctx.server.deployPath, filesEntry.remotePath ?? '.');
|
|
21
|
+
const dest = `${ctx.server.username}@${ctx.server.host}:${remotePath}`;
|
|
22
|
+
const source = localBase.endsWith('/') ? localBase : localBase + '/';
|
|
23
|
+
await ctx.run(`mkdir -p ${remotePath}`);
|
|
24
|
+
const command = buildRsyncCommand(ctx.server, source, dest, filesEntry, {
|
|
25
|
+
delete: true,
|
|
26
|
+
...ctx.taskConfig,
|
|
27
|
+
});
|
|
28
|
+
console.log(chalk.grey(command));
|
|
29
|
+
await ctx.runLocal(command);
|
|
30
|
+
}
|
|
54
31
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "d3ployer",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.14",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"@tsconfig/node24": "^24.0.4",
|
|
40
40
|
"@types/chai": "^5.2.3",
|
|
41
41
|
"@types/chai-as-promised": "^8.0.2",
|
|
42
|
+
"@types/lodash-es": "^4.17.12",
|
|
42
43
|
"@types/mocha": "^10.0.10",
|
|
43
44
|
"@types/node": "^24.10.13",
|
|
44
45
|
"c8": "^10.1.3",
|