@dotcms/dotcli 1.0.0-rc2 → 1.0.0-rc4
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
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
# dotCMS CLI
|
|
2
|
-
The dotCMS CLI is a
|
|
2
|
+
The **dotCMS CLI**, sometimes shortened to **dotCLI**, is a standalone tool for interacting with a dotCMS instance through a command shell, allowing a wide array of automated operations and behaviors.
|
|
3
|
+
|
|
4
|
+
## Getting Started
|
|
5
|
+
|
|
6
|
+
### Installation
|
|
7
|
+
|
|
8
|
+
### NPM
|
|
9
|
+
|
|
10
|
+
The simplest and most recommended way to get the dotCMS CLI is from its npm package:
|
|
11
|
+
|
|
12
|
+
```shell script
|
|
13
|
+
npm install -g @dotcms/dotcli
|
|
14
|
+
```
|
|
15
|
+
### Manual JAR Download
|
|
3
16
|
|
|
4
|
-
## Quick start
|
|
5
17
|
1. Download the CLI: The dotCMS CLI is delivered as an uber jar that can be downloaded from [here](https://repo.dotcms.com/artifactory/libs-snapshot-local/com/dotcms/dotcms-cli/).
|
|
6
18
|
Once downloaded, you just need to run it with:
|
|
7
19
|
|
|
@@ -9,7 +21,7 @@ The dotCMS CLI is a command-line tool that you can use to populate and modify yo
|
|
|
9
21
|
java -jar dotcli.jar
|
|
10
22
|
```
|
|
11
23
|
|
|
12
|
-
2. Configure the dotCMS instances you want to connect to using
|
|
24
|
+
2. Configure the dotCMS instances you want to connect to using the `config` command. More details on how to do it on the [Configuration](#Configuration) section.
|
|
13
25
|
|
|
14
26
|
3. Log in to the selected instance
|
|
15
27
|
```shell script
|
|
@@ -22,6 +34,7 @@ java -jar dotcli.jar login --user={USER} --password
|
|
|
22
34
|
|
|
23
35
|
| Command | Description |
|
|
24
36
|
|--------------------------------------------|-------------------------------------------------------------------------------------|
|
|
37
|
+
| [config](cli/docs/config.adoc) | Sets the initial configuration required by all commands to operate |
|
|
25
38
|
| [content-type](cli/docs/content-type.adoc) | Performs operations over content types. For example: pull, push, remove |
|
|
26
39
|
| [files](cli/docs/files.adoc) | Performs operations over files. For example: tree, ls, push |
|
|
27
40
|
| [instance](cli/docs/instance.adoc) | Prints a list of available dotCMS instances |
|
|
@@ -39,7 +52,21 @@ You can find more details about how to use the dotCMS CLI in the [Examples](#exa
|
|
|
39
52
|
|
|
40
53
|
## Examples
|
|
41
54
|
|
|
42
|
-
1.
|
|
55
|
+
1. Run Configuration command to set the initial configuration required by all commands to operate
|
|
56
|
+
```shell script
|
|
57
|
+
config
|
|
58
|
+
Enter the key/name that will serve to identify the dotCMS instance (must be unique) [local].
|
|
59
|
+
The name is [local]
|
|
60
|
+
Enter the dotCMS base URL (must be a valid URL starting protocol http or https) [http://localhost:8080]
|
|
61
|
+
The URL is [http://localhost:8080]
|
|
62
|
+
Are these values OK? (Enter to confirm or N to cancel) (Y/n)
|
|
63
|
+
...
|
|
64
|
+
Do you want to continue adding another dotCMS instance? (Y/n)n
|
|
65
|
+
0. Profile [local], Uri [http://localhost:8080], active [no].
|
|
66
|
+
1. Profile [local#1], Uri [https://demo.dotcms.com], active [no].
|
|
67
|
+
One of these profiles needs to be made the current active one. Please select the number of the profile you want to activate. 1
|
|
68
|
+
```
|
|
69
|
+
2. Log in with an admin user
|
|
43
70
|
```shell script
|
|
44
71
|
login --user=admin@dotCMS.com --password
|
|
45
72
|
```
|
|
@@ -181,39 +208,35 @@ Example:
|
|
|
181
208
|
../mvnw quarkus:dev -Dquarkus.log.file.path=/Users/my-user/CLI/dotcms-cli.log
|
|
182
209
|
```
|
|
183
210
|
|
|
184
|
-
##
|
|
211
|
+
## Configuration
|
|
185
212
|
|
|
186
213
|
The CLI can be used to manage multiple dotCMS instances. Each instance profile is defined in the `~/.dotcms/dot-service.yml` file.
|
|
187
|
-
Whatever profile is active will be used by the CLI to execute the commands
|
|
214
|
+
Whatever profile is active will be used by the CLI to execute the commands on
|
|
188
215
|
The selected profile can be obtained by running the `status` command.
|
|
189
216
|
Here's an example of the default `dot-service.yml` file shipped with the CLI:
|
|
190
217
|
|
|
191
218
|
```yaml
|
|
192
219
|
- name: "default"
|
|
220
|
+
url: "http://localhost:8080"
|
|
193
221
|
credentials:
|
|
194
222
|
user: "admin@dotcms.com"
|
|
195
223
|
- name: "demo"
|
|
224
|
+
url: "https://demo.dotcms.com"
|
|
196
225
|
active: true
|
|
197
226
|
credentials:
|
|
198
227
|
user: "admin@dotCMS.com"
|
|
199
228
|
```
|
|
200
229
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
dotcms.client.servers.default=http://localhost:8080/api
|
|
206
|
-
dotcms.client.servers.demo=https://demo.dotcms.com/api
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
Notice how the `dotcms.client.servers` property has a suffix matching the profile name in the `dot-service.yml` file.
|
|
230
|
+
Therefore, in order to add a new instance profile, you need to add a new entry in the `dot-service.yml` as it is shown on the example above.
|
|
231
|
+
The `active` attribute indicates which profile is currently active. The CLI will use the active profile to execute the commands.
|
|
232
|
+
If more than one profile is marked active, this will result in an InvalidStateException.
|
|
233
|
+
The `credentials` section is optional. If the credentials are not provided, the CLI will prompt the user to enter them when the `login` command is executed.
|
|
210
234
|
|
|
211
|
-
|
|
212
|
-
Application properties can be extended via system properties, environment variables, `.env` file or in `$PWD/config/application.properties` file.
|
|
235
|
+
If the `dot-service.yml` file does not exist, the CLI will prompt to create one No commands can operate without having a valid configuration in place.
|
|
213
236
|
|
|
214
|
-
|
|
237
|
+
The CLI provides a `config` command to set the initial configuration required by all commands to operate. The command will guide you through the process of adding a new instance profile to the `dot-service.yml` file. and setting the active profile.
|
|
238
|
+
See the [Configuration](cli/docs/config.adoc) section for more details. And the [Examples](#examples) section for a practical example.
|
|
215
239
|
|
|
216
|
-
In future versions this process will be facilitated by the CLI itself.
|
|
217
240
|
|
|
218
241
|
### Workspace
|
|
219
242
|
|
|
@@ -222,6 +245,7 @@ The workspace is basically a set of directories and files used to house and orga
|
|
|
222
245
|
Additionally, a marker file called `.dot-workspace.yml` indicates to the CLI that the current directory is a valid workspace.
|
|
223
246
|
In the following table you can see the different directories and files that conform a workspace.
|
|
224
247
|
|
|
248
|
+
|
|
225
249
|
| File/Directory | Type | Description |
|
|
226
250
|
|----------------------|------|-------------------------|
|
|
227
251
|
| `content-types/` | Dir | Content-Types directory |
|
|
@@ -241,7 +265,7 @@ In order to incorporate the CLI into your GitHub Actions workflow, you need to:
|
|
|
241
265
|
- In Your repository General Settings, enable the following permissions:
|
|
242
266
|
- Workflow Permissions : Read and Write permissions
|
|
243
267
|
- In Your repository General Settings, Secrets and variables, Actions
|
|
244
|
-
- Create a new variable called `DOT_API_URL` and set the value to a valid dotCMS URL. e.g. `https://demo.dotcms.com
|
|
268
|
+
- Create a new variable called `DOT_API_URL` and set the value to a valid dotCMS URL. e.g. `https://demo.dotcms.com`
|
|
245
269
|

|
|
246
270
|
- Create a new secret called `DOT_TOKEN` and set the value to a valid dotCMS CLI token.
|
|
247
271
|

|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
package/src/postinstall.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
// Dependencies
|
|
3
4
|
const path = require('path');
|
|
4
5
|
const fs = require('fs').promises;
|
|
5
6
|
const os = require('os');
|
|
6
7
|
|
|
8
|
+
// Architecture and platform mappings
|
|
7
9
|
const ARCHITECTURE_MAPPING = {
|
|
8
10
|
"x64": "x86_64",
|
|
9
11
|
"arm64": "aarch_64"
|
|
@@ -14,26 +16,35 @@ const PLATFORM_MAPPING = {
|
|
|
14
16
|
"linux": "linux"
|
|
15
17
|
};
|
|
16
18
|
|
|
19
|
+
const EXTENSION_MAP = {
|
|
20
|
+
"win32": ".exe",
|
|
21
|
+
"default": ""
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// Utility functions
|
|
17
25
|
function getGlobalBinPath() {
|
|
18
26
|
const npmGlobalPrefix = process.env.PREFIX || process.env.npm_config_prefix || process.env.HOME;
|
|
19
27
|
return path.join(npmGlobalPrefix, 'bin');
|
|
20
28
|
}
|
|
21
29
|
|
|
22
30
|
function validatePackageConfig(packageJson) {
|
|
31
|
+
// Validation of package.json configuration
|
|
23
32
|
if (!packageJson.version || !packageJson.packageName || !packageJson.alias || !packageJson.binaries || typeof packageJson.binaries !== "object") {
|
|
24
33
|
throw new Error("Invalid package.json. 'version', 'packageName', 'alias' and 'binaries' must be specified.");
|
|
25
34
|
}
|
|
26
35
|
}
|
|
27
36
|
|
|
37
|
+
// Read and parse package.json
|
|
28
38
|
async function parsePackageJson() {
|
|
29
|
-
|
|
30
39
|
console.log("Installing CLI");
|
|
40
|
+
|
|
31
41
|
const platform = os.platform();
|
|
32
42
|
const architecture = os.arch();
|
|
33
43
|
|
|
34
44
|
console.log("Platform: " + platform);
|
|
35
45
|
console.log("Architecture: " + architecture);
|
|
36
46
|
|
|
47
|
+
// Check installation support for platform and architecture
|
|
37
48
|
if (!(os.arch() in ARCHITECTURE_MAPPING) || !(os.platform() in PLATFORM_MAPPING)) {
|
|
38
49
|
throw new Error(`Installation is not supported for this ${platform}/${architecture} combination.`);
|
|
39
50
|
}
|
|
@@ -48,7 +59,7 @@ async function parsePackageJson() {
|
|
|
48
59
|
const packageName = packageJson.packageName;
|
|
49
60
|
const alias = packageJson.alias;
|
|
50
61
|
const binaries = packageJson.binaries;
|
|
51
|
-
const extension = platform
|
|
62
|
+
const extension = EXTENSION_MAP[platform] || EXTENSION_MAP.default;
|
|
52
63
|
const binaryKey = `${packageName}-${platform}-${architecture}`;
|
|
53
64
|
const binaryPath = binaries[binaryKey];
|
|
54
65
|
|
|
@@ -69,76 +80,86 @@ async function parsePackageJson() {
|
|
|
69
80
|
}
|
|
70
81
|
}
|
|
71
82
|
|
|
83
|
+
// Create symlink for the binary
|
|
84
|
+
async function createSymlink(globalBinPath, config) {
|
|
85
|
+
try {
|
|
86
|
+
console.info(`Creating symlink for the relevant binary for your platform ${os.platform()}-${os.arch()}`);
|
|
72
87
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
88
|
+
const currentDir = __dirname;
|
|
89
|
+
const targetDir = path.join(currentDir, '..');
|
|
90
|
+
const binarySource = path.join(targetDir, config.binaryPath);
|
|
91
|
+
const binaryDestination = config.alias;
|
|
92
|
+
const fullSymlinkPath = path.join(globalBinPath, binaryDestination);
|
|
76
93
|
|
|
77
|
-
|
|
78
|
-
try {
|
|
79
|
-
await fs.access(symlinkPath, fs.constants.F_OK);
|
|
80
|
-
// If the symlink exists, remove it.
|
|
81
|
-
await fs.unlink(symlinkPath);
|
|
82
|
-
console.log(`Existing symlink ${symlinkPath} found and removed.`);
|
|
83
|
-
} catch (error) {
|
|
84
|
-
// The symlink does not exist, continue.
|
|
85
|
-
}
|
|
94
|
+
await fs.symlink(binarySource, fullSymlinkPath);
|
|
86
95
|
|
|
87
|
-
|
|
88
|
-
// Create a junction for the binary for Windows.
|
|
89
|
-
// await fs.symlink(binarySource, symlinkPath, "junction");
|
|
90
|
-
} else {
|
|
91
|
-
// Create a symlink for the binary for macOS and Linux.
|
|
92
|
-
await fs.symlink(binarySource, symlinkPath);
|
|
93
|
-
}
|
|
94
|
-
console.info(`Created symlink ${symlinkPath} pointing to ${binarySource}`);
|
|
96
|
+
console.info(`Created symlink ${fullSymlinkPath} pointing to ${binarySource}`);
|
|
95
97
|
} catch (error) {
|
|
96
98
|
console.error("Error while creating symlink:", error);
|
|
97
99
|
throw new Error("Failed to create symlink.");
|
|
98
100
|
}
|
|
99
101
|
}
|
|
100
102
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
+
// Remove symlink if exists
|
|
104
|
+
async function removeSymlinkIfExists(globalBinPath, config) {
|
|
105
|
+
try {
|
|
106
|
+
console.info("Global bin path location:", globalBinPath);
|
|
103
107
|
|
|
104
|
-
|
|
105
|
-
config
|
|
106
|
-
|
|
108
|
+
const files = await fs.readdir(globalBinPath);
|
|
109
|
+
const symlinkFileName = config.alias + config.extension;
|
|
110
|
+
const symlinkPath = files.find(file => file === symlinkFileName);
|
|
107
111
|
|
|
108
|
-
|
|
112
|
+
if (!symlinkPath) {
|
|
113
|
+
console.warn(`Symlink '${symlinkFileName}' not found in the global bin directory.`);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
109
116
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
117
|
+
const fullSymlinkPath = path.join(globalBinPath, symlinkPath);
|
|
118
|
+
await fs.unlink(fullSymlinkPath);
|
|
119
|
+
console.info(`Removed symlink: ${fullSymlinkPath}`);
|
|
120
|
+
} catch (error) {
|
|
121
|
+
console.warn("Error while removing symlink:", error);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
114
124
|
|
|
115
|
-
|
|
125
|
+
// Install CLI
|
|
126
|
+
async function installCli() {
|
|
127
|
+
const config = await parsePackageJson();
|
|
128
|
+
const globalBinPath = getGlobalBinPath();
|
|
116
129
|
|
|
117
|
-
|
|
130
|
+
try{
|
|
131
|
+
await removeSymlinkIfExists(globalBinPath, config);
|
|
132
|
+
await createSymlink(globalBinPath, config);
|
|
133
|
+
} catch (ex) {
|
|
134
|
+
console.error("Error while installing:", ex);
|
|
135
|
+
throw new Error(`Failed to install ${config.alias}.`);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
console.info(`${config.alias} installed successfully.`);
|
|
118
139
|
}
|
|
119
140
|
|
|
141
|
+
// Uninstall CLI
|
|
120
142
|
async function uninstallCli() {
|
|
121
143
|
const config = await parsePackageJson();
|
|
144
|
+
const globalBinPath = getGlobalBinPath();
|
|
122
145
|
|
|
123
146
|
try {
|
|
124
|
-
|
|
125
|
-
const symlinkPath = path.join(globalBinPath, config.alias + config.extension);
|
|
126
|
-
|
|
127
|
-
console.info("Removing symlink:", symlinkPath);
|
|
128
|
-
|
|
129
|
-
await fs.unlink(symlinkPath);
|
|
147
|
+
await removeSymlinkIfExists(globalBinPath, config);
|
|
130
148
|
} catch (ex) {
|
|
131
149
|
console.error("Error while uninstalling:", ex);
|
|
150
|
+
throw new Error(`Failed to uninstall ${config.alias}.`);
|
|
132
151
|
}
|
|
133
152
|
|
|
134
|
-
console.info(
|
|
153
|
+
console.info(`${config.alias} uninstalled successfully.`);
|
|
135
154
|
}
|
|
136
155
|
|
|
156
|
+
// Available actions
|
|
137
157
|
const actions = {
|
|
138
158
|
"install": installCli,
|
|
139
159
|
"uninstall": uninstallCli
|
|
140
160
|
};
|
|
141
161
|
|
|
162
|
+
// Execute action based on provided command
|
|
142
163
|
const [cmd] = process.argv.slice(2);
|
|
143
164
|
if (cmd && actions[cmd]) {
|
|
144
165
|
actions[cmd]().then(
|
|
@@ -151,4 +172,4 @@ if (cmd && actions[cmd]) {
|
|
|
151
172
|
} else {
|
|
152
173
|
console.log("Invalid command. `install` and `uninstall` are the only supported commands");
|
|
153
174
|
process.exit(1);
|
|
154
|
-
}
|
|
175
|
+
}
|