@magnolia/cli-jumpstart-plugin 1.0.0-preview.3 → 1.0.0-preview.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.txt ADDED
@@ -0,0 +1,27 @@
1
+ Copyright (c) 2024 Magnolia International Ltd.
2
+ (http://www.magnolia-cms.com). All rights reserved.
3
+
4
+
5
+ The software is dual-licensed under both the Magnolia
6
+ Network Agreement and the GNU General Public License.
7
+ You may elect to use one or the other of these licenses.
8
+
9
+ The software is distributed in the hope that it will be
10
+ useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
11
+ implied warranty of MERCHANTABILITY or FITNESS FOR A
12
+ PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
13
+ Redistribution, except as permitted by whichever of the GPL
14
+ or MNA you select, is prohibited.
15
+
16
+ 1. For the GPL license (GPL), you can redistribute and/or
17
+ modify this file under the terms of the GNU General
18
+ Public License, Version 3, as published by the Free Software
19
+ Foundation. You should have received a copy of the GNU
20
+ General Public License, Version 3 along with this program;
21
+ if not, write to the Free Software Foundation, Inc., 51
22
+ Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
23
+
24
+ 2. For the Magnolia Network Agreement (MNA), this file
25
+ and the accompanying materials are made available under the
26
+ terms of the MNA which accompanies this distribution, and
27
+ is available at http://www.magnolia-cms.com/mna.html
package/README.md CHANGED
@@ -27,14 +27,17 @@ When run, the plugin will prompt the user to select a template. It will then pro
27
27
  ### **command-line options**
28
28
 
29
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.
30
+ - `-t, --template <name>`, choose a template from available project templates
31
+ - `-p, --project-templates-path <path>`, specify the path to load project templates from
32
+ - `-m, --magnolia-version <version>`, set the Magnolia version; defaults to the latest stable version
33
+ - `-s, --snapshot`, download the latest snapshot version of the specified or latest stable webapp
32
34
 
33
35
  **Template option:**
36
+
34
37
  With this option, you can specify which template to use:
35
38
 
36
39
  ```bash
37
- magnolia-cli jumpstart --template "headless/minimal-headless-spa-demos/dx-core/latest"
40
+ magnolia-cli jumpstart --template "headless/minimal-headless-spa-demos/dx-core"
38
41
  ```
39
42
 
40
43
 
@@ -47,7 +50,94 @@ You can specify your own project templates list with the *--project-templates-pa
47
50
  magnolia-cli jumpstart -p "<project-templates-path>"
48
51
  ```
49
52
 
50
- **Light-modules folder:**
53
+
54
+ ## Extensions
55
+
56
+ The extensions functionality allows for greater flexibility and customizability during the setup process of a new Magnolia project.
57
+
58
+ ### Extension YAML Configuration
59
+
60
+ The plugin searches for extension YAML files in the following path within your project directory:
61
+ `<rootdir>/extensions/extension.yaml`
62
+
63
+ This YAML file defines additional prompts and post-command functions, which can be helpful for tailoring the plugin's functionality to specific project requirements.
64
+
65
+ ### Structure of the YAML File
66
+
67
+ An extension YAML file typically contains the following key sections:
68
+
69
+ - `extend`: Specifies a JavaScript file that the extension will tie into for additional logic or configuration.
70
+ - `prompts`: A series of input prompts to gather necessary information from the user. Each prompt can specify:
71
+ - `type`: The type of prompt, such as `input` for user text input.
72
+ - `name`: The internal name used to reference the collected data.
73
+ - `message`: The message displayed to the user during the prompt.
74
+ - `default`: The default value for the prompt, used if the user provides no input.
75
+ - `commands`: Defines actions to be taken after the prompts have been completed, such as:
76
+ - `post`: Commands to be executed after the setup process. This could involve downloading dependencies, setting up environment variables, etc.
77
+
78
+ ### Example
79
+
80
+ ```yaml
81
+ extend: ./example.js
82
+ prompts:
83
+ - type: input
84
+ name: clientId
85
+ message: Client ID
86
+ default: clientId_001
87
+
88
+ - type: input
89
+ name: organizationId
90
+ message: Organization Id
91
+ default: organizationId_001
92
+
93
+ - type: input
94
+ name: siteId
95
+ message: Site Id
96
+ default: siteId_001
97
+
98
+ commands:
99
+ post:
100
+ - function: example
101
+ retry: 3
102
+ delay: 1000
103
+ ```
104
+
105
+ ### Execution Flow
106
+
107
+ Upon project initialization, if an extension file is detected, the **Jumpstart** Plugin performs the following steps:
108
+
109
+ 1. **Input Gathering**: It prompts the user for input based on the `prompts` defined within the extension's YAML file.
110
+
111
+ 2. **Configuration Integration**: The plugin retrieves the main **package.json** file. The responses gathered from the prompts are then added to this configuration object under an `answers` property. This augmented **package.json** object is subsequently used to automatically populate the corresponding placeholders within your project files.
112
+
113
+ 3. **Post-Command Execution**: Each `post-command` function specified in the YAML file is executed. These functions have access to the `prompts` object, which contains the user's responses, allowing the functions to perform tasks that are tailored to the user's input.
114
+
115
+ ### Customization Example
116
+
117
+ After gathering inputs, a file containing placeholders like below:
118
+ ```js
119
+ // config.js
120
+
121
+ export default {
122
+ clientId: <%=answers.siteId%>,
123
+ organizationId: <%=answers.organizationId%>,
124
+ siteId: <%=answers.siteId%>
125
+ };
126
+ ```
127
+ will be transformed into:
128
+ ```js
129
+ // config.js
130
+
131
+ export default {
132
+ clientId: clientId_001,
133
+ organizationId: organizationId_001,
134
+ siteId: siteId_001
135
+ };
136
+ ```
137
+
138
+ By using the **Jumpstart** Plugin's extensions functionality, developers can create a more interactive and automated project setup process, making it easier to get started with a new Magnolia project.
139
+
140
+ ## Light-modules folder:
51
141
 
52
142
  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
143
 
@@ -1,23 +1,26 @@
1
1
  import { PluginTemplate } from '@magnolia/cli-plugin-template';
2
2
  import { Option } from 'commander';
3
- import { PluginOptions, Template, Bundle, TemplateWithoutChildren } from "./types/types.js";
3
+ import { PluginOptions, Template, Bundle, TemplateWithoutChildren, Credentials } from "./types/types.js";
4
4
  import { Logger } from "winston";
5
5
  export declare let logger: Logger;
6
+ export declare let i18nInstance: {
7
+ t(key: string, options?: any): string;
8
+ };
6
9
  export default class JumpstartPlugin extends PluginTemplate {
7
10
  name: string;
8
11
  version: any;
9
- description: any;
10
12
  projectTemplates?: Array<Template>;
11
13
  options: Option[];
14
+ credentials?: Credentials;
15
+ description: string;
12
16
  constructor();
13
17
  executePostCommands(bundle: Bundle, file: string): Promise<void>;
14
- handleTemplate(template: TemplateWithoutChildren): Promise<void>;
18
+ handleTemplate(template: TemplateWithoutChildren, options: PluginOptions): Promise<void>;
15
19
  setProjectTemplates(options: PluginOptions): Promise<void>;
16
- promptTemplateSelection(templates: Array<Template>): Promise<TemplateWithoutChildren | undefined>;
20
+ promptTemplateSelection(templates: Array<Template>, names?: string[]): Promise<TemplateWithoutChildren | undefined>;
17
21
  findTemplateByIdentifier(identifier: string): TemplateWithoutChildren | undefined;
18
22
  chooseTemplate(options: PluginOptions): Promise<void>;
19
23
  init(winstonLogger: Logger): Promise<void>;
20
24
  start(options: PluginOptions): Promise<void>;
21
25
  stop(): Promise<void>;
22
- help(): Promise<void>;
23
26
  }
@@ -19,17 +19,27 @@ import { downloadBundle } from "./lib/download.js";
19
19
  import { PostCommands } from "./types/types.js";
20
20
  import { installDependencies } from "./lib/install.js";
21
21
  import path from "path";
22
- import { handleLightModulesFolder, initializeNodeProject, installAdditionalPlugins } from "./lib/helper.js";
22
+ import { askForCredentials, handleLightModulesFolder, initI18n, initializeNodeProject } from "./lib/helper.js";
23
+ import { compileCustomPrompts, evaluateCustomPrompts } from "./lib/extensions.js";
24
+ import { addConfigProps } from "./lib/config-helper.js";
25
+ import { installAdditionalPlugins } from "./lib/config-helper.js";
26
+ const extensionsPath = path.resolve("./extensions/extension.yaml");
23
27
  export let logger;
28
+ export let i18nInstance = {
29
+ t(key, options) { return key; }
30
+ };
24
31
  export default class JumpstartPlugin extends PluginTemplate {
25
32
  constructor() {
26
33
  super();
27
34
  this.name = "jumpstart";
28
35
  this.version = pkg.version;
29
- this.description = pkg.description;
36
+ i18nInstance = initI18n(this.name);
37
+ this.description = i18nInstance.t('cmd-option-description');
30
38
  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')
39
+ new Option('-t, --template <name>', i18nInstance.t("cmd-option-template")),
40
+ new Option('-p, --project-templates-path <path>', i18nInstance.t("cmd-option-project-templates-path")),
41
+ new Option('-m, --magnolia-version <version>', i18nInstance.t('cmd-option-magnolia-version')),
42
+ new Option('-s, --snapshot', i18nInstance.t('cmd-option-snapshot'))
33
43
  ];
34
44
  }
35
45
  executePostCommands(bundle, file) {
@@ -40,6 +50,7 @@ export default class JumpstartPlugin extends PluginTemplate {
40
50
  switch (command) {
41
51
  case PostCommands.Extract:
42
52
  case PostCommands.ExtractAndOverride:
53
+ case PostCommands.ExtractAndUnfold:
43
54
  yield extract(bundle, file, command);
44
55
  break;
45
56
  case PostCommands.NpmInstall:
@@ -50,51 +61,26 @@ export default class JumpstartPlugin extends PluginTemplate {
50
61
  }
51
62
  });
52
63
  }
53
- handleTemplate(template) {
64
+ handleTemplate(template, options) {
54
65
  return __awaiter(this, void 0, void 0, function* () {
55
- let templateCredentials;
56
66
  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
- ]);
67
+ logger === null || logger === void 0 ? void 0 : logger.info(i18nInstance.t("prompt-enter-credentials", {
68
+ bundle: template.name
69
+ }));
70
+ this.credentials = yield askForCredentials();
71
71
  }
72
72
  for (const bundle of template.bundles || []) {
73
- let credentials = null;
74
73
  let file;
75
74
  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);
75
+ if (bundle.auth === true) {
76
+ logger === null || logger === void 0 ? void 0 : logger.info(i18nInstance.t('prompt-enter-credentials', {
77
+ bundle: bundle.name ? bundle.name : bundle.url
78
+ }));
79
+ const bundleCredentials = yield askForCredentials();
80
+ file = yield downloadBundle(bundle, bundleCredentials, undefined, options);
95
81
  }
96
82
  else {
97
- file = yield downloadBundle(bundle, null, undefined);
83
+ file = yield downloadBundle(bundle, this.credentials, undefined, options);
98
84
  }
99
85
  if (file) {
100
86
  yield this.executePostCommands(bundle, file);
@@ -109,21 +95,31 @@ export default class JumpstartPlugin extends PluginTemplate {
109
95
  if (template.plugins) {
110
96
  yield installAdditionalPlugins(template.plugins);
111
97
  }
98
+ if (template.configVars) {
99
+ yield addConfigProps(template.configVars);
100
+ }
101
+ const extensions = yield evaluateCustomPrompts(extensionsPath);
102
+ if (extensions === null || extensions === void 0 ? void 0 : extensions.answers) {
103
+ yield compileCustomPrompts(extensions === null || extensions === void 0 ? void 0 : extensions.answers);
104
+ }
105
+ if (extensions === null || extensions === void 0 ? void 0 : extensions.executePostCommands) {
106
+ yield extensions.executePostCommands(extensions === null || extensions === void 0 ? void 0 : extensions.answers);
107
+ }
112
108
  });
113
109
  }
114
110
  setProjectTemplates(options) {
115
- var _a;
116
111
  return __awaiter(this, void 0, void 0, function* () {
112
+ var _a;
117
113
  try {
118
114
  if ((_a = options.projectTemplatesPath) === null || _a === void 0 ? void 0 : _a.startsWith("http", 0)) {
119
115
  const res = yield axios.get(options.projectTemplatesPath);
120
116
  this.projectTemplates = res.data.projectTemplates;
121
117
  }
122
118
  else if (options.projectTemplatesPath) {
123
- this.projectTemplates = requireFn(path.join(process.cwd(), options.projectTemplatesPath)).projectTemplates;
119
+ this.projectTemplates = requireFn(path.resolve(options.projectTemplatesPath)).projectTemplates;
124
120
  }
125
121
  else {
126
- const res = yield axios.get("https://git.magnolia-cms.com/rest/api/latest/projects/SERVICES/repos/cli-project-templates/raw/projectTemplates.json");
122
+ const res = yield axios.get("https://bitbucket.org/magnolia-cms/project-templates/raw/HEAD/projectTemplates.json");
127
123
  this.projectTemplates = res.data.projectTemplates;
128
124
  }
129
125
  }
@@ -132,8 +128,8 @@ export default class JumpstartPlugin extends PluginTemplate {
132
128
  }
133
129
  });
134
130
  }
135
- promptTemplateSelection(templates) {
136
- return __awaiter(this, void 0, void 0, function* () {
131
+ promptTemplateSelection(templates_1) {
132
+ return __awaiter(this, arguments, void 0, function* (templates, names = []) {
137
133
  if (!templates || !templates.length) {
138
134
  return;
139
135
  }
@@ -151,11 +147,14 @@ export default class JumpstartPlugin extends PluginTemplate {
151
147
  choices: choices
152
148
  }
153
149
  ]);
150
+ if (template.name) {
151
+ names.push(template.name);
152
+ }
154
153
  if (template.children && template.children.length) {
155
- return this.promptTemplateSelection(template.children);
154
+ return this.promptTemplateSelection(template.children, names);
156
155
  }
157
156
  if (template.bundles || template.plugins) {
158
- return template;
157
+ return Object.assign(Object.assign({}, template), { name: names.join("/") });
159
158
  }
160
159
  });
161
160
  }
@@ -179,16 +178,18 @@ export default class JumpstartPlugin extends PluginTemplate {
179
178
  if (typeof options.template === 'string') {
180
179
  const template = this.findTemplateByIdentifier(options.template);
181
180
  if (template) {
182
- yield this.handleTemplate(template);
181
+ yield this.handleTemplate(template, options);
183
182
  return;
184
183
  }
185
184
  else {
186
- logger.info(`The '${options.template}' template was not found.`);
185
+ logger.info(i18nInstance.t("info-template_not_found", {
186
+ template: options.template
187
+ }));
187
188
  }
188
189
  }
189
190
  const template = yield this.promptTemplateSelection(this.projectTemplates);
190
191
  if (template) {
191
- yield this.handleTemplate(template);
192
+ yield this.handleTemplate(template, options);
192
193
  }
193
194
  });
194
195
  }
@@ -199,19 +200,14 @@ export default class JumpstartPlugin extends PluginTemplate {
199
200
  }
200
201
  start(options) {
201
202
  return __awaiter(this, void 0, void 0, function* () {
202
- logger === null || logger === void 0 ? void 0 : logger.info(`'JumpstartPlugin' plugin started succesfully.`);
203
+ logger === null || logger === void 0 ? void 0 : logger.info(i18nInstance.t("info-jumpstart_started"));
203
204
  yield this.setProjectTemplates(options);
204
205
  yield this.chooseTemplate(options);
205
206
  });
206
207
  }
207
208
  stop() {
208
209
  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");
210
+ logger === null || logger === void 0 ? void 0 : logger.info(i18nInstance.t("info-jumpstart_stopped"));
215
211
  });
216
212
  }
217
213
  }
@@ -1,3 +1,4 @@
1
- import { PluginRequirement } from "../types/types.js";
1
+ import { PluginRequirement } from "../types/types";
2
+ export declare const installAdditionalPlugins: (plugins: Array<PluginRequirement>) => Promise<void>;
2
3
  export declare const handleMGNLConfigFile: () => Promise<void>;
3
- export declare const installAndConfigPlugins: (plugins: Array<PluginRequirement>) => Promise<void>;
4
+ export declare const addConfigProps: (vars: any) => Promise<void>;