@ordergroove/smi-serve 1.9.4 → 1.9.6

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/CHANGELOG.md CHANGED
@@ -3,6 +3,22 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [1.9.6](https://github.com/ordergroove/plush-toys/compare/@ordergroove/smi-serve@1.9.5...@ordergroove/smi-serve@1.9.6) (2024-11-13)
7
+
8
+ **Note:** Version bump only for package @ordergroove/smi-serve
9
+
10
+
11
+
12
+
13
+
14
+ ## [1.9.5](https://github.com/ordergroove/plush-toys/compare/@ordergroove/smi-serve@1.9.4...@ordergroove/smi-serve@1.9.5) (2024-11-13)
15
+
16
+ **Note:** Version bump only for package @ordergroove/smi-serve
17
+
18
+
19
+
20
+
21
+
6
22
  ## [1.9.4](https://github.com/ordergroove/plush-toys/compare/@ordergroove/smi-serve@1.9.3...@ordergroove/smi-serve@1.9.4) (2024-11-11)
7
23
 
8
24
  **Note:** Version bump only for package @ordergroove/smi-serve
package/README.md CHANGED
@@ -12,7 +12,7 @@ To initialize the current directory for local Subscription Manager development,
12
12
 
13
13
  After initialization, you can restart the dev server with `npx @ordergroove/smi-serve`.
14
14
 
15
- When you are ready to push your changes to production, run `npx @ordergroove/smi-serve deploy` to deploy your changes to Ordergroove.
15
+ When you are ready to push your changes, run `npx @ordergroove/smi-serve push-theme` to deploy your changes to Ordergroove. If the theme you're pushing is live, your changes will be published immediately!
16
16
 
17
17
  ## Configuration file
18
18
 
@@ -26,7 +26,7 @@ To see all available commands and flags, run `npx @ordergroove/smi-serve --help`
26
26
 
27
27
  ### init
28
28
 
29
- Initializes the current directory with the assets from your live Subscription Manager theme and starts a dev server. This only needs to be run when you need to retrieve the latest assets from Ordergroove; otherwise you can start the dev server directly with `npx @ordergroove/smi-serve serve`.
29
+ Initializes the current directory with the assets from your live Subscription Manager theme and starts a dev server. This only needs to be run when you need to retrieve the latest assets from Ordergroove; otherwise you can start the dev server directly with `npx @ordergroove/smi-serve serve`. To pull new assets, use the `pull-theme` command.
30
30
 
31
31
  ### serve
32
32
 
@@ -34,9 +34,13 @@ Starts a development server. This is the default command, so it can also be run
34
34
 
35
35
  By default it will choose a random available port, but you can customize this with the `--port` flag.
36
36
 
37
- ### deploy
37
+ ### pull-theme
38
38
 
39
- Publishes your template changes to your live Subscription Manager theme. Before publishing, it will summarize which files have changed and ask for confirmation.
39
+ Presents you with a list of your Subscription Manager themes including your live theme. Selecting a theme will overwrite the files in your present working directory.
40
+
41
+ ### push-theme
42
+
43
+ Publishes your template changes to your selected Subscription Manager theme. If the theme you're pushing is your live theme, your changes will be published to your live site immediately!
40
44
 
41
45
  ### select-merchant
42
46
 
@@ -52,7 +56,7 @@ Keep in mind that if you use this flag, _every command_ you run must also includ
52
56
 
53
57
  ### How do I integrate with source control?
54
58
 
55
- Once you run the `init` command, you can initialize the folder as a Git repository with `git init` and push to the source control provider of your choice. When you are ready to deploy the changes, run `npx @ordergroove/smi-serve deploy`.
59
+ Once you run the `init` command, you can initialize the folder as a Git repository with `git init` and push to the source control provider of your choice. When you are ready to deploy the changes, run `npx @ordergroove/smi-serve push-theme`.
56
60
 
57
61
  Make sure to commit the autogenerated `.gitignore`, which prevents you from committing the `.ogrc.json` file to source control. The `ogrc` file contains authentication tokens and should not be committed.
58
62
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ordergroove/smi-serve",
3
- "version": "1.9.4",
3
+ "version": "1.9.6",
4
4
  "description": "Utility to serve a Subscription Manager template locally",
5
5
  "keywords": [],
6
6
  "author": "Eugenio Lattanzio <eugenio.lattanzio@ordergroove.com>",
@@ -35,5 +35,5 @@
35
35
  "devDependencies": {
36
36
  "memfs": "^4.8.2"
37
37
  },
38
- "gitHead": "b395503cfeafe2043079a72bbb6365150d943280"
38
+ "gitHead": "c521e348e2da6908ba2e6daab6c6fe204a3953d6"
39
39
  }
