@magnolia/cli-jumpstart-plugin 1.0.0-preview.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 +63 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/jumpstart-plugin.d.ts +23 -0
- package/dist/jumpstart-plugin.js +217 -0
- package/dist/lib/config-helper.d.ts +3 -0
- package/dist/lib/config-helper.js +221 -0
- package/dist/lib/download.d.ts +4 -0
- package/dist/lib/download.js +119 -0
- package/dist/lib/extract.d.ts +4 -0
- package/dist/lib/extract.js +54 -0
- package/dist/lib/helper.d.ts +10 -0
- package/dist/lib/helper.js +154 -0
- package/dist/lib/install.d.ts +2 -0
- package/dist/lib/install.js +29 -0
- package/dist/lib/pj-helper.d.ts +3 -0
- package/dist/lib/pj-helper.js +91 -0
- package/dist/package.json +51 -0
- package/dist/types/types.d.ts +69 -0
- package/dist/types/types.js +7 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# CLI Jumpstart Plugin
|
|
2
|
+
|
|
3
|
+
**NOTE:** *This version of the Jumpstart plugin is still under development. The README will be updated continuosly as we refine the plugin.*
|
|
4
|
+
|
|
5
|
+
The Jumpstart Plugin is a part of the Magnolia CLI's plugin system. This plugin is designed to facilitate the process of starting new projects using predefined templates and bundles. It allows users to choose a template and download associated bundles while performing necessary tasks such as authentication, bundle downloading, extraction, and post-command execution.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
The Jumpstart plugin is by default installed in the MGNL plugin-system and ready to be used.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
The Jumpstart Plugin enhances the Magnolia CLI by providing a streamlined way to start new projects using predefined templates and bundles. Users can select templates, which are collections of bundles, and have the plugin handle the download, extraction, and execution of post-commands.
|
|
13
|
+
|
|
14
|
+
**Jumpstart command:**
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
magnolia-cli jumpstart
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
This command initiates the **jumpstart** plugin.
|
|
21
|
+
When run, the plugin will prompt the user to select a template. It will then proceed to download and extract the required bundles, executing post-commands if specified, install required plugins, initialize package.json project and create mgnl.config.js.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+

