@scandipwa/magento-scripts 1.13.3 → 1.13.5-alpha.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.
@@ -9,9 +9,12 @@ const systeminformation = require('systeminformation');
9
9
  const { getCSAThemes } = require('../util/CSA-theme');
10
10
  const shouldUseYarn = require('@scandipwa/scandipwa-dev-utils/should-use-yarn');
11
11
  const ConsoleBlock = require('../util/console-block');
12
+ const { getInstanceMetadata } = require('../util/instance-metadata');
12
13
 
13
14
  const cmaGaTrackingId = 'UA-127741417-7';
14
15
 
16
+ googleAnalytics.setGaTrackingId(cmaGaTrackingId);
17
+
15
18
  /**
16
19
  * @param {import('yargs')} yargs
17
20
  */
@@ -64,6 +67,9 @@ module.exports = (yargs) => {
64
67
  default: false
65
68
  }),
66
69
  async (args = {}) => {
70
+ /**
71
+ * @type {Listr<import('../../typings/context').ListrContext>}
72
+ */
67
73
  const tasks = new Listr(
68
74
  start(), {
69
75
  exitOnError: true,
@@ -75,7 +81,7 @@ module.exports = (yargs) => {
75
81
  }
76
82
  }
77
83
  );
78
- const timeStamp = Date.now() / 1000;
84
+ const timeStamp = Date.now();
79
85
 
80
86
  if (args.debug) {
81
87
  logger.warn('You are running in debug mode. Magento setup will be slow.');
@@ -90,20 +96,27 @@ module.exports = (yargs) => {
90
96
  const ctx = await tasks.run();
91
97
 
92
98
  const {
93
- ports,
94
- config: { magentoConfiguration, overridenConfiguration: { host, ssl } },
95
99
  systemConfiguration: { analytics }
96
100
  } = ctx;
97
101
 
98
- const webLocation = `${ssl.enabled ? 'https' : 'http'}://${host}${ssl.enabled || ports.app === 80 ? '' : `:${ports.app}`}/`;
102
+ const instanceMetadata = getInstanceMetadata(ctx);
99
103
 
100
104
  const block = new ConsoleBlock();
101
105
  block
102
106
  .addHeader('Magento 2')
103
- .addEmptyLine()
104
- .addLine(`Web location: ${logger.style.link(webLocation)}`)
105
- .addLine(`Magento Admin panel location: ${logger.style.link(`${webLocation}${magentoConfiguration.adminuri}`)}`)
106
- .addLine(`Magento Admin panel credentials: ${logger.style.misc(magentoConfiguration.user)} - ${logger.style.misc(magentoConfiguration.password)}`);
107
+ .addEmptyLine();
108
+
109
+ block.addLine(logger.style.misc('Frontend'));
110
+ instanceMetadata.frontend.forEach(({ title, text }) => {
111
+ block.addLine(` ${title}: ${text}`);
112
+ });
113
+
114
+ block.addEmptyLine();
115
+
116
+ block.addLine(logger.style.misc('Admin'));
117
+ instanceMetadata.admin.forEach(({ title, text }) => {
118
+ block.addLine(` ${title}: ${text}`);
119
+ });
107
120
 
108
121
  const themes = await getCSAThemes();
109
122
  if (themes.length > 0) {
@@ -132,7 +145,10 @@ module.exports = (yargs) => {
132
145
 
133
146
  block.log();
134
147
 
135
- logger.note(`MySQL credentials, containers status and project information available in ${logger.style.code('npm run status')} command.`);
148
+ logger.note(
149
+ `MySQL credentials, containers status and project information available in ${logger.style.code('npm run status')} command.
150
+ To access Magento CLI, Composer and PHP for this project use ${logger.style.code('npm run cli')} command.`
151
+ );
136
152
  logger.log('');
137
153
 
138
154
  if (!analytics) {
@@ -140,10 +156,8 @@ module.exports = (yargs) => {
140
156
  }
141
157
 
142
158
  try {
143
- googleAnalytics.setGaTrackingId(cmaGaTrackingId);
144
-
145
159
  if (!process.isFirstStart) {
146
- await googleAnalytics.trackTiming('CMA start time', Date.now() / 1000 - timeStamp);
160
+ await googleAnalytics.trackTiming('CMA start time', Date.now() - timeStamp);
147
161
  googleAnalytics.printAboutAnalytics();
148
162
  process.exit(0);
149
163
  }
@@ -157,7 +171,7 @@ module.exports = (yargs) => {
157
171
  const paramInfo = `Platform: ${platform} ${kernel}, CPU model: ${manufacturer} ${brand}, RAM amount: ${totalRam}MB`;
158
172
 
159
173
  await googleAnalytics.trackEvent('Params', paramInfo, 0, 'OS');
160
- await googleAnalytics.trackTiming('CMA first start time', Date.now() / 1000 - timeStamp);
174
+ await googleAnalytics.trackTiming('CMA first start time', Date.now() - timeStamp);
161
175
  googleAnalytics.printAboutAnalytics();
162
176
  } catch (e) {
163
177
  await googleAnalytics.trackError(e.message || e);
@@ -15,7 +15,8 @@ const dependenciesForPlatforms = {
15
15
  'libxml2',
16
16
  'openssl@1.1'
17
17
  ],
18
- installCommand: (deps) => `brew install ${deps}`
18
+ installCommand: (deps) => `brew install ${deps}`,
19
+ packageManager: 'brew'
19
20
  },
20
21
  'Arch Linux': {
21
22
  dependencies: [
@@ -35,7 +36,8 @@ const dependenciesForPlatforms = {
35
36
  'perl',
36
37
  'libsodium'
37
38
  ],
38
- installCommand: (deps) => `sudo pacman -S ${deps} --noconfirm`
39
+ installCommand: (deps) => `sudo pacman -S ${deps} --noconfirm`,
40
+ packageManager: 'pacman'
39
41
  },
40
42
  Fedora: {
41
43
  dependencies: [
@@ -51,7 +53,8 @@ const dependenciesForPlatforms = {
51
53
  'libtool-ltdl-devel',
52
54
  'oniguruma-devel'
53
55
  ],
54
- installCommand: (deps) => `sudo yum install ${deps} -y`
56
+ installCommand: (deps) => `sudo yum install ${deps} -y`,
57
+ packageManager: 'yum'
55
58
  },
56
59
  CentOS: {
57
60
  dependencies: [
@@ -67,7 +70,8 @@ const dependenciesForPlatforms = {
67
70
  'libtool-ltdl-devel',
68
71
  'oniguruma-devel'
69
72
  ],
70
- installCommand: (deps) => `sudo yum install --enablerepo=PowerTools ${deps} -y`
73
+ installCommand: (deps) => `sudo yum install --enablerepo=PowerTools ${deps} -y`,
74
+ packageManager: 'yum'
71
75
  },
72
76
  Ubuntu: {
73
77
  dependencies: [
@@ -95,7 +99,8 @@ const dependenciesForPlatforms = {
95
99
  'autoconf',
96
100
  'cmake'
97
101
  ],
98
- installCommand: (deps) => `sudo apt-get install ${deps} -y`
102
+ installCommand: (deps) => `sudo apt install ${deps} -y`,
103
+ packageManager: 'apt'
99
104
  }
100
105
  };
101
106
 
@@ -17,7 +17,7 @@ const getComposerVersion = async ({ composer, php }) => {
17
17
 
18
18
  const composerVersion = safeRegexExtract({
19
19
  string: composerVersionOutput,
20
- regex: /Composer version ([\d.]+)/i,
20
+ regex: /(\d+\.\d+\.\d+)/i,
21
21
  onNoMatch: () => {
22
22
  throw new Error(`
23
23
  No composer version found in composer version output!\n\n${composerVersionOutput}
@@ -1,8 +1,22 @@
1
+ /* eslint-disable max-len */
1
2
  const { execAsyncSpawn } = require('../../util/exec-async-command');
2
3
 
4
+ /**
5
+ * @param {Object} options
6
+ * @param {number[]} [options.ports] Publish or expose port [docs](https://docs.docker.com/engine/reference/commandline/run/#publish-or-expose-port--p---expose)
7
+ * @param {number[]} [options.mounts] Add bind mounts or volumes using the --mount flag [docs](https://docs.docker.com/engine/reference/commandline/run/#add-bind-mounts-or-volumes-using-the---mount-flag)
8
+ * @param {number[]} [options.mountVolumes] Mount volume [docs](https://docs.docker.com/engine/reference/commandline/run/#mount-volume--v---read-only)
9
+ * @param {Record<string, string>} [options.env] Set environment variables [docs](https://docs.docker.com/engine/reference/commandline/run/#set-environment-variables--e---env---env-file)
10
+ * @param {string} [options.image]
11
+ * @param {string} [options.restart] Restart policies [docs](https://docs.docker.com/engine/reference/commandline/run/#restart-policies---restart)
12
+ * @param {string} [options.name] Container name
13
+ * @param {string} [options.entrypoint] Container entrypoint
14
+ * @param {string} [options.command] Container command
15
+ * @param {Record<"cmd" | "interval" | "retries" | "start-period" | "timeout", string>} [options.healthCheck] Container heathcheck properties
16
+ * @param {string[]} [options.securityOptions] Security options [docs](https://docs.docker.com/engine/reference/commandline/run/#optional-security-options---security-opt)
17
+ */
3
18
  const run = (options) => {
4
19
  const {
5
- expose = [],
6
20
  ports = [],
7
21
  mounts = [],
8
22
  mountVolumes = [],
@@ -19,7 +33,6 @@ const run = (options) => {
19
33
 
20
34
  const restartArg = restart && `--restart ${ restart }`;
21
35
  const networkArg = network && `--network ${ network }`;
22
- const exposeArgs = expose.map((port) => `--expose ${ port }`).join(' ');
23
36
  const portsArgs = ports.map((port) => `-p ${ port }`).join(' ');
24
37
  const mountsArgs = mounts.map((mount) => `--mount ${ mount }`).join(' ');
25
38
  const mountVolumesArgs = mountVolumes.map((mount) => `-v ${mount}`).join(' ');
@@ -36,7 +49,6 @@ const run = (options) => {
36
49
  nameArg,
37
50
  networkArg,
38
51
  restartArg,
39
- exposeArgs,
40
52
  portsArgs,
41
53
  mountsArgs,
42
54
  mountVolumesArgs,
@@ -139,7 +151,7 @@ const stopContainers = () => ({
139
151
 
140
152
  const getContainerStatus = async (containerName) => {
141
153
  try {
142
- return JSON.parse(await execAsyncSpawn(`docker inspect --format='{{json .State.Health}}' ${containerName}`));
154
+ return JSON.parse(await execAsyncSpawn(`docker inspect --format='{{json .State}}' ${containerName}`));
143
155
  } catch {
144
156
  return null;
145
157
  }
package/lib/tasks/link.js CHANGED
@@ -6,6 +6,7 @@ const linkTheme = require('./theme/link-theme');
6
6
  const { startServices } = require('./docker');
7
7
  const { startPhpFpm } = require('./php-fpm');
8
8
  const checkConfigurationFile = require('../config/check-configuration-file');
9
+ const { connectToMySQL } = require('./mysql');
9
10
 
10
11
  /**
11
12
  * @type {(theme: string) => import('listr2').ListrTask<import('../../typings/context').ListrContext>}
@@ -18,6 +19,7 @@ const linkTask = (themePath) => ({
18
19
  getCachedPorts(),
19
20
  startServices(),
20
21
  startPhpFpm(),
22
+ connectToMySQL(),
21
23
  retrieveThemeData(themePath),
22
24
  linkTheme()
23
25
  ])
@@ -81,7 +81,7 @@ const enableMagentoComposerPlugins = () => ({
81
81
  const {
82
82
  config: {
83
83
  'allow-plugins': allowPlugins = {}
84
- }
84
+ } = {}
85
85
  } = composerJsonData;
86
86
  const allowPluginsKeys = Object.keys(allowPlugins);
87
87
 
@@ -110,7 +110,7 @@ Do you want to enable them all or disable some of them?`,
110
110
 
111
111
  if (userConfirmation) {
112
112
  composerJsonData.config = {
113
- ...composerJsonData.config,
113
+ ...(composerJsonData.config || {}),
114
114
  'allow-plugins': {
115
115
  ...allowPlugins,
116
116
  ...missingPlugins.reduce((acc, val) => ({ ...acc, [val]: true }), {})
@@ -141,7 +141,7 @@ Do you want to enable them all or disable some of them?`,
141
141
  const disabledPlugins = composerPlugins.filter((p) => !userEnabledPlugins.includes(p));
142
142
 
143
143
  composerJsonData.config = {
144
- ...composerJsonData.config,
144
+ ...(composerJsonData.config || {}),
145
145
  'allow-plugins': {
146
146
  ...allowPlugins,
147
147
  ...disabledPlugins.reduce((acc, val) => ({ ...acc, [val]: false }), {}),
@@ -0,0 +1,11 @@
1
+ const magentoTask = require('../../../util/magento-task');
2
+
3
+ /**
4
+ * @type {() => import('listr2').ListrTask<import('../../../../typings/context').ListrContext>}
5
+ */
6
+ const disablePageBuilder = () => ({
7
+ title: 'Disabling page builder in Magento',
8
+ task: (ctx, task) => task.newListr(magentoTask('config:set cms/pagebuilder/enabled 0'))
9
+ });
10
+
11
+ module.exports = disablePageBuilder;
@@ -2,11 +2,14 @@ const semver = require('semver');
2
2
  const runMagentoCommand = require('../../../util/run-magento');
3
3
 
4
4
  /**
5
- * @type {() => import('listr2').ListrTask<import('../../../../typings/context').ListrContext>}
5
+ * @type {({ isDbEmpty }: { isDbEmpty: boolean }) => import('listr2').ListrTask<import('../../../../typings/context').ListrContext>}
6
6
  */
7
- const installMagento = () => ({
8
- title: 'Installing magento...',
7
+ const installMagento = ({ isDbEmpty = false } = {}) => ({
8
+ title: 'Installing magento',
9
9
  task: async (ctx, task) => {
10
+ if (isDbEmpty) {
11
+ task.output = 'No Magento is installed in DB!\nInstalling...';
12
+ }
10
13
  const {
11
14
  magentoVersion,
12
15
  config: {
@@ -24,16 +24,14 @@ const migrateDatabase = (options = {}) => ({
24
24
  `);
25
25
 
26
26
  if (tableCount === 0) {
27
- task.output = 'No Magento is installed in DB!\nInstalling...';
28
-
29
27
  if (options.onlyInstallMagento) {
30
28
  return task.newListr(
31
- installMagento()
29
+ installMagento({ isDbEmpty: true })
32
30
  );
33
31
  }
34
32
 
35
33
  return task.newListr([
36
- installMagento(),
34
+ installMagento({ isDbEmpty: true }),
37
35
  setupPersistedQuery(),
38
36
  upgradeMagento(),
39
37
  magentoTask('cache:enable'),
@@ -11,8 +11,9 @@ module.exports = () => ({
11
11
  config: { overridenConfiguration: { host, ssl } },
12
12
  mysqlConnection
13
13
  } = ctx;
14
+ const isNgrok = host.endsWith('ngrok.io');
14
15
  const enableSecureFrontend = ssl.enabled ? '1' : '0';
15
- const location = `${host}${ ports.app !== 80 ? `:${ports.app}` : '' }/`;
16
+ const location = `${host}${ !isNgrok && ports.app !== 80 ? `:${ports.app}` : '' }/`;
16
17
  const secureLocation = `${host}/`; // SSL will work only on port 443, so you cannot run multiple projects with SSL at the same time.
17
18
  const httpUrl = `http://${location}`;
18
19
  const httpsUrl = `https://${secureLocation}`;
@@ -7,6 +7,7 @@ const sleep = require('../../util/sleep');
7
7
  */
8
8
  const connectToMySQL = () => ({
9
9
  title: 'Connecting to MySQL server...',
10
+ skip: (ctx) => ctx.skipSetup,
10
11
  task: async (ctx, task) => {
11
12
  const { config: { docker }, ports } = ctx;
12
13
  const { mysql: { env, name } } = docker.getContainers();
@@ -44,7 +44,7 @@ const compileOptions = {
44
44
  '+bz2="$(brew --prefix bzip2)"',
45
45
  '+bcmath',
46
46
  '+ctype',
47
- '+curl=$(brew --prefix curl-openssl)',
47
+ '+curl=$(brew --prefix curl)',
48
48
  '+intl=$(brew --prefix icu4c)',
49
49
  '+dom',
50
50
  '+filter',
@@ -70,7 +70,7 @@ const compileOptions = {
70
70
  ],
71
71
  env: {
72
72
  // eslint-disable-next-line max-len
73
- PKG_CONFIG_PATH: '$PKG_CONFIG_PATH:$(brew --prefix libxml2)/lib/pkgconfig:$(brew --prefix icu4c)/lib/pkgconfig:$(brew --prefix openssl@1.1)/lib/pkgconfig:$(brew --prefix curl-openssl@1.1)/lib/pkgconfig:$(brew --prefix zlib)/lib/pkgconfig',
73
+ PKG_CONFIG_PATH: '$PKG_CONFIG_PATH:$(brew --prefix libxml2)/lib/pkgconfig:$(brew --prefix icu4c)/lib/pkgconfig:$(brew --prefix openssl@1.1)/lib/pkgconfig:$(brew --prefix curl)/lib/pkgconfig:$(brew --prefix zlib)/lib/pkgconfig',
74
74
  CPATH: '$CPATH:$(brew --prefix openssl@1.1)/include',
75
75
  CXX: 'g++ -DTRUE=1 -DFALSE=0',
76
76
  CC: 'gcc -DTRUE=1 -DFALSE=0',
@@ -1,4 +1,4 @@
1
- const osPlatform = require('../../util/os-platform');
1
+ const systeminformation = require('systeminformation');
2
2
  const logger = require('@scandipwa/scandipwa-dev-utils/logger');
3
3
  const { execAsyncSpawn } = require('../../util/exec-async-command');
4
4
  const compileOptions = require('./compile-options');
@@ -11,8 +11,8 @@ const compile = () => ({
11
11
  task: async ({ config: { php } }, task) => {
12
12
  const platformCompileOptions = compileOptions[process.platform];
13
13
  if (process.platform === 'linux') {
14
- const { dist } = await osPlatform();
15
- if (['Fedora', 'Manjaro'].some((distro) => dist.includes(distro))) {
14
+ const { distro } = await systeminformation.osInfo();
15
+ if (['Fedora', 'Manjaro'].some((d) => distro.includes(d))) {
16
16
  platformCompileOptions.extraOptions.push('--with-libdir=lib64');
17
17
  }
18
18
  }
@@ -1,4 +1,5 @@
1
1
  const fs = require('fs');
2
+ const path = require('path');
2
3
  const logger = require('@scandipwa/scandipwa-dev-utils/logger');
3
4
  const pathExists = require('../../util/path-exists');
4
5
  const compile = require('./compile');
@@ -24,15 +25,28 @@ const installPhp = () => ({
24
25
  task.title = `Installing PHP ${php.version}`;
25
26
 
26
27
  try {
27
- const hasPHPVersion = (
28
- await fs.promises.readdir(phpbrewConfig.phpPath, {
29
- encoding: 'utf-8',
30
- withFileTypes: true
31
- })
32
- )
33
- .some((f) => f.isDirectory() && f.name === `php-${php.version}`);
28
+ const hasPHPVersionDirectory = (
29
+ await Promise.all(
30
+ (
31
+ await fs.promises.readdir(phpbrewConfig.phpPath, {
32
+ encoding: 'utf-8',
33
+ withFileTypes: true
34
+ })
35
+ ).map(async (f) => {
36
+ if (!f.isDirectory()) {
37
+ return false;
38
+ }
34
39
 
35
- if (hasPHPVersion && !recompilePhp) {
40
+ if (f.name !== `php-${php.version}`) {
41
+ return false;
42
+ }
43
+
44
+ return pathExists(path.join(phpbrewConfig.phpPath, f.name, 'bin', 'php'));
45
+ })
46
+ ))
47
+ .includes(true);
48
+
49
+ if (hasPHPVersionDirectory && !recompilePhp) {
36
50
  task.skip();
37
51
  // eslint-disable-next-line consistent-return
38
52
  return;
@@ -1,19 +1,18 @@
1
- const osPlatform = require('../../../util/os-platform');
2
1
  const archDependenciesCheck = require('./arch');
3
2
  const fedoraDependenciesCheck = require('./fedora');
4
3
  const centosDependenciesCheck = require('./centos');
5
4
  const ubuntuDependenciesCheck = require('./ubuntu');
6
5
  const macDependenciesCheck = require('./mac');
6
+ const osPlatform = require('../../../util/os-platform');
7
7
 
8
8
  const dependencyCheck = async () => {
9
9
  if (process.platform === 'darwin') {
10
10
  return macDependenciesCheck();
11
11
  }
12
12
 
13
- const { dist } = await osPlatform();
14
- switch (dist) {
15
- case 'Arch Linux':
16
- case 'Manjaro Linux': {
13
+ const distro = await osPlatform();
14
+ switch (distro) {
15
+ case 'Arch Linux': {
17
16
  return archDependenciesCheck();
18
17
  }
19
18
  case 'Fedora': {
@@ -22,7 +21,6 @@ const dependencyCheck = async () => {
22
21
  case 'CentOS': {
23
22
  return centosDependenciesCheck();
24
23
  }
25
- case 'Linux Mint':
26
24
  case 'Ubuntu': {
27
25
  return ubuntuDependenciesCheck();
28
26
  }
@@ -3,6 +3,7 @@ const os = require('os');
3
3
  const { execAsyncSpawn } = require('../../../util/exec-async-command');
4
4
  const getIsWsl = require('../../../util/is-wsl');
5
5
  const installDocker = require('./install');
6
+ const { checkDockerSocketPermissions } = require('./permissions');
6
7
  const getDockerVersion = require('./version');
7
8
 
8
9
  /**
@@ -70,4 +71,14 @@ ${ logger.style.link('https://docs.create-magento-app.com/getting-started/prereq
70
71
  }
71
72
  });
72
73
 
73
- module.exports = checkDocker;
74
+ /**
75
+ * @type {() => import('listr2').ListrTask<import('../../../../typings/context').ListrContext>}
76
+ */
77
+ module.exports = () => ({
78
+ task: (ctx, task) => task.newListr([
79
+ checkDockerSocketPermissions(),
80
+ checkDocker()
81
+ ], {
82
+ concurrent: false
83
+ })
84
+ });
@@ -16,10 +16,9 @@ const postInstallSteps = [
16
16
  const installDocker = () => ({
17
17
  title: 'Installing Docker',
18
18
  task: async (ctx, task) => {
19
- const { dist } = await osPlatform();
20
- switch (dist) {
21
- case 'Arch Linux':
22
- case 'Manjaro Linux': {
19
+ const distro = await osPlatform();
20
+ switch (distro) {
21
+ case 'Arch Linux': {
23
22
  return task.newListr([
24
23
  installDependenciesTask({
25
24
  platform: 'Arch Linux',
@@ -39,7 +38,6 @@ const installDocker = () => ({
39
38
  executeSudoCommand('sudo systemctl enable docker')
40
39
  ]);
41
40
  }
42
- case 'Linux Mint':
43
41
  case 'Ubuntu': {
44
42
  return task.newListr([
45
43
  execCommandTask('curl -fsSL https://get.docker.com -o get-docker.sh'),
@@ -51,7 +49,7 @@ const installDocker = () => ({
51
49
  }
52
50
  default: {
53
51
  throw new Error(`Docker is not installed!
54
- Your distro ${dist} is not supported by automatic installation.`);
52
+ Your distro ${distro} is not supported by automatic installation.`);
55
53
  }
56
54
  }
57
55
  }
@@ -0,0 +1,58 @@
1
+ const os = require('os');
2
+ const fs = require('fs');
3
+ const logger = require('@scandipwa/scandipwa-dev-utils/logger');
4
+ const pathExists = require('../../../util/path-exists');
5
+ const { execCommandTask } = require('../../../util/exec-async-command');
6
+
7
+ const dockerSocketPath = '/var/run/docker.sock';
8
+
9
+ const fixCommand = `sudo chmod 666 ${ dockerSocketPath }`;
10
+
11
+ /**
12
+ * @type {() => import('listr2').ListrTask<import('../../../../typings/context').ListrContext>}
13
+ */
14
+ const checkDockerSocketPermissions = () => ({
15
+ title: 'Checking Docker permissions',
16
+ // skip check if socket does not exist
17
+ skip: async () => !await pathExists(dockerSocketPath),
18
+ task: async (ctx, task) => {
19
+ try {
20
+ await fs.promises.access(dockerSocketPath, fs.constants.R_OK);
21
+ } catch (e) {
22
+ // check for permission
23
+ if (Math.abs(e.errno) === Math.abs(os.constants.errno.EACCES)) {
24
+ const confirmPrompt = await task.prompt({
25
+ type: 'Confirm',
26
+ message: `We detected that your Docker socket, located in ${ logger.style.file(dockerSocketPath) }, have permissions set, that prevents user (${ logger.style.misc(os.userInfo().username) }) from accessing it.
27
+
28
+ We can fix it by running the following command: ${ logger.style.command(fixCommand) }
29
+
30
+ Would you like to fix this permission issue?
31
+
32
+ Otherwise installation will likely fail.`
33
+ });
34
+
35
+ if (confirmPrompt) {
36
+ task.output = 'Enter your sudo password!';
37
+ task.output = logger.style.command(`>[sudo] password for ${ os.userInfo().username }:`);
38
+ return task.newListr(
39
+ execCommandTask(fixCommand, {
40
+ callback: (t) => {
41
+ task.output = t;
42
+ },
43
+ pipeInput: true
44
+ })
45
+ );
46
+ }
47
+ task.skip(`Permission issue detected in ${ logger.style.file(dockerSocketPath) } but user decided not to fix it.`);
48
+ }
49
+ }
50
+ },
51
+ options: {
52
+ bottomBar: 10
53
+ }
54
+ });
55
+
56
+ module.exports = {
57
+ checkDockerSocketPermissions
58
+ };
@@ -1,23 +1,16 @@
1
1
  const { execAsyncSpawn } = require('../../../util/exec-async-command');
2
- const safeRegexExtract = require('../../../util/safe-regex-extract');
3
2
 
4
3
  /**
5
4
  * @type {() => import('listr2').ListrTask<import('../../../../typings/context').ListrContext>}
6
5
  */
7
6
  const getDockerVersion = () => ({
8
7
  task: async (ctx) => {
9
- const { result, code } = await execAsyncSpawn('docker -v', {
8
+ const { result, code } = await execAsyncSpawn('docker version --format {{.Server.Version}}', {
10
9
  withCode: true
11
10
  });
12
11
 
13
12
  if (code === 0) {
14
- const dockerVersion = safeRegexExtract({
15
- string: result,
16
- regex: /docker version ([\d.]+)/i,
17
- onNoMatch: () => {
18
- throw new Error(`No docker version found in docker version output!\n\n${result}`);
19
- }
20
- });
13
+ const dockerVersion = result.split('').filter((c) => /[\d.]/i.test(c)).join('') || result;
21
14
 
22
15
  ctx.dockerVersion = dockerVersion;
23
16
  }
@@ -1,10 +1,10 @@
1
1
  const os = require('os');
2
2
  const path = require('path');
3
3
  const fs = require('fs');
4
- const osPlatform = require('../../../util/os-platform');
5
4
  const { execAsyncSpawn } = require('../../../util/exec-async-command');
6
5
  const logger = require('@scandipwa/scandipwa-dev-utils/logger');
7
6
  const installDependenciesTask = require('../../../util/install-dependencies-task');
7
+ const osPlatform = require('../../../util/os-platform');
8
8
 
9
9
  /**
10
10
  * @type {() => import('listr2').ListrTask<import('../../../../typings/context').ListrContext>}
@@ -20,10 +20,9 @@ const installPHPBrewDependencies = () => ({
20
20
  })
21
21
  );
22
22
  }
23
- const { dist } = await osPlatform();
24
- switch (dist) {
25
- case 'Arch Linux':
26
- case 'Manjaro Linux': {
23
+ const distro = await osPlatform();
24
+ switch (distro) {
25
+ case 'Arch Linux': {
27
26
  return task.newListr(
28
27
  installDependenciesTask({
29
28
  platform: 'Arch Linux',
@@ -47,7 +46,6 @@ const installPHPBrewDependencies = () => ({
47
46
  })
48
47
  );
49
48
  }
50
- case 'Linux Mint':
51
49
  case 'Ubuntu': {
52
50
  return task.newListr(
53
51
  installDependenciesTask({
@@ -27,6 +27,8 @@ const pkg = require('../../package.json');
27
27
  const checkConfigurationFile = require('../config/check-configuration-file');
28
28
  const convertLegacyVolumes = require('./docker/convert-legacy-volumes');
29
29
  const enableMagentoComposerPlugins = require('./magento/enable-magento-composer-plugins');
30
+ const getIsWsl = require('../util/is-wsl');
31
+ const checkForXDGOpen = require('../util/xdg-open-exists');
30
32
 
31
33
  /**
32
34
  * @type {() => import('listr2').ListrTask<import('../../typings/context').ListrContext>}
@@ -172,7 +174,21 @@ const start = () => ({
172
174
  finishProjectConfiguration(),
173
175
  {
174
176
  title: 'Opening browser',
175
- skip: (ctx) => ctx.noOpen,
177
+ skip: async (ctx) => {
178
+ if (ctx.noOpen) {
179
+ return true;
180
+ }
181
+
182
+ if (await getIsWsl()) {
183
+ const canOpenBrowser = await checkForXDGOpen();
184
+
185
+ if (!canOpenBrowser) {
186
+ return 'Cannot open the browser, xdg-open is not available.';
187
+ }
188
+ }
189
+
190
+ return false;
191
+ },
176
192
  task: ({ ports, config: { overridenConfiguration: { host, ssl } } }) => {
177
193
  openBrowser(`${ssl.enabled ? 'https' : 'http'}://${host}${ssl.enabled || ports.app === 80 ? '' : `:${ports.app}`}/`);
178
194
  },
@@ -7,6 +7,20 @@ const { getArchSync } = require('../../util/arch');
7
7
  const ConsoleBlock = require('../../util/console-block');
8
8
  const { getComposerVersion } = require('../composer');
9
9
 
10
+ /**
11
+ * @param {string} port
12
+ * @return {{ host: string, hostPort: string, containerPort: string }}
13
+ */
14
+ const parsePort = (port) => {
15
+ const [host, hostPort, containerPort] = port.split(':');
16
+
17
+ return {
18
+ host,
19
+ hostPort,
20
+ containerPort
21
+ };
22
+ };
23
+
10
24
  const prettyStatus = async (ctx) => {
11
25
  const {
12
26
  ports,
@@ -64,14 +78,11 @@ const prettyStatus = async (ctx) => {
64
78
  .addEmptyLine();
65
79
 
66
80
  let containerStatus;
67
- if (container.status) {
68
- if (container.status.Status === 'healthy') {
69
- containerStatus = `✓ ${logger.style.file('running')}`;
70
- } else {
71
- containerStatus = logger.style.code(container.status.Status);
72
- }
81
+
82
+ if (container.status && container.status.Health) {
83
+ containerStatus = `✓ ${ logger.style.file(container.status.Health.Status) } and ${ logger.style.file('running') }`;
73
84
  } else {
74
- containerStatus = logger.style.code('stopped');
85
+ containerStatus = logger.style.file(container.status.Status);
75
86
  }
76
87
 
77
88
  block
@@ -81,10 +92,14 @@ const prettyStatus = async (ctx) => {
81
92
  .addLine(`Network: ${logger.style.link(container.network)}`);
82
93
 
83
94
  if (container.ports.length > 0) {
84
- block.addLine(`Port forwarding: ${container.ports.map((port) => logger.style.link(port)).join(', ')}`);
95
+ block.addLine('Port forwarding:');
96
+ container.ports.forEach((port) => {
97
+ const { host, hostPort, containerPort } = parsePort(port);
98
+ block.addLine(`${' '.repeat(3)} ${logger.style.link(`${host}:${hostPort}`)} -> ${logger.style.file(containerPort)}`);
99
+ });
85
100
  }
86
101
 
87
- if (container.env) {
102
+ if (container.env && Object.keys(container.env).length > 0) {
88
103
  block.addLine('Environment variables:');
89
104
  for (const [envName, envValue] of Object.entries(container.env)) {
90
105
  block.addLine(`${' '.repeat(3)} ${logger.style.misc(envName)}=${logger.style.file(envValue)}`);
@@ -1,10 +1,12 @@
1
1
  const symlinkTheme = require('./symlink-theme');
2
2
  const installTheme = require('./install-theme');
3
3
  const disablePageCache = require('../magento/setup-magento/disable-page-cache');
4
+ const disablePageBuilder = require('../magento/setup-magento/disable-page-builder');
4
5
  const buildTheme = require('./build-theme');
5
6
  const upgradeMagento = require('../magento/setup-magento/upgrade-magento');
6
7
  const setupPersistedQuery = require('./setup-persisted-query');
7
8
  const updateEnvPHP = require('../php/update-env-php');
9
+ const semver = require('semver');
8
10
 
9
11
  /**
10
12
  * @type {() => import('listr2').ListrTask<import('../../../typings/context').ListrContext>}
@@ -12,7 +14,28 @@ const updateEnvPHP = require('../php/update-env-php');
12
14
  const linkTheme = () => ({
13
15
  title: 'Linking theme',
14
16
  task: async (ctx, task) => {
15
- const { absoluteThemePath, themePath, composerData } = ctx;
17
+ const {
18
+ config: { overridenConfiguration },
19
+ absoluteThemePath,
20
+ themePath,
21
+ composerData,
22
+ mysqlConnection
23
+ } = ctx;
24
+ const {
25
+ magento: { edition: magentoEdition },
26
+ magentoVersion
27
+ } = overridenConfiguration;
28
+
29
+ const isEnterprise = magentoEdition === 'enterprise';
30
+ const isPageBuilderInstalled = isEnterprise && semver.satisfies(semver.coerce(magentoVersion), '^2.4');
31
+ const [queryResult] = await mysqlConnection.query(`
32
+ SELECT value AS isPagebuilderEnabled
33
+ FROM core_config_data
34
+ WHERE path = 'cms/pagebuilder/enabled'
35
+ `);
36
+
37
+ const [{ isPagebuilderEnabled = 1 }] = queryResult.length ? queryResult : [{}];
38
+
16
39
  /**
17
40
  * @type {import('../../../typings/theme').Theme}
18
41
  */
@@ -31,6 +54,7 @@ const linkTheme = () => ({
31
54
  setupPersistedQuery(),
32
55
  upgradeMagento(),
33
56
  disablePageCache(),
57
+ ...(isPageBuilderInstalled && Number(isPagebuilderEnabled) ? [disablePageBuilder()] : []),
34
58
  buildTheme(theme)
35
59
  ]);
36
60
  },
@@ -0,0 +1,74 @@
1
+ const logger = require('@scandipwa/scandipwa-dev-utils/logger');
2
+
3
+ const WEB_LOCAL_LOCATION_TITLE = `Location on ${ logger.style.misc('localhost') }`;
4
+ const WEB_LOCATION_TITLE = 'Location on the Web';
5
+ const WEB_ADMIN_LOCATION_TITLE = 'Panel location';
6
+ const WEB_ADMIN_CREDENTIALS_TITLE = 'Panel credentials';
7
+
8
+ const mapDataStyle = ({ title, text }) => ({
9
+ title,
10
+ text: logger.style.link(text)
11
+ });
12
+
13
+ /**
14
+ * @param {import("../../typings/context").ListrContext} ctx
15
+ * @return {{ frontend: { title: string, text: string }[], admin: { title: string, url: string }[]}}
16
+ */
17
+ const getInstanceMetadata = (ctx) => {
18
+ const {
19
+ ports,
20
+ config: {
21
+ magentoConfiguration,
22
+ overridenConfiguration: { host, ssl }
23
+ }
24
+ } = ctx;
25
+
26
+ /**
27
+ * @type {{ title: string, text: string }[]}
28
+ */
29
+ const frontend = [];
30
+
31
+ /**
32
+ * @type {{ title: string, text: string }[]}
33
+ */
34
+ const admin = [];
35
+
36
+ const isNgrok = host.endsWith('ngrok.io');
37
+
38
+ if (isNgrok) {
39
+ frontend.push({
40
+ title: WEB_LOCAL_LOCATION_TITLE,
41
+ text: `${ssl.enabled ? 'https' : 'http'}://localhost${ssl.enabled || ports.app === 80 ? '' : `:${ports.app}`}/`
42
+ });
43
+ frontend.push({
44
+ title: WEB_LOCATION_TITLE,
45
+ text: `${ssl.enabled ? 'https' : 'http'}://${host}/`
46
+ });
47
+ } else {
48
+ frontend.push({
49
+ title: WEB_LOCATION_TITLE,
50
+ text: `${ssl.enabled ? 'https' : 'http'}://${host}${ssl.enabled || ports.app === 80 ? '' : `:${ports.app}`}/`
51
+ });
52
+ }
53
+
54
+ const webLocation = frontend.find((u) => u.title === WEB_LOCATION_TITLE);
55
+
56
+ admin.push({
57
+ title: WEB_ADMIN_LOCATION_TITLE,
58
+ text: logger.style.link(`${webLocation.text}admin`)
59
+ });
60
+
61
+ admin.push({
62
+ title: WEB_ADMIN_CREDENTIALS_TITLE,
63
+ text: `${logger.style.misc(magentoConfiguration.user)} - ${logger.style.misc(magentoConfiguration.password)}`
64
+ });
65
+
66
+ return {
67
+ admin,
68
+ frontend: frontend.map(mapDataStyle)
69
+ };
70
+ };
71
+
72
+ module.exports = {
73
+ getInstanceMetadata
74
+ };
@@ -2,7 +2,8 @@ const { execAsync } = require('./exec-async-command');
2
2
 
3
3
  const openBrowser = async (url) => {
4
4
  const start = process.platform === 'darwin' ? 'open' : 'xdg-open';
5
- await execAsync(`${start } ${ url}`);
5
+
6
+ await execAsync(`${ start } ${ url }`);
6
7
  };
7
8
 
8
9
  module.exports = openBrowser;
@@ -1,9 +1,51 @@
1
- const getos = require('getos');
1
+ const fs = require('fs');
2
+ const systeminformation = require('systeminformation');
3
+ const pathExists = require('./path-exists');
4
+ const dependenciesForPlatforms = require('../config/dependencies-for-platforms');
2
5
 
6
+ const packageManagers = Object.entries(dependenciesForPlatforms).map((d) => ({
7
+ platform: d[0],
8
+ packageManager: d[1].packageManager
9
+ }));
3
10
  /**
4
11
  *
5
- * @returns {Promise<import('getos').OS>}
12
+ * @returns {Promise<keyof typeof dependenciesForPlatforms>}
6
13
  */
7
- const osPlatform = () => new Promise((resolve, reject) => getos((err, os) => (err ? reject(err) : resolve(os))));
14
+ const osPlatform = async () => {
15
+ const binPaths = process.env.PATH.split(':');
16
+
17
+ const platforms = await Promise.all(binPaths.map(async (binPath) => {
18
+ if (!await pathExists(binPath)) {
19
+ return null;
20
+ }
21
+ const bins = await fs.promises.readdir(binPath);
22
+
23
+ for (const bin of bins) {
24
+ const possiblePlatforms = packageManagers.filter((p) => p.packageManager === bin);
25
+
26
+ if (possiblePlatforms.length > 0) {
27
+ if (possiblePlatforms.length > 1) {
28
+ const { distro } = await systeminformation.osInfo();
29
+
30
+ const foundDistro = possiblePlatforms.find((p) => p.platform.toLowerCase().includes(distro.toLowerCase()));
31
+
32
+ if (foundDistro) {
33
+ return foundDistro.platform;
34
+ }
35
+
36
+ return possiblePlatforms[0].platform;
37
+ }
38
+
39
+ return possiblePlatforms[0].platform;
40
+ }
41
+ }
42
+
43
+ return null;
44
+ }));
45
+
46
+ const filteredPlatforms = platforms.filter(Boolean);
47
+
48
+ return filteredPlatforms.shift();
49
+ };
8
50
 
9
51
  module.exports = osPlatform;
@@ -0,0 +1,27 @@
1
+ const fs = require('fs');
2
+ const pathExists = require('./path-exists');
3
+
4
+ const checkForXDGOpen = async () => {
5
+ const pathParts = process.env.PATH.split(':');
6
+
7
+ const results = await Promise.all(
8
+ pathParts.map(
9
+ async (pathPart) => {
10
+ if (!await pathExists(pathPart)) {
11
+ return false;
12
+ }
13
+
14
+ const files = await fs.promises.readdir(pathPart, {
15
+ encoding: 'utf-8',
16
+ withFileTypes: true
17
+ });
18
+
19
+ return files.some((file) => file.isFile() && file.name === 'xdg-open');
20
+ }
21
+ )
22
+ );
23
+
24
+ return results.includes(true);
25
+ };
26
+
27
+ module.exports = checkForXDGOpen;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Scripts and configuration used by CMA.",
4
4
  "homepage": "https://docs.create-magento-app.com/",
5
5
  "repository": "github:scandipwa/create-magento-app",
6
- "version": "1.13.3",
6
+ "version": "1.13.5-alpha.1",
7
7
  "main": "./index.js",
8
8
  "types": "./typings/index.d.ts",
9
9
  "license": "OSL-3.0",
@@ -23,24 +23,23 @@
23
23
  ],
24
24
  "dependencies": {
25
25
  "@scandipwa/scandipwa-dev-utils": "0.1.12",
26
- "conf": "10.0.3",
26
+ "conf": "10.1.1",
27
27
  "enquirer": "2.3.6",
28
28
  "eta": "1.12.3",
29
- "getos": "3.2.1",
30
29
  "hjson": "^3.2.2",
31
30
  "is-installed-globally": "0.4.0",
32
- "joi": "17.4.2",
33
- "listr2": "3.13.0",
31
+ "joi": "17.6.0",
32
+ "listr2": "4.0.5",
34
33
  "macos-version": "5.2.1",
35
34
  "merge-files": "0.1.2",
36
35
  "mysql2": "2.3.2",
37
36
  "node-ssh": "12.0.0",
38
37
  "semver": "7.3.5",
39
- "systeminformation": "5.9.8",
40
- "yargs": "17.2.1"
38
+ "systeminformation": "5.11.7",
39
+ "yargs": "17.3.1"
41
40
  },
42
41
  "publishConfig": {
43
42
  "access": "public"
44
43
  },
45
- "gitHead": "b03f5e0d8d7899f8d217b5eda38e7daabc63dccd"
44
+ "gitHead": "e00e8d06964b4a7fc5a0095ea510fc26a06520a8"
46
45
  }