package/smi-serve.js CHANGED
@@ -9,11 +9,10 @@ const figures = require('figures');
9
9
 
10
10
  const { getcwd, getNetFreePort, readRcEnv } = require('./src/utils');
11
11
  const { cliCallSelectMerchant } = require('./src/select-merchant');
12
- const { cliPullTheme } = require('./src/pull-theme');
13
- const { deploy } = require('./src/deploy');
12
+ const { cliPullTheme, getMerchantThemes } = require('./src/pull-theme');
13
+ const { cliPushTheme } = require('./src/push-theme');
14
14
  const { init, DirNotEmpty, OG_RC_FILE } = require('./src/init');
15
15
  const { serve } = require('./src/serve');
16
- const { getMerchantThemes } = require('./src/pull-theme');
17
16
 
18
17
  function box(text) {
19
18
  return `\
@@ -60,7 +59,7 @@ function wrapHandler(fn) {
60
59
  ID: ${merchant.public_id}
61
60
  Platform: ${merchant.ecommerce_platform}
62
61
  Env: ${args.env}
63
- . Live theme: ${liveTheme.name}
62
+ Live theme: ${liveTheme.name}
64
63
  Selected theme: ${merchant.selectedTheme?.name || 'N/A'}\
65
64
  `)
66
65
  );
@@ -110,11 +109,6 @@ async function program() {
110
109
  describe: 'Start the dev server',
111
110
  handler: wrapHandler(initOrServe)
112
111
  })