|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### **command-line options**
|
|
28
|
+
|
|
29
|
+
You can customize the **jumpstart** plugin's actions using these command-line options:
|
|
30
|
+
- `-t, --template <name>`: Choose template.
|
|
31
|
+
- `-p, --projectTemplatesPath <path>`: Specify from where the projectTemplates should be loaded.
|
|
32
|
+
|
|
33
|
+
**Template option:**
|
|
34
|
+
With this option, you can specify which template to use:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
magnolia-cli jumpstart --template "headless/minimal-headless-spa-demos/dx-core/latest"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
**Project templates list:**
|
|
42
|
+
|
|
43
|
+
The **jumpstart** plugin relies on a list of predefined project templates stored in an external [repository](https://git.magnolia-cms.com/projects/SERVICES/repos/cli-project-templates/raw/projectTemplates.json).
|
|
44
|
+
You can specify your own project templates list with the *--project-templates-path* command:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
magnolia-cli jumpstart -p "<project-templates-path>"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Light-modules folder:**
|
|
51
|
+
|
|
52
|
+
The Jumpstart Plugin initiates a recursive search throughout the project's directory structure for an existing `light-modules` directory. Upon detection, the plugin avoids creating a new one, instead utilizing the existing directory to maintain the pre-configured modules. On the other hand, if a `light-modules` directory is not found, the system will generate one.
|
|
53
|
+
|
|
54
|
+
**magnolia.properties file:**
|
|
55
|
+
|
|
56
|
+
The Jumpstart Plugin automatically applies specific modifications to the 'magnolia.properties' files of magnoliaAuthor and magnoliaPublic webapps.
|
|
57
|
+
|
|
58
|
+
Following properties are modified:
|
|
59
|
+
- 'magnolia.resources.dir' is adjusted to reference the `light-modules` directory.
|
|
60
|
+
- 'magnolia.update.auto' is set to true
|
|
61
|
+
|
|
62
|
+
## Conclusion
|
|
63
|
+
The Jumpstart Plugin demonstrates an effective way to streamline the process of setting up new projects by providing template-based automation for downloading, extracting, and handling bundles. With its intuitive command-line interface and detailed documentation, users can quickly get started with the Magnolia CLI's powerful plugin system.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './jumpstart-plugin.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './jumpstart-plugin.js';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { PluginTemplate } from '@magnolia/cli-plugin-template';
|
|
2
|
+
import { Option } from 'commander';
|
|
3
|
+
import { PluginOptions, Template, Bundle, TemplateWithoutChildren } from "./types/types.js";
|
|
4
|
+
import { Logger } from "winston";
|
|
5
|
+
export declare let logger: Logger;
|
|
6
|
+
export default class JumpstartPlugin extends PluginTemplate {
|
|
7
|
+
name: string;
|
|
8
|
+
version: any;
|
|
9
|
+
description: any;
|
|
10
|
+
projectTemplates?: Array<Template>;
|
|
11
|
+
options: Option[];
|
|
12
|
+
constructor();
|
|
13
|
+
executePostCommands(bundle: Bundle, file: string): Promise<void>;
|
|
14
|
+
handleTemplate(template: TemplateWithoutChildren): Promise<void>;
|
|
15
|
+
setProjectTemplates(options: PluginOptions): Promise<void>;
|
|
16
|
+
promptTemplateSelection(templates: Array<Template>): Promise<TemplateWithoutChildren | undefined>;
|
|
17
|
+
findTemplateByIdentifier(identifier: string): TemplateWithoutChildren | undefined;
|
|
18
|
+
chooseTemplate(options: PluginOptions): Promise<void>;
|
|
19
|
+
init(winstonLogger: Logger): Promise<void>;
|
|
20
|
+
start(options: PluginOptions): Promise<void>;
|
|
21
|
+
stop(): Promise<void>;
|
|
22
|
+
help(): Promise<void>;
|
|
23
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { PluginTemplate } from '@magnolia/cli-plugin-template';
|
|
11
|
+
import { Option } from 'commander';
|
|
12
|
+
import { createRequire } from 'module';
|
|
13
|
+
const requireFn = createRequire(import.meta.url);
|
|
14
|
+
const pkg = requireFn('./package.json');
|
|
15
|
+
import inquirer from 'inquirer';
|
|
16
|
+
import axios from "axios";
|
|
17
|
+
import { extract } from "./lib/extract.js";
|
|
18
|
+
import { downloadBundle } from "./lib/download.js";
|
|
19
|
+
import { PostCommands } from "./types/types.js";
|
|
20
|
+
import { installDependencies } from "./lib/install.js";
|
|
21
|
+
import path from "path";
|
|
22
|
+
import { handleLightModulesFolder, initializeNodeProject, installAdditionalPlugins } from "./lib/helper.js";
|
|
23
|
+
export let logger;
|
|
24
|
+
export default class JumpstartPlugin extends PluginTemplate {
|
|
25
|
+
constructor() {
|
|
26
|
+
super();
|
|
27
|
+
this.name = "jumpstart";
|
|
28
|
+
this.version = pkg.version;
|
|
29
|
+
this.description = pkg.description;
|
|
30
|
+
this.options = [
|
|
31
|
+
new Option('-t, --template <name>', 'Choose template'),
|
|
32
|
+
new Option('-p, --project-templates-path <path>', 'Specify from where the projectTemplates should be loaded')
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
executePostCommands(bundle, file) {
|
|
36
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
37
|
+
if (!bundle.postCommand)
|
|
38
|
+
return;
|
|
39
|
+
for (const command of bundle.postCommand) {
|
|
40
|
+
switch (command) {
|
|
41
|
+
case PostCommands.Extract:
|
|
42
|
+
case PostCommands.ExtractAndOverride:
|
|
43
|
+
yield extract(bundle, file, command);
|
|
44
|
+
break;
|
|
45
|
+
case PostCommands.NpmInstall:
|
|
46
|
+
case PostCommands.YarnInstall:
|
|
47
|
+
yield installDependencies(bundle, command);
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
handleTemplate(template) {
|
|
54
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
55
|
+
let templateCredentials;
|
|
56
|
+
if (template.auth) {
|
|
57
|
+
console.log("Please enter credentials for ", template.name);
|
|
58
|
+
templateCredentials = yield inquirer
|
|
59
|
+
.prompt([
|
|
60
|
+
{
|
|
61
|
+
type: 'input',
|
|
62
|
+
name: 'username',
|
|
63
|
+
message: 'Username'
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
type: 'password',
|
|
67
|
+
name: 'password',
|
|
68
|
+
message: 'Password'
|
|
69
|
+
}
|
|
70
|
+
]);
|
|
71
|
+
}
|
|
72
|
+
for (const bundle of template.bundles || []) {
|
|
73
|
+
let credentials = null;
|
|
74
|
+
let file;
|
|
75
|
+
try {
|
|
76
|
+
if (bundle.auth === "inherit") {
|
|
77
|
+
file = yield downloadBundle(bundle, templateCredentials, undefined);
|
|
78
|
+
}
|
|
79
|
+
else if (bundle.auth) {
|
|
80
|
+
console.log("Please enter credentials for ", bundle.name ? bundle.name : bundle.url);
|
|
81
|
+
credentials = yield inquirer
|
|
82
|
+
.prompt([
|
|
83
|
+
{
|
|
84
|
+
type: 'input',
|
|
85
|
+
name: 'username',
|
|
86
|
+
message: 'Username'
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
type: 'password',
|
|
90
|
+
name: 'password',
|
|
91
|
+
message: 'Password'
|
|
92
|
+
}
|
|
93
|
+
]);
|
|
94
|
+
file = yield downloadBundle(bundle, credentials, undefined);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
file = yield downloadBundle(bundle, null, undefined);
|
|
98
|
+
}
|
|
99
|
+
if (file) {
|
|
100
|
+
yield this.executePostCommands(bundle, file);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch (e) {
|
|
104
|
+
logger.error(e.message);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
yield handleLightModulesFolder();
|
|
108
|
+
yield initializeNodeProject();
|
|
109
|
+
if (template.plugins) {
|
|
110
|
+
yield installAdditionalPlugins(template.plugins);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
setProjectTemplates(options) {
|
|
115
|
+
var _a;
|
|
116
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
117
|
+
try {
|
|
118
|
+
if ((_a = options.projectTemplatesPath) === null || _a === void 0 ? void 0 : _a.startsWith("http", 0)) {
|
|
119
|
+
const res = yield axios.get(options.projectTemplatesPath);
|
|
120
|
+
this.projectTemplates = res.data.projectTemplates;
|
|
121
|
+
}
|
|
122
|
+
else if (options.projectTemplatesPath) {
|
|
123
|
+
this.projectTemplates = requireFn(path.join(process.cwd(), options.projectTemplatesPath)).projectTemplates;
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
const res = yield axios.get("https://git.magnolia-cms.com/rest/api/latest/projects/SERVICES/repos/cli-project-templates/raw/projectTemplates.json");
|
|
127
|
+
this.projectTemplates = res.data.projectTemplates;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch (e) {
|
|
131
|
+
logger.error(e.message);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
promptTemplateSelection(templates) {
|
|
136
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
137
|
+
if (!templates || !templates.length) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const choices = templates.map(template => {
|
|
141
|
+
return {
|
|
142
|
+
name: template.name,
|
|
143
|
+
value: template
|
|
144
|
+
};
|
|
145
|
+
});
|
|
146
|
+
const { template } = yield inquirer.prompt([
|
|
147
|
+
{
|
|
148
|
+
type: 'rawlist',
|
|
149
|
+
name: 'template',
|
|
150
|
+
message: 'Please choose a template?',
|
|
151
|
+
choices: choices
|
|
152
|
+
}
|
|
153
|
+
]);
|
|
154
|
+
if (template.children && template.children.length) {
|
|
155
|
+
return this.promptTemplateSelection(template.children);
|
|
156
|
+
}
|
|
157
|
+
if (template.bundles || template.plugins) {
|
|
158
|
+
return template;
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
findTemplateByIdentifier(identifier) {
|
|
163
|
+
if (!this.projectTemplates)
|
|
164
|
+
return;
|
|
165
|
+
let currentTemplates = this.projectTemplates;
|
|
166
|
+
for (const segment of identifier.split('/')) {
|
|
167
|
+
const foundTemplate = currentTemplates.find((template) => template.name === segment);
|
|
168
|
+
if (!foundTemplate)
|
|
169
|
+
return;
|
|
170
|
+
if (foundTemplate.bundles || foundTemplate.plugins)
|
|
171
|
+
return foundTemplate;
|
|
172
|
+
currentTemplates = foundTemplate.children;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
chooseTemplate(options) {
|
|
176
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
177
|
+
if (!this.projectTemplates)
|
|
178
|
+
return;
|
|
179
|
+
if (typeof options.template === 'string') {
|
|
180
|
+
const template = this.findTemplateByIdentifier(options.template);
|
|
181
|
+
if (template) {
|
|
182
|
+
yield this.handleTemplate(template);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
logger.info(`The '${options.template}' template was not found.`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
const template = yield this.promptTemplateSelection(this.projectTemplates);
|
|
190
|
+
if (template) {
|
|
191
|
+
yield this.handleTemplate(template);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
init(winstonLogger) {
|
|
196
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
197
|
+
logger = winstonLogger;
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
start(options) {
|
|
201
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
202
|
+
logger === null || logger === void 0 ? void 0 : logger.info(`'JumpstartPlugin' plugin started succesfully.`);
|
|
203
|
+
yield this.setProjectTemplates(options);
|
|
204
|
+
yield this.chooseTemplate(options);
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
stop() {
|
|
208
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
209
|
+
console.log("Plugin stopped");
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
help() {
|
|
213
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
214
|
+
console.log("Plugin help");
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import fs from "fs-extra";
|
|
11
|
+
import parser from "@babel/parser";
|
|
12
|
+
import t from "@babel/types";
|
|
13
|
+
import beautifyModule from "js-beautify";
|
|
14
|
+
import path from "path";
|
|
15
|
+
import { determinePackageManager, extractRepoName, installPackage, isValidURL } from "./helper.js";
|
|
16
|
+
import ora from "ora";
|
|
17
|
+
import { logger } from "../jumpstart-plugin.js";
|
|
18
|
+
const { js_beautify } = beautifyModule;
|
|
19
|
+
const BEAUTIFY_OPTIONS = {
|
|
20
|
+
indent_size: 2,
|
|
21
|
+
end_with_newline: true,
|
|
22
|
+
max_preserve_newlines: 2,
|
|
23
|
+
keep_array_indentation: false,
|
|
24
|
+
preserve_newlines: true
|
|
25
|
+
};
|
|
26
|
+
const getLocalConfigPath = () => path.join(process.cwd(), 'mgnl.config.js');
|
|
27
|
+
const getPackageConfigPath = () => path.join(process.cwd(), 'node_modules/@magnolia/cli/mgnl.config.js');
|
|
28
|
+
export const handleMGNLConfigFile = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
29
|
+
let isMgnlCliInstalled = true;
|
|
30
|
+
if (!fs.existsSync(getPackageConfigPath())) {
|
|
31
|
+
isMgnlCliInstalled = yield installPackage(determinePackageManager(), "@magnolia/cli@preview");
|
|
32
|
+
logger === null || logger === void 0 ? void 0 : logger.warn("Couldn't install @magnolia/cli");
|
|
33
|
+
}
|
|
34
|
+
if (isMgnlCliInstalled && fs.existsSync(getLocalConfigPath())) {
|
|
35
|
+
handleExistingConfigFile();
|
|
36
|
+
}
|
|
37
|
+
else if (isMgnlCliInstalled && !fs.existsSync(getLocalConfigPath())) {
|
|
38
|
+
createMgnlConfigFile();
|
|
39
|
+
}
|
|
40
|
+
else if (!isMgnlCliInstalled && !fs.existsSync(getLocalConfigPath())) {
|
|
41
|
+
createSimpleMgnlConfigFile();
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
// the mgnl.config.js exist, do not do anything
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
export const installAndConfigPlugins = (plugins) => __awaiter(void 0, void 0, void 0, function* () {
|
|
48
|
+
const localConfig = parseConfigFile(getLocalConfigPath());
|
|
49
|
+
if (!localConfig)
|
|
50
|
+
return;
|
|
51
|
+
const missingPlugins = findMissingPlugins(plugins, localConfig);
|
|
52
|
+
if (missingPlugins.length === 0)
|
|
53
|
+
return;
|
|
54
|
+
logger === null || logger === void 0 ? void 0 : logger.info(`Will attempt to install missing plugins`);
|
|
55
|
+
const installedPlugins = yield installPlugins(missingPlugins);
|
|
56
|
+
const pluginsConfig = createCustomConfigForPlugins(installedPlugins);
|
|
57
|
+
updateLocalConfig(pluginsConfig, localConfig);
|
|
58
|
+
});
|
|
59
|
+
const handleExistingConfigFile = () => {
|
|
60
|
+
const localConfigContent = fs.readFileSync(getLocalConfigPath(), "utf8");
|
|
61
|
+
const packageConfigContent = fs.readFileSync(getPackageConfigPath(), "utf8");
|
|
62
|
+
const localLoggerConfig = extractLoggerConfig(localConfigContent);
|
|
63
|
+
const globalLoggerConfig = extractLoggerConfig(packageConfigContent);
|
|
64
|
+
if (!localLoggerConfig && (globalLoggerConfig && globalLoggerConfig[1])) {
|
|
65
|
+
const loggerContent = getLoggerContent(globalLoggerConfig[1]);
|
|
66
|
+
const newLocalConfigContent = localConfigContent.replace(/(export default \{)/, `$1${loggerContent}`);
|
|
67
|
+
writeConfigContent(newLocalConfigContent);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
function createMgnlConfigFile() {
|
|
71
|
+
const packageConfigContent = fs.readFileSync(getPackageConfigPath(), "utf8");
|
|
72
|
+
const loggerConfig = extractLoggerConfig(packageConfigContent);
|
|
73
|
+
const mgnlConfigPrefix = `
|
|
74
|
+
export default {`;
|
|
75
|
+
const logger = loggerConfig && loggerConfig[1]
|
|
76
|
+
? getLoggerContent(loggerConfig[1])
|
|
77
|
+
: '';
|
|
78
|
+
const mgnlConfigSufix = `
|
|
79
|
+
// Here you can add plugins you want to use with MGNL CLI
|
|
80
|
+
commands: []
|
|
81
|
+
};`;
|
|
82
|
+
const mgnlConfigContent = mgnlConfigPrefix + logger + mgnlConfigSufix;
|
|
83
|
+
writeConfigContent(mgnlConfigContent);
|
|
84
|
+
}
|
|
85
|
+
function createSimpleMgnlConfigFile() {
|
|
86
|
+
const mgnlConfigContent = `
|
|
87
|
+
export default {
|
|
88
|
+
// Here you can add plugins you want to use with MGNL CLI
|
|
89
|
+
commands: []
|
|
90
|
+
};`;
|
|
91
|
+
writeConfigContent(mgnlConfigContent);
|
|
92
|
+
}
|
|
93
|
+
function getLoggerContent(logger) {
|
|
94
|
+
return `
|
|
95
|
+
// Logger configuration
|
|
96
|
+
// see: https://github.com/winstonjs/winston#logging for logging levels explanation
|
|
97
|
+
${logger},`;
|
|
98
|
+
}
|
|
99
|
+
const extractLoggerConfig = (content) => {
|
|
100
|
+
const loggerRegex = /(logger\s*:\s*{[^}]*})/s;
|
|
101
|
+
return loggerRegex.exec(content);
|
|
102
|
+
};
|
|
103
|
+
const findMissingPlugins = (plugins, config) => {
|
|
104
|
+
return plugins.filter(plugin => {
|
|
105
|
+
let packageName = plugin.name;
|
|
106
|
+
return !config.imports.some(customImport => customImport.importedNames === packageName);
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
const installPlugins = (plugins) => __awaiter(void 0, void 0, void 0, function* () {
|
|
110
|
+
const packageManager = determinePackageManager();
|
|
111
|
+
let installedPlugins = [];
|
|
112
|
+
for (const plugin of plugins) {
|
|
113
|
+
const installed = yield installPackage(packageManager, plugin.installReference, plugin.name);
|
|
114
|
+
if (installed)
|
|
115
|
+
installedPlugins.push(plugin);
|
|
116
|
+
}
|
|
117
|
+
return installedPlugins;
|
|
118
|
+
});
|
|
119
|
+
const createCustomConfigForPlugins = (plugins) => {
|
|
120
|
+
const defaultConfig = { configContent: "", imports: [], commands: [] };
|
|
121
|
+
plugins.forEach(plugin => {
|
|
122
|
+
let importSource;
|
|
123
|
+
if (isValidURL(plugin.installReference)) {
|
|
124
|
+
importSource = extractRepoName(plugin.installReference);
|
|
125
|
+
}
|
|
126
|
+
if (!importSource) {
|
|
127
|
+
importSource = plugin.installReference;
|
|
128
|
+
}
|
|
129
|
+
defaultConfig.imports.push({ importedNames: plugin.name, importSource: importSource });
|
|
130
|
+
defaultConfig.commands.push({ commandName: plugin.name });
|
|
131
|
+
});
|
|
132
|
+
return defaultConfig;
|
|
133
|
+
};
|
|
134
|
+
const parseConfigFile = (configPath) => {
|
|
135
|
+
let configContent;
|
|
136
|
+
try {
|
|
137
|
+
configContent = fs.readFileSync(configPath, 'utf-8');
|
|
138
|
+
}
|
|
139
|
+
catch (e) {
|
|
140
|
+
logger === null || logger === void 0 ? void 0 : logger.error(`Couldn't read ${configPath}`);
|
|
141
|
+
console.error(e);
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
let parsedConfig;
|
|
145
|
+
try {
|
|
146
|
+
parsedConfig = parser.parse(configContent, { sourceType: 'module' });
|
|
147
|
+
}
|
|
148
|
+
catch (e) {
|
|
149
|
+
logger === null || logger === void 0 ? void 0 : logger.error(`Couldn't parse ${configPath}, please check the file for issues`);
|
|
150
|
+
console.error(e);
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
if (!parsedConfig)
|
|
154
|
+
return null;
|
|
155
|
+
const { imports, commands } = extractImportsAndCommands(parsedConfig);
|
|
156
|
+
return { configContent, imports, commands };
|
|
157
|
+
};
|
|
158
|
+
const extractImportsAndCommands = (ast) => {
|
|
159
|
+
const imports = [];
|
|
160
|
+
const commands = [];
|
|
161
|
+
ast.program.body.forEach(node => {
|
|
162
|
+
if (t.isImportDeclaration(node)) {
|
|
163
|
+
imports.push({
|
|
164
|
+
importedNames: node.specifiers.map(specifier => specifier.local.name).join(', '),
|
|
165
|
+
importSource: node.source.value
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
if (t.isExportDefaultDeclaration(node) && t.isObjectExpression(node.declaration)) {
|
|
169
|
+
node.declaration.properties.forEach(property => {
|
|
170
|
+
if (t.isObjectProperty(property) && t.isArrayExpression(property.value)) {
|
|
171
|
+
property.value.elements.forEach(element => {
|
|
172
|
+
if (t.isNewExpression(element) && t.isIdentifier(element.callee)) {
|
|
173
|
+
commands.push({ commandName: element.callee.name });
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
return { imports, commands };
|
|
181
|
+
};
|
|
182
|
+
const updateLocalConfig = (defaultConfig, localConfig) => {
|
|
183
|
+
const getMissingItems = (defaultItems, customItems, comparator) => {
|
|
184
|
+
return defaultItems.filter(defaultItem => !customItems.some(customItem => comparator(defaultItem, customItem)));
|
|
185
|
+
};
|
|
186
|
+
const mergeImports = (customImports, missingImports) => {
|
|
187
|
+
return customImports.concat(missingImports)
|
|
188
|
+
.map(i => `import ${i.importedNames} from "${i.importSource}";`).join('\n');
|
|
189
|
+
};
|
|
190
|
+
const missingImports = getMissingItems(defaultConfig.imports, localConfig.imports, (a, b) => a.importSource === b.importSource);
|
|
191
|
+
const missingCommands = getMissingItems(defaultConfig.commands, localConfig.commands, (a, b) => a.commandName === b.commandName);
|
|
192
|
+
const mergedImports = mergeImports(localConfig.imports, missingImports);
|
|
193
|
+
const updatedConfigContent = mergeCommandsWithConfigContent(localConfig.configContent, missingCommands);
|
|
194
|
+
writeToLocalConfigFile(mergedImports, updatedConfigContent);
|
|
195
|
+
};
|
|
196
|
+
const mergeCommandsWithConfigContent = (configContent, missingCommands) => {
|
|
197
|
+
const missingCommandsStr = missingCommands.map(c => `new ${c.commandName}()`).join(',\n');
|
|
198
|
+
const commandsPattern = /(commands\s*:\s*\[)([^\]]*?)(,\s*)?(\])/;
|
|
199
|
+
return configContent.replace(commandsPattern, (match, p1, p2, p3, p4) => {
|
|
200
|
+
const separator = (p2.trim() !== "" && missingCommandsStr.trim() !== "") ? "," : "";
|
|
201
|
+
return `${p1}${p2}${separator}${missingCommandsStr}${p4}`;
|
|
202
|
+
});
|
|
203
|
+
};
|
|
204
|
+
const writeToLocalConfigFile = (mergedImports, updatedConfigContent) => {
|
|
205
|
+
const importPattern = /import .* from ['"].*['"];\s*/g;
|
|
206
|
+
const configContentWithImports = `${mergedImports}\n\n${updatedConfigContent.replace(importPattern, '')}`;
|
|
207
|
+
writeConfigContent(configContentWithImports);
|
|
208
|
+
};
|
|
209
|
+
const writeConfigContent = (content) => {
|
|
210
|
+
const spinner = ora().start(`Updating mgnl.config.js`);
|
|
211
|
+
try {
|
|
212
|
+
fs.writeFileSync(getLocalConfigPath(), js_beautify(content.trim(), BEAUTIFY_OPTIONS), 'utf-8');
|
|
213
|
+
}
|
|
214
|
+
catch (e) {
|
|
215
|
+
spinner.stop();
|
|
216
|
+
logger === null || logger === void 0 ? void 0 : logger.error('Error occured while updating mgnl.config.js');
|
|
217
|
+
console.error(e);
|
|
218
|
+
}
|
|
219
|
+
spinner.stop();
|
|
220
|
+
logger === null || logger === void 0 ? void 0 : logger.info('mgnl.config.js updated');
|
|
221
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Bundle, Credentials } from "../types/types.js";
|
|
2
|
+
export declare const downloadBundle: (bundle: Bundle, credentials: Credentials, dest: string | undefined) => Promise<string>;
|
|
3
|
+
export declare const getDownloadUrl: (bundle: Bundle, credentials: Credentials) => Promise<string>;
|
|
4
|
+
export declare const selectTag: (url: string, credentials: Credentials) => Promise<string>;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import path from "path";
|
|
11
|
+
import fs from "fs-extra";
|
|
12
|
+
import axios from "axios";
|
|
13
|
+
import ProgressBar from "progress";
|
|
14
|
+
import inquirer from "inquirer";
|
|
15
|
+
import { logger } from "../jumpstart-plugin.js";
|
|
16
|
+
export const downloadBundle = (bundle, credentials, dest) => __awaiter(void 0, void 0, void 0, function* () {
|
|
17
|
+
try {
|
|
18
|
+
let url = bundle.url;
|
|
19
|
+
const downloadDest = dest ? dest : "./download-" + new Date().getTime();
|
|
20
|
+
let downloadUrl;
|
|
21
|
+
if (path.parse(url).name === "tags") {
|
|
22
|
+
downloadUrl = yield selectTag(url, credentials);
|
|
23
|
+
}
|
|
24
|
+
else if (url.includes('https://nexus.magnolia-cms.com/service/rest/v1/search')) {
|
|
25
|
+
downloadUrl = yield getDownloadUrl(bundle, credentials);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
downloadUrl = url;
|
|
29
|
+
}
|
|
30
|
+
const opts = {
|
|
31
|
+
method: 'get',
|
|
32
|
+
responseType: 'stream',
|
|
33
|
+
};
|
|
34
|
+
if (credentials) {
|
|
35
|
+
opts.auth = credentials;
|
|
36
|
+
}
|
|
37
|
+
if (downloadDest) {
|
|
38
|
+
yield fs.ensureDir(downloadDest);
|
|
39
|
+
}
|
|
40
|
+
const tempDownload = path.join(downloadDest, bundle.name ? bundle.name : 'temp-' + new Date().getTime());
|
|
41
|
+
const target = fs.createWriteStream(tempDownload);
|
|
42
|
+
logger === null || logger === void 0 ? void 0 : logger.info("Starting download from: " + downloadUrl);
|
|
43
|
+
const res = yield axios.get(downloadUrl, opts);
|
|
44
|
+
if (res.headers['content-length']) {
|
|
45
|
+
const len = parseInt(res.headers['content-length'], 10);
|
|
46
|
+
const bar = new ProgressBar('Downloading [:bar] :percent :etas', {
|
|
47
|
+
complete: '=',
|
|
48
|
+
incomplete: ' ',
|
|
49
|
+
width: 20,
|
|
50
|
+
total: len
|
|
51
|
+
});
|
|
52
|
+
res.data.on('data', (chunk) => {
|
|
53
|
+
bar.tick(chunk.length);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
res.data.pipe(target);
|
|
57
|
+
res.data.on('error', (error) => {
|
|
58
|
+
throw new Error(error);
|
|
59
|
+
});
|
|
60
|
+
return new Promise((resolve) => {
|
|
61
|
+
res.data.on('end', () => {
|
|
62
|
+
logger === null || logger === void 0 ? void 0 : logger.info("Download finished");
|
|
63
|
+
resolve(path.join('.', tempDownload));
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
throw new Error(error);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
export const getDownloadUrl = (bundle, credentials) => __awaiter(void 0, void 0, void 0, function* () {
|
|
72
|
+
const opts = {
|
|
73
|
+
method: 'get',
|
|
74
|
+
responseType: 'json',
|
|
75
|
+
headers: {
|
|
76
|
+
Accept: 'application/json'
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
if (credentials && credentials.username && credentials.password) {
|
|
80
|
+
opts.auth = credentials;
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const response = yield axios.get(bundle.url + '&prerelease=false', opts);
|
|
84
|
+
const params = new URLSearchParams(bundle.url.split("?")[1]);
|
|
85
|
+
let downloadUrl = response.data.items[0].downloadUrl;
|
|
86
|
+
downloadUrl = downloadUrl === null || downloadUrl === void 0 ? void 0 : downloadUrl.split('/magnolia.');
|
|
87
|
+
downloadUrl = downloadUrl && `${downloadUrl[0]}/${params.get('repository')}/${response.data.items[0].path}`;
|
|
88
|
+
return downloadUrl;
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
throw new Error(error);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
export const selectTag = (url, credentials) => __awaiter(void 0, void 0, void 0, function* () {
|
|
95
|
+
var _a;
|
|
96
|
+
const opts = {
|
|
97
|
+
method: 'get',
|
|
98
|
+
headers: {
|
|
99
|
+
Accept: 'application/json'
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
if (credentials && credentials.username && credentials.password) {
|
|
103
|
+
opts.auth = credentials;
|
|
104
|
+
}
|
|
105
|
+
const res = yield axios.get(url, opts);
|
|
106
|
+
if (!((_a = res.data) === null || _a === void 0 ? void 0 : _a.values) || res.data.values.length <= 0) {
|
|
107
|
+
throw new Error("There are no available tags");
|
|
108
|
+
}
|
|
109
|
+
const { tag } = yield inquirer
|
|
110
|
+
.prompt([
|
|
111
|
+
{
|
|
112
|
+
type: 'rawlist',
|
|
113
|
+
name: 'tag',
|
|
114
|
+
message: 'Please select a tag',
|
|
115
|
+
choices: res.data.values.map((tag) => ({ name: tag.displayId, value: "archive?at=" + tag.id }))
|
|
116
|
+
}
|
|
117
|
+
]);
|
|
118
|
+
return url.slice(0, url.length - 4) + tag;
|
|
119
|
+
});
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Bundle } from "../types/types.js";
|
|
2
|
+
export declare const extract: (bundle: Bundle, file: string, command: string) => Promise<void>;
|
|
3
|
+
export declare const extractApacheTomcat: (dest: string, unzipFolder: string) => Promise<void>;
|
|
4
|
+
export declare const findExtractedApacheTomcatDir: (p: string) => Promise<unknown>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import decompress from "decompress";
|
|
11
|
+
import path from "path";
|
|
12
|
+
import walk from "walk";
|
|
13
|
+
import fs from "fs-extra";
|
|
14
|
+
import { PostCommands } from "../types/types.js";
|
|
15
|
+
import url from "url";
|
|
16
|
+
import { logger } from "../jumpstart-plugin.js";
|
|
17
|
+
export const extract = (bundle, file, command) => __awaiter(void 0, void 0, void 0, function* () {
|
|
18
|
+
var _a;
|
|
19
|
+
logger === null || logger === void 0 ? void 0 : logger.info('Extracting...');
|
|
20
|
+
const { dest = "./", type } = bundle;
|
|
21
|
+
const unzipFolder = "temp-" + new Date().getTime();
|
|
22
|
+
yield decompress(file, unzipFolder);
|
|
23
|
+
if (command === PostCommands.ExtractAndOverride) {
|
|
24
|
+
fs.rmSync(dest, { recursive: true, force: true });
|
|
25
|
+
}
|
|
26
|
+
const artifactId = (_a = url.parse(bundle.url, true)) === null || _a === void 0 ? void 0 : _a.query['maven.artifactId'];
|
|
27
|
+
if (artifactId === 'magnolia-tomcat-barebone') {
|
|
28
|
+
yield extractApacheTomcat(dest, unzipFolder);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
fs.copySync(unzipFolder, dest, { overwrite: true });
|
|
32
|
+
}
|
|
33
|
+
fs.rmSync(unzipFolder, { recursive: true, force: true });
|
|
34
|
+
fs.rmSync(path.dirname(file), { recursive: true, force: true });
|
|
35
|
+
});
|
|
36
|
+
export const extractApacheTomcat = (dest, unzipFolder) => __awaiter(void 0, void 0, void 0, function* () {
|
|
37
|
+
const apacheTomcatDir = yield findExtractedApacheTomcatDir(unzipFolder);
|
|
38
|
+
fs.rmSync(path.join(apacheTomcatDir, 'webapps', 'magnoliaAuthor'), { recursive: true, force: true });
|
|
39
|
+
fs.copySync(apacheTomcatDir, path.join(dest, "apache-tomcat"), { overwrite: false });
|
|
40
|
+
});
|
|
41
|
+
export const findExtractedApacheTomcatDir = (p) => {
|
|
42
|
+
return new Promise((resolve, reject) => {
|
|
43
|
+
const walker = walk.walk(p, { followLinks: false });
|
|
44
|
+
walker.on('directory', (root, { name }, next) => {
|
|
45
|
+
if (name.match(/(apache-tomcat).*/)) {
|
|
46
|
+
resolve(path.join(root, name));
|
|
47
|
+
}
|
|
48
|
+
next();
|
|
49
|
+
});
|
|
50
|
+
walker.on('end', function () {
|
|
51
|
+
return reject(new Error("apache-tomcat was not found."));
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { PluginRequirement } from "../types/types.js";
|
|
2
|
+
export declare const handleLightModulesFolder: () => Promise<void>;
|
|
3
|
+
export declare const findLightModulesFolder: (p: string) => Promise<unknown>;
|
|
4
|
+
export declare const findWebAppsList: (apacheTomcatPath: string) => string[];
|
|
5
|
+
export declare const installAdditionalPlugins: (plugins: Array<PluginRequirement>) => Promise<void>;
|
|
6
|
+
export declare const initializeNodeProject: () => Promise<void>;
|
|
7
|
+
export declare const installPackage: (packageManager: string, packageReference: string, packageName?: string) => Promise<boolean>;
|
|
8
|
+
export declare const isValidURL: (str: string) => boolean;
|
|
9
|
+
export declare const extractRepoName: (gitUrl: string) => string | null;
|
|
10
|
+
export declare const determinePackageManager: (baseDirectory?: string) => "yarn" | "npm";
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { handleMGNLConfigFile, installAndConfigPlugins } from "./config-helper.js";
|
|
11
|
+
import { handlePackageJSON } from "./pj-helper.js";
|
|
12
|
+
import ora from "ora";
|
|
13
|
+
import { execa } from "execa";
|
|
14
|
+
import path from "path";
|
|
15
|
+
import fs from "fs-extra";
|
|
16
|
+
import { findExtractedApacheTomcatDir } from "./extract.js";
|
|
17
|
+
import walk from "walk";
|
|
18
|
+
import { logger } from "../jumpstart-plugin.js";
|
|
19
|
+
export const handleLightModulesFolder = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
20
|
+
let lightModulesPath;
|
|
21
|
+
try {
|
|
22
|
+
lightModulesPath = (yield findLightModulesFolder(process.cwd()));
|
|
23
|
+
logger === null || logger === void 0 ? void 0 : logger.info(`Found existing light-modules path at '${lightModulesPath}'`);
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
logger === null || logger === void 0 ? void 0 : logger.info(`No light-modules folder found. Attempting to create one.`);
|
|
27
|
+
lightModulesPath = path.join(process.cwd(), 'light-modules');
|
|
28
|
+
try {
|
|
29
|
+
fs.mkdirSync(lightModulesPath, { recursive: true });
|
|
30
|
+
logger === null || logger === void 0 ? void 0 : logger.info(`'light-modules' folder created at '${lightModulesPath}'.`);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
logger === null || logger === void 0 ? void 0 : logger.error(`Failed to create 'light-modules' folder: ${error instanceof Error ? error.message : ""}`);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const apacheTomcatPath = yield findExtractedApacheTomcatDir(process.cwd());
|
|
38
|
+
const webApps = findWebAppsList(apacheTomcatPath);
|
|
39
|
+
for (const webApp of webApps) {
|
|
40
|
+
const lightModulesPathToMagnoliaHomeRelPath = process.platform === 'win32' ? path.relative(webApp, lightModulesPath).replace(/\\/g, '/') : path.relative(webApp, lightModulesPath);
|
|
41
|
+
const props = {
|
|
42
|
+
'magnolia.resources.dir': '${magnolia.home}/' + lightModulesPathToMagnoliaHomeRelPath,
|
|
43
|
+
'magnolia.update.auto': "true"
|
|
44
|
+
};
|
|
45
|
+
if (webApp.endsWith("magnoliaAuthor")) {
|
|
46
|
+
props['magnolia.develop'] = "true";
|
|
47
|
+
}
|
|
48
|
+
const webAppPropertiesFilePath = path.join(webApp, 'WEB-INF', 'config', 'default', 'magnolia.properties');
|
|
49
|
+
editProperties(webAppPropertiesFilePath, props);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
const editProperties = (filePath, props) => {
|
|
53
|
+
if (!fs.existsSync(filePath)) {
|
|
54
|
+
logger === null || logger === void 0 ? void 0 : logger.warn(`File ${filePath} doesn't exists, skipping configuration.`);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const propertiesFileContent = fs.readFileSync(filePath, 'utf-8');
|
|
58
|
+
const replacedContent = replaceInConfig(propertiesFileContent, props);
|
|
59
|
+
try {
|
|
60
|
+
fs.writeFileSync(filePath, replacedContent);
|
|
61
|
+
Object.keys(props).forEach((key) => {
|
|
62
|
+
logger === null || logger === void 0 ? void 0 : logger.info(`Setting ${key} to: ${props[key]} in ${filePath}`);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
logger === null || logger === void 0 ? void 0 : logger.error(`An error occurred while updating 'magnolia.properties': ${error instanceof Error ? error.message : ""}`);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const replaceInConfig = (config, props) => {
|
|
70
|
+
Object.keys(props).forEach((key) => {
|
|
71
|
+
const regex = '(' + key.replace(/\./g, '\\.') + ')(\s*=\s*)(.+)'; // eslint-disable-line no-useless-escape
|
|
72
|
+
const replacement = '$1$2' + props[key];
|
|
73
|
+
config = config.replace(new RegExp(regex), replacement);
|
|
74
|
+
});
|
|
75
|
+
return config;
|
|
76
|
+
};
|
|
77
|
+
export const findLightModulesFolder = (p) => {
|
|
78
|
+
return new Promise((resolve, reject) => {
|
|
79
|
+
const walker = walk.walk(p, { followLinks: false });
|
|
80
|
+
walker.on('directory', (root, { name }, next) => {
|
|
81
|
+
if (name.match(/(light-modules)/)) {
|
|
82
|
+
resolve(path.join(root, name));
|
|
83
|
+
}
|
|
84
|
+
next();
|
|
85
|
+
});
|
|
86
|
+
walker.on('end', function () {
|
|
87
|
+
return reject(new Error("light-modules was not found."));
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
export const findWebAppsList = (apacheTomcatPath) => {
|
|
92
|
+
let webApps = [];
|
|
93
|
+
const webAppsFolder = path.join(apacheTomcatPath, 'webapps');
|
|
94
|
+
const files = fs.readdirSync(webAppsFolder);
|
|
95
|
+
for (const file of files) {
|
|
96
|
+
const filePath = path.join(webAppsFolder, file);
|
|
97
|
+
if (fs.statSync(filePath).isDirectory()) {
|
|
98
|
+
webApps.push(filePath);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return webApps;
|
|
102
|
+
};
|
|
103
|
+
export const installAdditionalPlugins = (plugins) => __awaiter(void 0, void 0, void 0, function* () {
|
|
104
|
+
yield installAndConfigPlugins(plugins);
|
|
105
|
+
});
|
|
106
|
+
export const initializeNodeProject = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
107
|
+
yield handlePackageJSON();
|
|
108
|
+
yield handleMGNLConfigFile();
|
|
109
|
+
});
|
|
110
|
+
export const installPackage = (packageManager, packageReference, packageName) => __awaiter(void 0, void 0, void 0, function* () {
|
|
111
|
+
if (!packageName) {
|
|
112
|
+
packageName = packageReference;
|
|
113
|
+
}
|
|
114
|
+
const spinner = ora().start(`Installing ${packageName}`);
|
|
115
|
+
try {
|
|
116
|
+
yield execa(packageManager, [packageManager === 'npm' ? 'install' : 'add', packageReference], {
|
|
117
|
+
buffer: true,
|
|
118
|
+
cwd: process.cwd()
|
|
119
|
+
});
|
|
120
|
+
spinner.stop();
|
|
121
|
+
logger === null || logger === void 0 ? void 0 : logger.info(`${packageName} installed`);
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
spinner.stop();
|
|
126
|
+
logger === null || logger === void 0 ? void 0 : logger.error(`Failed to install ${packageName}`);
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
export const isValidURL = (str) => {
|
|
131
|
+
try {
|
|
132
|
+
new URL(str);
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
catch (_) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
export const extractRepoName = (gitUrl) => {
|
|
140
|
+
const match = gitUrl.match(/\/([^/]+?)(?:\.git)?$/);
|
|
141
|
+
return match ? match[1] : null;
|
|
142
|
+
};
|
|
143
|
+
export const determinePackageManager = (baseDirectory = process.cwd()) => {
|
|
144
|
+
const yarnLockPath = path.join(baseDirectory, 'yarn.lock');
|
|
145
|
+
const packageLockPath = path.join(baseDirectory, 'package-lock.json');
|
|
146
|
+
if (fs.existsSync(yarnLockPath)) {
|
|
147
|
+
return 'yarn';
|
|
148
|
+
}
|
|
149
|
+
else if (fs.existsSync(packageLockPath)) {
|
|
150
|
+
return 'npm';
|
|
151
|
+
}
|
|
152
|
+
// Default to npm
|
|
153
|
+
return 'npm';
|
|
154
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { PostCommands } from "../types/types.js";
|
|
11
|
+
import path from "path";
|
|
12
|
+
import { execa } from "execa";
|
|
13
|
+
import ora from 'ora';
|
|
14
|
+
import { logger } from "../jumpstart-plugin.js";
|
|
15
|
+
export const installDependencies = (bundle, command) => __awaiter(void 0, void 0, void 0, function* () {
|
|
16
|
+
const spinner = ora('Installing dependencies').start();
|
|
17
|
+
try {
|
|
18
|
+
yield execa(command === PostCommands.YarnInstall ? 'yarn' : 'npm', ['install'], {
|
|
19
|
+
buffer: true,
|
|
20
|
+
cwd: path.join(process.cwd(), bundle.dest ? bundle.dest : "./")
|
|
21
|
+
});
|
|
22
|
+
spinner.stop();
|
|
23
|
+
logger === null || logger === void 0 ? void 0 : logger.info('Dependencies installed');
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
spinner.stop();
|
|
27
|
+
logger === null || logger === void 0 ? void 0 : logger.error('Failed to install dependencies');
|
|
28
|
+
}
|
|
29
|
+
});
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import path from "path";
|
|
11
|
+
import ora from "ora";
|
|
12
|
+
import fs from "fs-extra";
|
|
13
|
+
import { execa } from "execa";
|
|
14
|
+
import { determinePackageManager, installPackage } from "./helper.js";
|
|
15
|
+
import { logger } from "../jumpstart-plugin.js";
|
|
16
|
+
export const handlePackageJSON = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
17
|
+
const pjPath = path.join(process.cwd(), 'package.json');
|
|
18
|
+
if (!fs.existsSync(pjPath)) {
|
|
19
|
+
yield initPackageJSON();
|
|
20
|
+
}
|
|
21
|
+
yield modifyPackageJSON(pjPath);
|
|
22
|
+
});
|
|
23
|
+
export const modifyPackageJSON = (pjPath) => __awaiter(void 0, void 0, void 0, function* () {
|
|
24
|
+
let pj = JSON.parse(fs.readFileSync(pjPath, 'utf8'));
|
|
25
|
+
let isMgnlCliInstalled = (pj === null || pj === void 0 ? void 0 : pj.dependencies) && (pj === null || pj === void 0 ? void 0 : pj.dependencies['@magnolia/cli']);
|
|
26
|
+
if (!isMgnlCliInstalled) {
|
|
27
|
+
isMgnlCliInstalled = yield installPackage(determinePackageManager(), "@magnolia/cli@preview", "mgnl-cli");
|
|
28
|
+
if (isMgnlCliInstalled) {
|
|
29
|
+
pj = JSON.parse(fs.readFileSync(pjPath, 'utf8'));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const nodeModulesPath = path.join(process.cwd(), "node_modules");
|
|
33
|
+
if (!fs.existsSync(nodeModulesPath)) {
|
|
34
|
+
const npmISpinner = ora().start("Didn't find 'node_modules' folder. Running 'npm install'");
|
|
35
|
+
try {
|
|
36
|
+
yield execa(determinePackageManager(), ["install"], {
|
|
37
|
+
buffer: true,
|
|
38
|
+
cwd: process.cwd()
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
catch (e) {
|
|
42
|
+
npmISpinner.stop();
|
|
43
|
+
logger === null || logger === void 0 ? void 0 : logger.error("'npm install' has failed");
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
npmISpinner.stop();
|
|
47
|
+
logger === null || logger === void 0 ? void 0 : logger.info("Running 'npm install' done");
|
|
48
|
+
}
|
|
49
|
+
if (isMgnlCliInstalled) {
|
|
50
|
+
const mgnlScript = { "mgnl": "node node_modules/@magnolia/cli" };
|
|
51
|
+
const scriptKey = Object.keys(mgnlScript)[0];
|
|
52
|
+
if (!pj.scripts) {
|
|
53
|
+
pj.scripts = {};
|
|
54
|
+
}
|
|
55
|
+
if (!pj.scripts[scriptKey] || pj.scripts[scriptKey] !== mgnlScript[scriptKey]) {
|
|
56
|
+
logger === null || logger === void 0 ? void 0 : logger.info('Add "mgnl" script to package.json');
|
|
57
|
+
pj.scripts[scriptKey] = mgnlScript[scriptKey];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (!pj.type) {
|
|
61
|
+
pj.type = "module";
|
|
62
|
+
}
|
|
63
|
+
else if (pj.type !== "module") {
|
|
64
|
+
logger === null || logger === void 0 ? void 0 : logger.warn(`Changing 'type' to "module"`);
|
|
65
|
+
pj.type = "module";
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
fs.writeFileSync(pjPath, JSON.stringify(pj, null, '\t'), 'utf8');
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
logger === null || logger === void 0 ? void 0 : logger.error('Failed to modify package.json');
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
export const initPackageJSON = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
76
|
+
const pjSpinner = ora().start('Creating package.json');
|
|
77
|
+
try {
|
|
78
|
+
yield execa(determinePackageManager(), ['init', '-y'], {
|
|
79
|
+
buffer: true,
|
|
80
|
+
cwd: process.cwd()
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
catch (e) {
|
|
84
|
+
pjSpinner.stop();
|
|
85
|
+
logger === null || logger === void 0 ? void 0 : logger.info('Failed to create package.json');
|
|
86
|
+
console.error(e);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
pjSpinner.stop();
|
|
90
|
+
logger === null || logger === void 0 ? void 0 : logger.info('package.json created');
|
|
91
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@magnolia/cli-jumpstart-plugin",
|
|
3
|
+
"version": "1.0.0-preview.1",
|
|
4
|
+
"description": "Plugin to set up new projects using predefined templates and bundles. Easily select and configure project templates, and let the plugin handle bundle downloads, extraction, and post-command execution.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
|
8
|
+
"build": "standard && tsc && cpy package.json dist",
|
|
9
|
+
"standard": "npx standard"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [],
|
|
12
|
+
"author": "",
|
|
13
|
+
"license": "ISC",
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@jest/globals": "^29.6.3",
|
|
16
|
+
"@types/decompress": "^4.2.4",
|
|
17
|
+
"@types/fs-extra": "^11.0.1",
|
|
18
|
+
"@types/inquirer": "^9.0.3",
|
|
19
|
+
"@types/js-beautify": "^1.14.0",
|
|
20
|
+
"@types/node": "^20.3.3",
|
|
21
|
+
"@types/progress": "^2.0.5",
|
|
22
|
+
"@types/walk": "^2.3.1",
|
|
23
|
+
"@types/yauzl": "^2.10.1",
|
|
24
|
+
"cpy-cli": "^5.0.0",
|
|
25
|
+
"jest": "^29.6.2",
|
|
26
|
+
"standard": "^17.1.0",
|
|
27
|
+
"typescript": "^5.1.6"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@magnolia/cli-plugin-template": "^1.1.0",
|
|
31
|
+
"axios": "^1.4.0",
|
|
32
|
+
"chalk": "^5.3.0",
|
|
33
|
+
"commander": "^11.0.0",
|
|
34
|
+
"decompress": "^4.2.1",
|
|
35
|
+
"dotenv": "^16.3.1",
|
|
36
|
+
"execa": "^7.2.0",
|
|
37
|
+
"fs-extra": "^11.1.1",
|
|
38
|
+
"inquirer": "^9.2.8",
|
|
39
|
+
"js-beautify": "^1.14.9",
|
|
40
|
+
"ora": "^7.0.1",
|
|
41
|
+
"progress": "^2.0.3",
|
|
42
|
+
"walk": "^2.3.15",
|
|
43
|
+
"winston": "^3.10.0"
|
|
44
|
+
},
|
|
45
|
+
"type": "module",
|
|
46
|
+
"standard": {
|
|
47
|
+
"ignore": [
|
|
48
|
+
"tests/resources/config-helper/*/mgnl.config.js"
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export interface PluginOptions {
|
|
2
|
+
template: string | boolean;
|
|
3
|
+
projectTemplatesPath: string;
|
|
4
|
+
}
|
|
5
|
+
export interface Bundle {
|
|
6
|
+
url: string;
|
|
7
|
+
auth?: string | boolean;
|
|
8
|
+
postCommand: Array<string>;
|
|
9
|
+
type?: string;
|
|
10
|
+
dest?: string;
|
|
11
|
+
downloadDest?: string;
|
|
12
|
+
name?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface TemplateBase {
|
|
15
|
+
name: string;
|
|
16
|
+
auth?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface TemplateWithChildren extends TemplateBase {
|
|
19
|
+
children: Array<Template>;
|
|
20
|
+
bundles?: never;
|
|
21
|
+
plugins?: never;
|
|
22
|
+
}
|
|
23
|
+
export interface TemplateWithBundles extends TemplateBase {
|
|
24
|
+
bundles: Array<Bundle>;
|
|
25
|
+
children?: never;
|
|
26
|
+
plugins?: never;
|
|
27
|
+
}
|
|
28
|
+
export interface TemplateWithPlugins extends TemplateBase {
|
|
29
|
+
plugins: Array<PluginRequirement>;
|
|
30
|
+
bundles?: never;
|
|
31
|
+
children?: never;
|
|
32
|
+
}
|
|
33
|
+
export interface TemplateWithBundlesAndPlugins extends TemplateBase {
|
|
34
|
+
bundles: Array<Bundle>;
|
|
35
|
+
plugins: Array<PluginRequirement>;
|
|
36
|
+
children?: never;
|
|
37
|
+
}
|
|
38
|
+
export type TemplateWithoutChildren = TemplateWithBundles | TemplateWithPlugins | TemplateWithBundlesAndPlugins;
|
|
39
|
+
export type Template = TemplateWithChildren | TemplateWithoutChildren;
|
|
40
|
+
export interface PluginRequirement {
|
|
41
|
+
name: string;
|
|
42
|
+
installReference: string;
|
|
43
|
+
}
|
|
44
|
+
export type Credentials = {
|
|
45
|
+
username: string;
|
|
46
|
+
password: string;
|
|
47
|
+
} | null;
|
|
48
|
+
export declare enum PostCommands {
|
|
49
|
+
Extract = "extract",
|
|
50
|
+
ExtractAndOverride = "extract and override",
|
|
51
|
+
NpmInstall = "npm install",
|
|
52
|
+
YarnInstall = "yarn install"
|
|
53
|
+
}
|
|
54
|
+
export interface PluginRequirement {
|
|
55
|
+
name: string;
|
|
56
|
+
installReference: string;
|
|
57
|
+
}
|
|
58
|
+
export type ImportItem = {
|
|
59
|
+
importedNames: string;
|
|
60
|
+
importSource: string;
|
|
61
|
+
};
|
|
62
|
+
export interface CommandItem {
|
|
63
|
+
commandName: string;
|
|
64
|
+
}
|
|
65
|
+
export type ParsedConfigData = {
|
|
66
|
+
configContent: string;
|
|
67
|
+
imports: ImportItem[];
|
|
68
|
+
commands: CommandItem[];
|
|
69
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export var PostCommands;
|
|
2
|
+
(function (PostCommands) {
|
|
3
|
+
PostCommands["Extract"] = "extract";
|
|
4
|
+
PostCommands["ExtractAndOverride"] = "extract and override";
|
|
5
|
+
PostCommands["NpmInstall"] = "npm install";
|
|
6
|
+
PostCommands["YarnInstall"] = "yarn install";
|
|
7
|
+
})(PostCommands || (PostCommands = {}));
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@magnolia/cli-jumpstart-plugin",
|
|
3
|
+
"version": "1.0.0-preview.1",
|
|
4
|
+
"description": "Plugin to set up new projects using predefined templates and bundles. Easily select and configure project templates, and let the plugin handle bundle downloads, extraction, and post-command execution.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
|
8
|
+
"build": "standard && tsc && cpy package.json dist",
|
|
9
|
+
"standard": "npx standard"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [],
|
|
12
|
+
"author": "",
|
|
13
|
+
"license": "ISC",
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@jest/globals": "^29.6.3",
|
|
16
|
+
"@types/decompress": "^4.2.4",
|
|
17
|
+
"@types/fs-extra": "^11.0.1",
|
|
18
|
+
"@types/inquirer": "^9.0.3",
|
|
19
|
+
"@types/js-beautify": "^1.14.0",
|
|
20
|
+
"@types/node": "^20.3.3",
|
|
21
|
+
"@types/progress": "^2.0.5",
|
|
22
|
+
"@types/walk": "^2.3.1",
|
|
23
|
+
"@types/yauzl": "^2.10.1",
|
|
24
|
+
"cpy-cli": "^5.0.0",
|
|
25
|
+
"jest": "^29.6.2",
|
|
26
|
+
"standard": "^17.1.0",
|
|
27
|
+
"typescript": "^5.1.6"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@magnolia/cli-plugin-template": "^1.1.0",
|
|
31
|
+
"axios": "^1.4.0",
|
|
32
|
+
"chalk": "^5.3.0",
|
|
33
|
+
"commander": "^11.0.0",
|
|
34
|
+
"decompress": "^4.2.1",
|
|
35
|
+
"dotenv": "^16.3.1",
|
|
36
|
+
"execa": "^7.2.0",
|
|
37
|
+
"fs-extra": "^11.1.1",
|
|
38
|
+
"inquirer": "^9.2.8",
|
|
39
|
+
"js-beautify": "^1.14.9",
|
|
40
|
+
"ora": "^7.0.1",
|
|
41
|
+
"progress": "^2.0.3",
|
|
42
|
+
"walk": "^2.3.15",
|
|
43
|
+
"winston": "^3.10.0"
|
|
44
|
+
},
|
|
45
|
+
"type": "module",
|
|
46
|
+
"standard": {
|
|
47
|
+
"ignore": [
|
|
48
|
+
"tests/resources/config-helper/*/mgnl.config.js"
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
}
|