@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 +16 -0
- package/README.md +9 -5
- package/package.json +2 -2
- package/smi-serve.js +8 -9
- package/smi-serve.spec.js +0 -1
- package/src/init.js +1 -2
- package/src/push-theme.js +136 -0
- package/src/deploy.js +0 -143
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
|
|
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
|
-
###
|
|
37
|
+
### pull-theme
|
|
38
38
|
|
|
39
|
-
|
|
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
|
|
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.
|
|
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": "
|
|
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 {
|
|
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
|
-
|
|
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
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;
|