113
- .command({
114
- command: 'deploy',
115
- describe: 'Publish your template changes to your live theme',
116
- handler: wrapHandler(deploy)
117
- })
118
112
  .command({
119
113
  command: 'select-merchant',
120
114
  describe: 'Select a different Ordergroove merchant',
@@ -125,6 +119,11 @@ async function program() {
125
119
  describe: 'Pull the theme data for the selected merchant',
126
120
  handler: wrapHandler(cliPullTheme)
127
121
  })
122
+ .command({
123
+ command: 'push-theme',
124
+ describe: 'Push the theme data for the selected merchant',
125
+ handler: wrapHandler(cliPushTheme)
126
+ })
128
127
  .option('verbose', {
129
128
  alias: 'v',
130
129
  type: 'boolean',
package/smi-serve.spec.js CHANGED
@@ -87,7 +87,6 @@ describe('smi-serve', () => {
87
87
  templatesVersion: '0.40.1'
88
88
  },
89
89
  scripts: {
90
- deploy: 'smi-serve deploy',
91
90
  start: 'smi-serve'
92
91
  }
93
92
  },
package/src/init.js CHANGED
@@ -159,8 +159,7 @@ node_modules/
159
159
 
160
160
  await updateJsonFile(path.join(args.cwd, 'package.json'), {
161
161
  scripts: {
162
- start: 'smi-serve',
163
- deploy: 'smi-serve deploy'
162
+ start: 'smi-serve'
164
163
  },
165
164
  description: `Ordergroove Subscription Manager for ${merchant.name} on ${merchant.ecommerce_platform} platform (${merchant.public_id})}`,
166
165
  author: getAuthorNameFromToken(token),
@@ -0,0 +1,136 @@
1
+ const fs = require('fs');
2
+ const fetch = require('node-fetch');
3
+ const util = require('util');
4
+ const glob = util.promisify(require('glob'));
5
+ const inquirer = require('inquirer');
6
+ const { getMerchantThemes } = require('./pull-theme');
7
+ const { getValidSettings } = require('./select-merchant');
8
+ const { getRC3Url } = require('./auth');
9
+ const { getcwd, readRcEnv } = require('./utils');
10
+
11
+ // Function to push theme files to the selected theme
12
+ async function pushTheme(args) {
13
+ try {
14
+ // Get the selected merchant and token based on the environment
15
+ let { token, merchant } = await getValidSettings(args);
16
+ const env = args.env;
17
+
18
+ // Read theme details from .ogrc.json for the selected environment
19
+ const config = await readRcEnv(args);
20
+ const { selectedTheme } = config.merchant;
21
+
22
+ if (!selectedTheme) {
23
+ console.error(`No theme selected for environment: ${env}. Please run pull-theme first.`);
24
+ return;
25
+ }
26
+
27
+ const { live: liveTheme } = await getMerchantThemes(args);
28
+ const isLiveTheme = liveTheme.id === selectedTheme.id;
29
+
30
+ console.log(`Pushing to Theme: ${selectedTheme.name} (ID: ${selectedTheme.id})`);
31
+
32
+ if (isLiveTheme) {
33
+ console.log('THIS IS YOUR LIVE THEME. CHANGES WILL BE PUBLISHED IMMEDIATELY.');
34
+ }
35
+
36
+ const fileList = await getThemeFiles(args);
37
+
38
+ const original = await fetchOriginalConfig(args, merchant, token, isLiveTheme);
39
+
40
+ const newRequest = buildRequestPayload(isLiveTheme, original, fileList, merchant, selectedTheme);
41
+
42
+ // Confirm with the user if they want to proceed
43
+ const { ok } = args.yes
44
+ ? { ok: true }
45
+ : await inquirer.prompt([
46
+ {
47
+ type: 'list',
48
+ name: 'ok',
49
+ message: 'Do you want to deploy your files to this theme?',
50
+ choices: [
51
+ { value: true, name: `Yes` },
52
+ { value: false, name: 'No' }
53
+ ]
54
+ }
55
+ ]);
56
+
57
+ if (!ok) return;
58
+
59
+ // Push the new theme files to the API
60
+ const requestUrl = isLiveTheme
61
+ ? `${getRC3Url(args)}configs/msi/?${new URLSearchParams([['merchant_public_id', merchant.public_id]])}`
62
+ : `${getRC3Url(args)}configs/msi/drafts/?${new URLSearchParams([
63
+ ['merchant_public_id', merchant.public_id],
64
+ ['main_theme', selectedTheme.id]
65
+ ])}`;
66
+
67
+ const response = await fetch(requestUrl, {
68
+ method: 'post',
69
+ headers: {
70
+ Authorization: `Bearer ${token}`,
71
+ 'Content-Type': 'application/json'
72
+ },
73
+ body: JSON.stringify(newRequest)
74
+ });
75
+
76
+ if (response.status === 201) {
77
+ console.log('Theme files successfully pushed to the selected theme');
78
+ } else {
79
+ console.error(`Error pushing theme: ${response.status}`, await response.text());
80
+ }
81
+ } catch (error) {
82
+ console.error('Error pushing theme:', error.message);
83
+ }
84
+ }
85
+
86
+ async function fetchOriginalConfig(args, merchant, token, isLiveTheme) {
87
+ if (!isLiveTheme) return null;
88
+
89
+ try {
90
+ const response = await fetch(
91
+ `${getRC3Url(args)}configs/msi/?${new URLSearchParams([['merchant_public_id', merchant.public_id]])}`,
92
+ {
93
+ headers: { Authorization: `Bearer ${token}` }
94
+ }
95
+ );
96
+
97
+ if (response.status === 200) {
98
+ return await response.json().catch(() => ({ configs: {} }));
99
+ } else {
100
+ throw new Error(`Error fetching theme: ${response.status}`);
101
+ }
102
+ } catch (error) {
103
+ console.log(error);
104
+ return null;
105
+ }
106
+ }
107
+
108
+ async function cliPushTheme(args) {
109
+ return await pushTheme(args);
110
+ }
111
+
112
+ exports.cliPushTheme = cliPushTheme;
113
+
114
+ async function getThemeFiles(args) {
115
+ const allowlistDirs = ['views', 'styles', 'scripts', 'locales', 'controls'];
116
+ const files = await glob(`${getcwd(args)}/+(${allowlistDirs.join('|')})/**/*.*`);
117
+ return Promise.all(
118
+ files.map(async file => ({
119
+ name: file.substring(getcwd(args).length),
120
+ content: await fs.promises.readFile(file, 'utf8')
121
+ }))
122
+ );
123
+ }
124
+
125
+ function buildRequestPayload(isLiveTheme, original, fileList, merchant, selectedTheme) {
126
+ if (isLiveTheme) {
127
+ original.configs.smi.files = fileList;
128
+ return original;
129
+ }
130
+
131
+ return {
132
+ configs: { smi: { files: fileList } },
133
+ merchant_public_id: merchant.public_id,
134
+ main_theme: selectedTheme.id
135
+ };
136
+ }
package/src/deploy.js DELETED
@@ -1,143 +0,0 @@
1
- const fs = require('fs');
2
- const fetch = require('node-fetch');
3
- const util = require('util');
4
- const inquirer = require('inquirer');
5
- const glob = util.promisify(require('glob'));
6
- const { getRC3Url } = require('./auth');
7
- const { getcwd, readPackageJson, packageJsonKeys } = require('./utils');
8
- const { getValidSettings } = require('./select-merchant');
9
-
10
- function reportDiffFiles(original, newRequest) {
11
- const originalFiles =
12
- ((original.configs && original.configs.smi && original.configs.smi.files) || []).reduce(
13
- (acc, cur) => ({ ...acc, [cur.name]: cur.content }),
14
- {}
15
- ) || {};
16
-
17
- const newFiles =
18
- ((newRequest.configs && newRequest.configs.smi && newRequest.configs.smi.files) || []).reduce(
19
- (acc, cur) => ({ ...acc, [cur.name]: cur.content }),
20
- {}
21
- ) || {};
22
-
23
- const diff = [...new Set([...Object.keys(newFiles), ...Object.keys(originalFiles)])].filter(
24
- key => newFiles[key] !== originalFiles[key]
25
- );
26
-
27
- if (diff.length === 0) {
28
- console.log('Nothing to push');
29
- return;
30
- }
31
-
32
- const status = name => {
33
- if (originalFiles[name] && newFiles[name]) {
34
- return '[CHANGED]';
35
- }
36
- if (originalFiles[name]) {
37
- return '[REMOVED]';
38
- }
39
- if (newFiles[name]) {
40
- return '[ADDED]';
41
- }
42
- return '';
43
- };
44
-
45
- process.stdout.write(`\
46
- The following changed files will be pushed:
47
- `);
48
-
49
- diff.forEach(name =>
50
- process.stdout.write(`\
51
- - ${name.padEnd(60, '.')} ${status(name)}
52
- `)
53
- );
54
- }
55
- async function deploy(args) {
56
- let { token, merchant } = await getValidSettings(args);
57
-
58
- const ignoreFiles = [
59
- '**/node_modules/**',
60
- 'node_modules/**',
61
- '**/README.md',
62
- '**/package.json',
63
- '**/package-lock.json'
64
- ];
65
-
66
- const files = await glob(`${getcwd(args)}/**/*.*`, { ignore: ignoreFiles });
67
-
68
- const fileList = await Promise.all(
69
- files.map(async file => ({
70
- name: file.substring(getcwd(args).length),
71
- content: await fs.promises.readFile(file, 'utf8')
72
- }))
73
- );
74
-
75
- let original;
76
-
77
- try {
78
- const res = await fetch(
79
- `${getRC3Url(args)}configs/msi/?${new URLSearchParams([['merchant_public_id', merchant.public_id]])}`,
80
- {
81
- headers: { Authorization: `Bearer ${token}` }
82
- }
83
- );
84
- if (res.status === 200) {
85
- original = await res.json().catch(() => ({ configs: {} }));
86
- } else {
87
- original = { configs: {} };
88
- }
89
- } catch (err) {
90
- console.log(err);
91
- }
92
-
93
- const packageJson = readPackageJson(getcwd(args));
94
- const smiTemplatesVersion = packageJson[packageJsonKeys.OG_SECTION]?.[packageJsonKeys.TEMPLATES_VERSION];
95
-
96
- const newRequest = {
97
- ...original,
98
- configs: {
99
- ...original.configs,
100
- smi: {
101
- ...((original.configs && original.configs.smi) || {}),
102
- files: fileList
103
- },
104
- ...(smiTemplatesVersion && { provisioned_with: { '@ordergroove/smi-templates': smiTemplatesVersion } })
105
- }
106
- };
107
-
108
- reportDiffFiles(original, newRequest);
109
-
110
- const { ok } = args.yes
111
- ? { ok: true }
112
- : await inquirer.prompt([
113
- {
114
- type: 'list',
115
- name: 'ok',
116
- message: 'Do you want to proceed?',
117
- choices: [
118
- { value: true, name: `Yes` },
119
- { value: false, name: 'No' }
120
- ]
121
- }
122
- ]);
123
-
124
- if (!ok) return;
125
-
126
- const response = await fetch(
127
- `${getRC3Url(args)}/configs/msi/?${new URLSearchParams([['merchant_public_id', merchant.public_id]])}`,
128
- {
129
- method: 'post',
130
- headers: {
131
- Authorization: `Bearer ${token}`,
132
- 'Content-Type': 'application/json'
133
- },
134
- body: JSON.stringify(newRequest)
135
- }
136
- );
137
- if (response.status === 201) {
138
- console.log('Subscription Manager changes deployed');
139
- } else {
140
- console.error(response.status, await response.text());
141
- }
142
- }
143
- exports.deploy = deploy;