climaybe 2.4.2 → 3.0.0
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 +25 -26
- package/bin/version.txt +1 -1
- package/package.json +9 -1
- package/src/commands/add-dev-kit.js +5 -3
- package/src/commands/add-store.js +22 -7
- package/src/commands/app-init.js +1 -1
- package/src/commands/build-scripts.js +27 -0
- package/src/commands/create-entrypoints.js +45 -0
- package/src/commands/init.js +52 -18
- package/src/commands/migrate-legacy-config.js +217 -0
- package/src/index.js +37 -2
- package/src/lib/build-scripts.js +153 -0
- package/src/lib/build-workflows.js +3 -43
- package/src/lib/config.js +78 -8
- package/src/lib/dev-runtime.js +188 -0
- package/src/lib/prompts.js +29 -6
- package/src/lib/shopify-cli.js +30 -0
- package/src/lib/theme-dev-kit.js +33 -51
- package/src/lib/watch.js +80 -0
- package/src/lib/workflows.js +2 -4
- package/src/workflows/build/create-release.yml +23 -6
- package/src/workflows/build/reusable-build.yml +26 -5
- package/src/workflows/multi/main-to-staging-stores.yml +4 -3
- package/src/workflows/multi/multistore-hotfix-to-main.yml +3 -3
- package/src/workflows/multi/pr-to-live.yml +3 -3
- package/src/workflows/preview/pr-close.yml +4 -4
- package/src/workflows/preview/pr-update.yml +4 -4
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import pc from 'picocolors';
|
|
3
|
+
|
|
4
|
+
function spawnInherit(cmd, args, { cwd = process.cwd(), name = cmd } = {}) {
|
|
5
|
+
const child = spawn(cmd, args, {
|
|
6
|
+
cwd,
|
|
7
|
+
stdio: 'inherit',
|
|
8
|
+
shell: process.platform === 'win32',
|
|
9
|
+
});
|
|
10
|
+
child.on('exit', (code) => {
|
|
11
|
+
if (code && code !== 0) {
|
|
12
|
+
console.log(pc.red(`\n ${name} exited with code ${code}\n`));
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
return child;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Run Shopify CLI, falling back to npx when `shopify` isn't available.
|
|
20
|
+
* @param {string[]} args e.g. ['theme','check']
|
|
21
|
+
*/
|
|
22
|
+
export function runShopify(args, { cwd = process.cwd(), name = 'shopify' } = {}) {
|
|
23
|
+
const child = spawnInherit('shopify', args, { cwd, name });
|
|
24
|
+
child.on('error', (err) => {
|
|
25
|
+
if (err?.code !== 'ENOENT') return;
|
|
26
|
+
spawnInherit('npx', ['-y', '@shopify/cli@latest', ...args], { cwd, name: 'shopify(npx)' });
|
|
27
|
+
});
|
|
28
|
+
return child;
|
|
29
|
+
}
|
|
30
|
+
|
package/src/lib/theme-dev-kit.js
CHANGED
|
@@ -1,21 +1,8 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { join, dirname } from 'node:path';
|
|
3
|
-
import { readPkg, writePkg } from './config.js';
|
|
3
|
+
import { readPkg, writePkg, writeClimaybeConfig } from './config.js';
|
|
4
4
|
|
|
5
5
|
const DEV_KIT_FILES = {
|
|
6
|
-
'nodemon.json': `{
|
|
7
|
-
"watch": ["_scripts"],
|
|
8
|
-
"ext": "js",
|
|
9
|
-
"exec": "npm run scripts:build --silent",
|
|
10
|
-
"quiet": true,
|
|
11
|
-
"no-colours": true,
|
|
12
|
-
"ignore": ["node_modules/**/*", "assets/**/*", "**/*.min.js"],
|
|
13
|
-
"delay": "500",
|
|
14
|
-
"polling": false,
|
|
15
|
-
"legacyWatch": false,
|
|
16
|
-
"restartable": "rs"
|
|
17
|
-
}
|
|
18
|
-
`,
|
|
19
6
|
'.theme-check.yml': `root: .
|
|
20
7
|
|
|
21
8
|
extends: :nothing
|
|
@@ -80,7 +67,7 @@ const VSCODE_TASKS_CONTENT = `{
|
|
|
80
67
|
{
|
|
81
68
|
"label": "Shopify",
|
|
82
69
|
"type": "shell",
|
|
83
|
-
"command": "
|
|
70
|
+
"command": "climaybe serve:shopify",
|
|
84
71
|
"isBackground": true,
|
|
85
72
|
"presentation": {
|
|
86
73
|
"echo": true,
|
|
@@ -96,7 +83,7 @@ const VSCODE_TASKS_CONTENT = `{
|
|
|
96
83
|
{
|
|
97
84
|
"label": "Tailwind",
|
|
98
85
|
"type": "shell",
|
|
99
|
-
"command": "
|
|
86
|
+
"command": "climaybe serve:assets",
|
|
100
87
|
"isBackground": true,
|
|
101
88
|
"presentation": {
|
|
102
89
|
"echo": true,
|
|
@@ -128,33 +115,6 @@ assets/index.js
|
|
|
128
115
|
.vercel
|
|
129
116
|
`;
|
|
130
117
|
|
|
131
|
-
const PACKAGE_MERGES = {
|
|
132
|
-
scripts: {
|
|
133
|
-
'shopify:serve': 'shopify theme dev --theme-editor-sync --store=$npm_package_config_store',
|
|
134
|
-
'shopify:populate': 'shopify populate --store=$npm_package_config_store',
|
|
135
|
-
'scripts:build': 'node build-scripts.js',
|
|
136
|
-
'scripts:watch': 'nodemon',
|
|
137
|
-
'tailwind:watch':
|
|
138
|
-
`concurrently --kill-others --max-restarts 3 "NODE_ENV=production NODE_OPTIONS='--max-old-space-size=512' ` +
|
|
139
|
-
`npx @tailwindcss/cli -i _styles/main.css -o assets/style.css --watch" "NODE_OPTIONS='--max-old-space-size=256' ` +
|
|
140
|
-
`npm run scripts:watch" "npx -y @shopify/dev-mcp@latest"`,
|
|
141
|
-
'tailwind:build': 'NODE_ENV=production npx @tailwindcss/cli -i _styles/main.css -o assets/style.css --minify && npm run scripts:build',
|
|
142
|
-
'lint:liquid': 'shopify theme check',
|
|
143
|
-
'lint:js': 'eslint ./assets/*.js --config .config/eslint.config.mjs',
|
|
144
|
-
'lint:css': 'node_modules/.bin/stylelint ./assets/*.css --config .config/.stylelintrc.json',
|
|
145
|
-
release: 'node .sys/scripts/release.js',
|
|
146
|
-
},
|
|
147
|
-
devDependencies: {
|
|
148
|
-
'@shopify/prettier-plugin-liquid': '^1.6.3',
|
|
149
|
-
'@tailwindcss/cli': '^4.1.17',
|
|
150
|
-
concurrently: '^8.2.2',
|
|
151
|
-
nodemon: '^3.0.2',
|
|
152
|
-
prettier: '^3.4.2',
|
|
153
|
-
stylelint: '^16.9.0',
|
|
154
|
-
eslint: '^9.11.0',
|
|
155
|
-
},
|
|
156
|
-
};
|
|
157
|
-
|
|
158
118
|
function ensureParent(path) {
|
|
159
119
|
mkdirSync(dirname(path), { recursive: true });
|
|
160
120
|
}
|
|
@@ -171,12 +131,16 @@ function mergeGitignore(cwd = process.cwd()) {
|
|
|
171
131
|
writeFileSync(path, `${next}\n`, 'utf-8');
|
|
172
132
|
}
|
|
173
133
|
|
|
174
|
-
function mergePackageJson(
|
|
175
|
-
const pkg = readPkg(cwd) || { name:
|
|
176
|
-
pkg.
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
134
|
+
function mergePackageJson({ packageName = 'shopify-theme', cwd = process.cwd() } = {}) {
|
|
135
|
+
const pkg = readPkg(cwd) || { name: packageName, version: '1.0.0', private: true };
|
|
136
|
+
pkg.devDependencies = { ...(pkg.devDependencies || {}) };
|
|
137
|
+
|
|
138
|
+
// Ensure teammates can run climaybe + Tailwind after plain npm install.
|
|
139
|
+
const cliVersion = process.env.CLIMAYBE_PACKAGE_VERSION;
|
|
140
|
+
const climaybeRange = /^\d+\.\d+\.\d+/.test(String(cliVersion || '')) ? `^${cliVersion}` : 'latest';
|
|
141
|
+
if (!pkg.devDependencies.climaybe) pkg.devDependencies.climaybe = climaybeRange;
|
|
142
|
+
if (!pkg.devDependencies.tailwindcss) pkg.devDependencies.tailwindcss = 'latest';
|
|
143
|
+
|
|
180
144
|
writePkg(pkg, cwd);
|
|
181
145
|
}
|
|
182
146
|
|
|
@@ -186,7 +150,12 @@ export function getDevKitExistingFiles({ includeVSCodeTasks = true, cwd = proces
|
|
|
186
150
|
return paths.filter((p) => existsSync(join(cwd, p)));
|
|
187
151
|
}
|
|
188
152
|
|
|
189
|
-
export function scaffoldThemeDevKit({
|
|
153
|
+
export function scaffoldThemeDevKit({
|
|
154
|
+
includeVSCodeTasks = true,
|
|
155
|
+
defaultStoreDomain = '',
|
|
156
|
+
packageName = 'shopify-theme',
|
|
157
|
+
cwd = process.cwd(),
|
|
158
|
+
} = {}) {
|
|
190
159
|
for (const [rel, content] of Object.entries(DEV_KIT_FILES)) {
|
|
191
160
|
const dest = join(cwd, rel);
|
|
192
161
|
ensureParent(dest);
|
|
@@ -198,5 +167,18 @@ export function scaffoldThemeDevKit({ includeVSCodeTasks = true, defaultStoreDom
|
|
|
198
167
|
writeFileSync(dest, VSCODE_TASKS_CONTENT, 'utf-8');
|
|
199
168
|
}
|
|
200
169
|
mergeGitignore(cwd);
|
|
201
|
-
mergePackageJson(
|
|
170
|
+
mergePackageJson({ packageName, cwd });
|
|
171
|
+
|
|
172
|
+
// New source-of-truth config file for climaybe (local dev + CI).
|
|
173
|
+
// We intentionally keep package.json changes minimal (no script injection).
|
|
174
|
+
writeClimaybeConfig(
|
|
175
|
+
{
|
|
176
|
+
port: 9295,
|
|
177
|
+
default_store: defaultStoreDomain || undefined,
|
|
178
|
+
dev_kit: true,
|
|
179
|
+
vscode_tasks: includeVSCodeTasks,
|
|
180
|
+
project_type: 'theme',
|
|
181
|
+
},
|
|
182
|
+
cwd
|
|
183
|
+
);
|
|
202
184
|
}
|
package/src/lib/watch.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { existsSync, readdirSync, watch } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
function debounce(fn, ms) {
|
|
5
|
+
let t = null;
|
|
6
|
+
return (...args) => {
|
|
7
|
+
if (t) clearTimeout(t);
|
|
8
|
+
t = setTimeout(() => fn(...args), ms);
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function listDirsRecursively(rootDir) {
|
|
13
|
+
const dirs = [];
|
|
14
|
+
if (!existsSync(rootDir)) return dirs;
|
|
15
|
+
|
|
16
|
+
const stack = [rootDir];
|
|
17
|
+
while (stack.length) {
|
|
18
|
+
const dir = stack.pop();
|
|
19
|
+
dirs.push(dir);
|
|
20
|
+
let entries = [];
|
|
21
|
+
try {
|
|
22
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
23
|
+
} catch {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
for (const e of entries) {
|
|
27
|
+
if (!e.isDirectory()) continue;
|
|
28
|
+
const full = join(dir, e.name);
|
|
29
|
+
stack.push(full);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return dirs;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function watchTree({ rootDir, ignore = () => false, onChange, debounceMs = 300 } = {}) {
|
|
36
|
+
if (!rootDir) throw new Error('watchTree: rootDir is required');
|
|
37
|
+
if (typeof onChange !== 'function') throw new Error('watchTree: onChange is required');
|
|
38
|
+
if (!existsSync(rootDir)) return { close: () => {} };
|
|
39
|
+
|
|
40
|
+
const watchers = new Map();
|
|
41
|
+
const debounced = debounce(onChange, debounceMs);
|
|
42
|
+
|
|
43
|
+
function ensureWatched(dir) {
|
|
44
|
+
if (watchers.has(dir)) return;
|
|
45
|
+
try {
|
|
46
|
+
const w = watch(dir, { persistent: true }, (eventType, filename) => {
|
|
47
|
+
const name = typeof filename === 'string' ? filename : '';
|
|
48
|
+
const full = name ? join(dir, name) : dir;
|
|
49
|
+
if (ignore(full)) return;
|
|
50
|
+
debounced(full, eventType);
|
|
51
|
+
// Best-effort: new dirs can appear; rescan on any event.
|
|
52
|
+
rescan();
|
|
53
|
+
});
|
|
54
|
+
watchers.set(dir, w);
|
|
55
|
+
} catch {
|
|
56
|
+
// ignore unwatcheable dirs
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function rescan() {
|
|
61
|
+
const dirs = listDirsRecursively(rootDir);
|
|
62
|
+
for (const d of dirs) ensureWatched(d);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
rescan();
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
close() {
|
|
69
|
+
for (const w of watchers.values()) {
|
|
70
|
+
try {
|
|
71
|
+
w.close();
|
|
72
|
+
} catch {
|
|
73
|
+
// ignore
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
watchers.clear();
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
package/src/lib/workflows.js
CHANGED
|
@@ -2,7 +2,7 @@ import { existsSync, mkdirSync, readdirSync, copyFileSync, rmSync } from 'node:f
|
|
|
2
2
|
import { join, dirname } from 'node:path';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import pc from 'picocolors';
|
|
5
|
-
import {
|
|
5
|
+
import { ensureBuildWorkflowDefaults } from './build-workflows.js';
|
|
6
6
|
|
|
7
7
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
8
|
const TEMPLATES_DIR = join(__dirname, '..', 'workflows');
|
|
@@ -110,9 +110,7 @@ export function scaffoldWorkflows(mode = 'single', options = {}, cwd = process.c
|
|
|
110
110
|
for (const f of listYmls(buildDir)) {
|
|
111
111
|
copyWorkflow(buildDir, f, dest);
|
|
112
112
|
}
|
|
113
|
-
|
|
114
|
-
} else {
|
|
115
|
-
removeBuildScript(cwd);
|
|
113
|
+
ensureBuildWorkflowDefaults(cwd);
|
|
116
114
|
}
|
|
117
115
|
|
|
118
116
|
const total = readdirSync(dest).filter((f) => f.endsWith('.yml')).length;
|
|
@@ -119,9 +119,18 @@ jobs:
|
|
|
119
119
|
COMMITS=$(git log --pretty=format:"%s" -n 30 "$TAG_NAME" 2>/dev/null || true)
|
|
120
120
|
fi
|
|
121
121
|
|
|
122
|
+
# Filter out noisy system-generated sync/merge commits so release notes stay readable.
|
|
123
|
+
FILTERED_COMMITS=$(printf '%s\n' "$COMMITS" | sed '/^[[:space:]]*$/d' | grep -Eiv \
|
|
124
|
+
'^Sync main → staging-|^Sync main -> staging-|^Merge pull request #|^Merge branch |^Merge live-.* into main \[hotfix-backport\]$|^chore: sync root to stores/.+ \[root-to-stores\]$|^chore: keep store root JSONs from stores/.+ \[stores-to-root\]$|^Update from Shopify for theme ')
|
|
125
|
+
if [ -z "$FILTERED_COMMITS" ]; then
|
|
126
|
+
NOISY_ONLY_COMMITS=true
|
|
127
|
+
else
|
|
128
|
+
NOISY_ONLY_COMMITS=false
|
|
129
|
+
fi
|
|
130
|
+
|
|
122
131
|
# Score how many commit subjects follow conventional-commit style.
|
|
123
|
-
TOTAL_COUNT=$(printf '%s\n' "$
|
|
124
|
-
CONVENTIONAL_COUNT=$(printf '%s\n' "$
|
|
132
|
+
TOTAL_COUNT=$(printf '%s\n' "$FILTERED_COMMITS" | sed '/^[[:space:]]*$/d' | wc -l | tr -d ' ')
|
|
133
|
+
CONVENTIONAL_COUNT=$(printf '%s\n' "$FILTERED_COMMITS" | sed '/^[[:space:]]*$/d' | grep -Eic '^(feat|fix|refactor|perf|docs|style|test|build|ci|chore|revert)(\([^)]+\))?!?: ')
|
|
125
134
|
if [ -z "$TOTAL_COUNT" ] || [ "$TOTAL_COUNT" -eq 0 ]; then
|
|
126
135
|
TOTAL_COUNT=1
|
|
127
136
|
fi
|
|
@@ -139,8 +148,8 @@ jobs:
|
|
|
139
148
|
} > "$NOTES_FILE"
|
|
140
149
|
|
|
141
150
|
# If commit quality is low and Gemini is available, ask AI to summarize merchant-facing notes.
|
|
142
|
-
if [ "$QUALITY" -lt 50 ] && [ -n "$GEMINI_API_KEY" ]; then
|
|
143
|
-
printf '%s\n' "$
|
|
151
|
+
if [ "$QUALITY" -lt 50 ] && [ -n "$GEMINI_API_KEY" ] && [ "$NOISY_ONLY_COMMITS" != "true" ]; then
|
|
152
|
+
printf '%s\n' "$FILTERED_COMMITS" > .sys/release-notes/commits-for-ai.txt
|
|
144
153
|
|
|
145
154
|
PROMPT=$(cat <<'PROMPT_EOF'
|
|
146
155
|
You generate release notes for a Shopify theme.
|
|
@@ -182,12 +191,20 @@ jobs:
|
|
|
182
191
|
else
|
|
183
192
|
echo "## Changes" >> "$NOTES_FILE"
|
|
184
193
|
echo >> "$NOTES_FILE"
|
|
185
|
-
|
|
194
|
+
if [ "$NOISY_ONLY_COMMITS" = "true" ]; then
|
|
195
|
+
echo "- No notable merchant-facing changes in this release." >> "$NOTES_FILE"
|
|
196
|
+
else
|
|
197
|
+
printf '%s\n' "$FILTERED_COMMITS" | sed '/^[[:space:]]*$/d' | sed 's/^/- /' >> "$NOTES_FILE"
|
|
198
|
+
fi
|
|
186
199
|
fi
|
|
187
200
|
else
|
|
188
201
|
echo "## Changes" >> "$NOTES_FILE"
|
|
189
202
|
echo >> "$NOTES_FILE"
|
|
190
|
-
|
|
203
|
+
if [ "$NOISY_ONLY_COMMITS" = "true" ]; then
|
|
204
|
+
echo "- No notable merchant-facing changes in this release." >> "$NOTES_FILE"
|
|
205
|
+
else
|
|
206
|
+
printf '%s\n' "$FILTERED_COMMITS" | sed '/^[[:space:]]*$/d' | sed 's/^/- /' >> "$NOTES_FILE"
|
|
207
|
+
fi
|
|
191
208
|
fi
|
|
192
209
|
|
|
193
210
|
echo "notes_file=$NOTES_FILE" >> $GITHUB_OUTPUT
|
|
@@ -24,16 +24,32 @@ jobs:
|
|
|
24
24
|
node-version: "24"
|
|
25
25
|
cache: "npm"
|
|
26
26
|
|
|
27
|
-
- name:
|
|
28
|
-
|
|
27
|
+
- name: Detect build entrypoints
|
|
28
|
+
id: detect
|
|
29
|
+
run: |
|
|
30
|
+
HAS_SCRIPTS=false
|
|
31
|
+
if ls _scripts/*.js >/dev/null 2>&1; then
|
|
32
|
+
HAS_SCRIPTS=true
|
|
33
|
+
fi
|
|
34
|
+
HAS_STYLES=false
|
|
35
|
+
if [ -f "_styles/main.css" ]; then
|
|
36
|
+
HAS_STYLES=true
|
|
37
|
+
fi
|
|
38
|
+
echo "has_scripts=$HAS_SCRIPTS" >> $GITHUB_OUTPUT
|
|
39
|
+
echo "has_styles=$HAS_STYLES" >> $GITHUB_OUTPUT
|
|
29
40
|
|
|
30
41
|
- name: Build scripts
|
|
31
|
-
|
|
42
|
+
if: steps.detect.outputs.has_scripts == 'true'
|
|
43
|
+
run: npx -y climaybe@latest build-scripts
|
|
32
44
|
|
|
33
45
|
- name: Run Tailwind build
|
|
34
46
|
id: build
|
|
35
47
|
run: |
|
|
36
|
-
|
|
48
|
+
if [ "${{ steps.detect.outputs.has_styles }}" = "true" ]; then
|
|
49
|
+
NODE_ENV=production npx -y climaybe@latest build
|
|
50
|
+
else
|
|
51
|
+
echo "No _styles/main.css found; skipping Tailwind build."
|
|
52
|
+
fi
|
|
37
53
|
echo "success=true" >> $GITHUB_OUTPUT
|
|
38
54
|
|
|
39
55
|
- name: Commit and push changes
|
|
@@ -43,7 +59,12 @@ jobs:
|
|
|
43
59
|
BRANCH_NAME=${{ github.head_ref || github.ref_name }}
|
|
44
60
|
git fetch origin "$BRANCH_NAME" || echo "Branch does not exist yet"
|
|
45
61
|
git checkout -B "$BRANCH_NAME" "origin/$BRANCH_NAME" 2>/dev/null || git checkout -B "$BRANCH_NAME"
|
|
46
|
-
|
|
62
|
+
if ls assets/*.js >/dev/null 2>&1; then
|
|
63
|
+
git add -f assets/*.js
|
|
64
|
+
fi
|
|
65
|
+
if [ -f "assets/style.css" ]; then
|
|
66
|
+
git add -f assets/style.css
|
|
67
|
+
fi
|
|
47
68
|
if git diff --staged --quiet; then
|
|
48
69
|
echo "No changes to commit"
|
|
49
70
|
else
|
|
@@ -68,7 +68,7 @@ jobs:
|
|
|
68
68
|
fi
|
|
69
69
|
echo "hotfix_skip_alias=$HOTFIX_SKIP_ALIAS" >> $GITHUB_OUTPUT
|
|
70
70
|
|
|
71
|
-
# Read store list from
|
|
71
|
+
# Read store list from climaybe.config.json
|
|
72
72
|
config:
|
|
73
73
|
needs: gate
|
|
74
74
|
if: needs.gate.outputs.should_run == 'true'
|
|
@@ -82,8 +82,9 @@ jobs:
|
|
|
82
82
|
id: read
|
|
83
83
|
run: |
|
|
84
84
|
STORES=$(node -e "
|
|
85
|
-
const
|
|
86
|
-
const
|
|
85
|
+
const fs = require('fs');
|
|
86
|
+
const cfg = JSON.parse(fs.readFileSync('./climaybe.config.json', 'utf8'));
|
|
87
|
+
const stores = Object.keys(cfg?.stores || {});
|
|
87
88
|
console.log(JSON.stringify(stores));
|
|
88
89
|
")
|
|
89
90
|
echo "stores=$STORES" >> $GITHUB_OUTPUT
|
|
@@ -48,9 +48,9 @@ jobs:
|
|
|
48
48
|
run: |
|
|
49
49
|
DEFAULT_ALIAS=$(node -e "
|
|
50
50
|
const fs = require('fs');
|
|
51
|
-
const
|
|
52
|
-
const stores =
|
|
53
|
-
const defaultStoreRaw =
|
|
51
|
+
const cfg = JSON.parse(fs.readFileSync('./climaybe.config.json', 'utf8'));
|
|
52
|
+
const stores = cfg?.stores || {};
|
|
53
|
+
const defaultStoreRaw = cfg?.default_store;
|
|
54
54
|
const normalize = (v) => String(v || '').toLowerCase().replace(/^https?:\\/\\//, '').replace(/\/.*\$/, '');
|
|
55
55
|
const defaultStore = normalize(defaultStoreRaw);
|
|
56
56
|
let alias = '';
|
|
@@ -47,7 +47,7 @@ jobs:
|
|
|
47
47
|
echo "staging_branch=$BRANCH" >> $GITHUB_OUTPUT
|
|
48
48
|
echo "live_branch=live-${ALIAS}" >> $GITHUB_OUTPUT
|
|
49
49
|
|
|
50
|
-
- name: Resolve store domain from
|
|
50
|
+
- name: Resolve store domain from climaybe.config.json
|
|
51
51
|
id: store
|
|
52
52
|
env:
|
|
53
53
|
SHOPIFY_STORE_URL_SCOPED: ${{ secrets[format('SHOPIFY_STORE_URL_{0}', steps.alias.outputs.alias_secret)] }}
|
|
@@ -56,8 +56,8 @@ jobs:
|
|
|
56
56
|
ALIAS="${{ steps.alias.outputs.alias }}"
|
|
57
57
|
DOMAIN_CONFIG=$(node -e "
|
|
58
58
|
const fs = require('fs');
|
|
59
|
-
const
|
|
60
|
-
const domain =
|
|
59
|
+
const cfg = JSON.parse(fs.readFileSync('./climaybe.config.json', 'utf8'));
|
|
60
|
+
const domain = cfg?.stores?.['${ALIAS}'] || '';
|
|
61
61
|
process.stdout.write(domain);
|
|
62
62
|
")
|
|
63
63
|
DOMAIN="${SHOPIFY_STORE_URL_SCOPED:-}"
|
|
@@ -31,9 +31,9 @@ jobs:
|
|
|
31
31
|
else
|
|
32
32
|
ALIAS=$(node -e "
|
|
33
33
|
const fs = require('fs');
|
|
34
|
-
const
|
|
35
|
-
const stores =
|
|
36
|
-
const defaultStoreRaw =
|
|
34
|
+
const cfg = JSON.parse(fs.readFileSync('./climaybe.config.json', 'utf8'));
|
|
35
|
+
const stores = cfg?.stores || {};
|
|
36
|
+
const defaultStoreRaw = cfg?.default_store;
|
|
37
37
|
const normalize = (v) => String(v || '')
|
|
38
38
|
.toLowerCase()
|
|
39
39
|
.replace(/^https?:\\/\\//, '')
|
|
@@ -63,7 +63,7 @@ jobs:
|
|
|
63
63
|
fi
|
|
64
64
|
|
|
65
65
|
if [ -z "$ALIAS" ]; then
|
|
66
|
-
echo "Could not resolve store alias from
|
|
66
|
+
echo "Could not resolve store alias from climaybe.config.json config or base branch."
|
|
67
67
|
exit 1
|
|
68
68
|
fi
|
|
69
69
|
|
|
@@ -34,9 +34,9 @@ jobs:
|
|
|
34
34
|
else
|
|
35
35
|
ALIAS=$(node -e "
|
|
36
36
|
const fs = require('fs');
|
|
37
|
-
const
|
|
38
|
-
const stores =
|
|
39
|
-
const defaultStoreRaw =
|
|
37
|
+
const cfg = JSON.parse(fs.readFileSync('./climaybe.config.json', 'utf8'));
|
|
38
|
+
const stores = cfg?.stores || {};
|
|
39
|
+
const defaultStoreRaw = cfg?.default_store;
|
|
40
40
|
const normalize = (v) => String(v || '')
|
|
41
41
|
.toLowerCase()
|
|
42
42
|
.replace(/^https?:\\/\\//, '')
|
|
@@ -66,7 +66,7 @@ jobs:
|
|
|
66
66
|
fi
|
|
67
67
|
|
|
68
68
|
if [ -z "$ALIAS" ]; then
|
|
69
|
-
echo "Could not resolve default store alias from
|
|
69
|
+
echo "Could not resolve default store alias from climaybe.config.json config."
|
|
70
70
|
exit 1
|
|
71
71
|
fi
|
|
72
72
|
|