climaybe 2.2.4 → 2.3.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
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Shopify CLI for **theme CI/CD** (GitHub Actions, branches, multi-store config) and light **app repo** setup. Same install works in theme or app repositories.
|
|
4
4
|
|
|
5
|
+
Built by [Electric Maybe](https://electricmaybe.com) — a Shopify-focused product and development studio.
|
|
6
|
+
|
|
5
7
|
**Commit linting and Cursor bundle (optional in both flows):**
|
|
6
8
|
|
|
7
9
|
- **Conventional commit linting:** During `climaybe theme init` or `climaybe app init`, you can install [commitlint](https://commitlint.js.org/) and [Husky](https://typicode.github.io/husky) for [Conventional Commits](https://www.conventionalcommits.org/).
|
|
@@ -209,7 +211,7 @@ Direct pushes to `staging-<store>` or `live-<store>` are automatically synced ba
|
|
|
209
211
|
|
|
210
212
|
| Workflow | Trigger | What it does |
|
|
211
213
|
|----------|---------|-------------|
|
|
212
|
-
| `main-to-staging-stores.yml` (main-to-staging-<store>) | Push to `main` | Merges main into each `staging-<alias>`; root JSONs ignored. For hotfix-backport
|
|
214
|
+
| `main-to-staging-stores.yml` (main-to-staging-<store>) | Push to `main` | Merges main into each `staging-<alias>`; root JSONs ignored. For hotfix-backport: if source is `staging-<alias>`, that same staging branch is skipped; if source is `live-<alias>`, `staging-<alias>` is also synced. Skips only on pure store-sync. |
|
|
213
215
|
| `stores-to-root.yml` | Push to `staging-*` | From main merge: stores→root. From elsewhere (e.g. Shopify): root→stores |
|
|
214
216
|
| `pr-to-live.yml` | After stores-to-root | Opens PR from `staging-<alias>` to `live-<alias>` |
|
|
215
217
|
| `root-to-stores.yml` | Push to `live-*` | From main merge: stores→root. From elsewhere: root→stores (same as stores-to-root on staging-*) |
|
|
@@ -268,7 +270,7 @@ You can install/update this later with:
|
|
|
268
270
|
- **No tags yet?** The system uses `theme_version` from `config/settings_schema.json` (`theme_info`), creates that tag on main (e.g. `v1.0.0`), and continues from there.
|
|
269
271
|
- **Staging → main**: On PR, a pre-release patch tag (e.g. v3.1.13) locks the current minor line; on merge, **minor** bump (e.g. v3.1.13 → v3.2.0).
|
|
270
272
|
- **Non-staging to main** (hotfix backports, direct commits): **Patch** bump only, via **nightly workflow** at 02:00 US Eastern (not at commit time).
|
|
271
|
-
- **Version bump runs only on main** (post-merge-tag and nightly-hotfix). Main-to-staging-stores merges main into each `staging-<alias>` on every push (version bumps and hotfixes).
|
|
273
|
+
- **Version bump runs only on main** (post-merge-tag and nightly-hotfix). Main-to-staging-stores merges main into each `staging-<alias>` on every push (version bumps and hotfixes). For hotfix-backport, only a `staging-<alias> -> main` source skips syncing back to the same staging branch; a `live-<alias> -> main` source still syncs into `staging-<alias>`.
|
|
272
274
|
- Version bumps update `config/settings_schema.json` and, when present, `package.json` `version`.
|
|
273
275
|
- **Safety**: The version-bump workflow fails if the new tag would not be **strictly higher** than the latest merged release tag (semver), so the release line cannot step backward.
|
|
274
276
|
|
|
@@ -336,7 +338,7 @@ Add the following secrets to your GitHub repository (or use **GitLab CI/CD varia
|
|
|
336
338
|
|
|
337
339
|
- **Branch:** Single default branch `main`. Feature branches open as PRs into `main`.
|
|
338
340
|
- **Versioning:** [SemVer](https://semver.org/). Versions are **bumped automatically** when PRs are merged to `main` using [conventional commits](https://www.conventionalcommits.org/): `fix:` → patch, `feat:` → minor, `BREAKING CHANGE` or `feat!:` → major.
|
|
339
|
-
- **Flow:** Merge to `main` → [Release version](.github/workflows/release-version.yml) runs semantic-release (bumps `package.json`, publishes to npm, pushes tag). Optional: tag push runs [Verify release tag](.github/workflows/verify-release-tag.yml) for an extra test pass and tag vs `package.json` check (no publish). Prefer [npm Trusted Publisher](https://docs.npmjs.com/trusted-publishers) (workflow file `release-version.yml`) so no long-lived `NPM_TOKEN` is needed for CI; see [CONTRIBUTING.md](CONTRIBUTING.md). Do not create tags manually; only the Release version workflow creates tags so that tag and package version stay in sync.
|
|
341
|
+
- **Flow:** Merge to `main` → [Release version](.github/workflows/release-version.yml) runs semantic-release (bumps `package.json`, creates GitHub Release notes, publishes to npm, pushes tag). Optional: tag push runs [Verify release tag](.github/workflows/verify-release-tag.yml) for an extra test pass and tag vs `package.json` check (no publish). We publish to **npmjs.com** only (not GitHub Packages). Prefer [npm Trusted Publisher](https://docs.npmjs.com/trusted-publishers) (workflow file `release-version.yml`) so no long-lived `NPM_TOKEN` is needed for CI; see [CONTRIBUTING.md](CONTRIBUTING.md). Do not create tags manually; only the Release version workflow creates tags so that tag and package version stay in sync.
|
|
340
342
|
- **CI:** Every PR and push to `main` runs tests on Node 20 and 22 ([CI workflow](.github/workflows/ci.yml)).
|
|
341
343
|
|
|
342
344
|
See [CONTRIBUTING.md](CONTRIBUTING.md) for branch, PR, and conventional-commit details.
|
package/bin/version.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.
|
|
1
|
+
2.3.0
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "climaybe",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "Shopify CLI
|
|
3
|
+
"version": "2.3.0",
|
|
4
|
+
"description": "Shopify CLI by Electric Maybe for theme CI/CD workflows, branch orchestration, app setup, and dev tooling",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"climaybe": "bin/cli.js"
|
|
@@ -15,20 +15,23 @@
|
|
|
15
15
|
},
|
|
16
16
|
"keywords": [
|
|
17
17
|
"shopify",
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"theme",
|
|
21
|
-
"
|
|
22
|
-
"github-actions"
|
|
18
|
+
"shopify-cli",
|
|
19
|
+
"shopify-theme",
|
|
20
|
+
"theme-development",
|
|
21
|
+
"ci-cd",
|
|
22
|
+
"github-actions",
|
|
23
|
+
"workflow-automation",
|
|
24
|
+
"release-automation",
|
|
25
|
+
"electric-maybe"
|
|
23
26
|
],
|
|
24
|
-
"author": "Electric Maybe",
|
|
27
|
+
"author": "Electric Maybe (https://electricmaybe.com)",
|
|
25
28
|
"license": "MIT",
|
|
26
29
|
"repository": {
|
|
27
30
|
"type": "git",
|
|
28
31
|
"url": "git+https://github.com/electricmaybe/climaybe.git"
|
|
29
32
|
},
|
|
30
33
|
"bugs": "https://github.com/electricmaybe/climaybe/issues",
|
|
31
|
-
"homepage": "https://
|
|
34
|
+
"homepage": "https://electricmaybe.com",
|
|
32
35
|
"publishConfig": {
|
|
33
36
|
"access": "public",
|
|
34
37
|
"provenance": true
|
|
@@ -60,6 +63,7 @@
|
|
|
60
63
|
}
|
|
61
64
|
],
|
|
62
65
|
"@semantic-release/release-notes-generator",
|
|
66
|
+
"@semantic-release/github",
|
|
63
67
|
"@semantic-release/npm",
|
|
64
68
|
[
|
|
65
69
|
"@semantic-release/git",
|
|
@@ -82,6 +86,7 @@
|
|
|
82
86
|
"@commitlint/cli": "^20.4.4",
|
|
83
87
|
"@commitlint/config-conventional": "^20.4.4",
|
|
84
88
|
"@semantic-release/git": "^10.0.1",
|
|
89
|
+
"@semantic-release/github": "^11.0.6",
|
|
85
90
|
"@semantic-release/npm": "^13.1.5",
|
|
86
91
|
"husky": "^9.1.7",
|
|
87
92
|
"semantic-release": "^25.0.3"
|
|
@@ -3,12 +3,16 @@ const path = require('path');
|
|
|
3
3
|
const ROOT_DIR = process.cwd();
|
|
4
4
|
|
|
5
5
|
function extractImports(content) {
|
|
6
|
-
const importRegex = /^\s*import\s+(?:[^'"\n;]+?\s+from\s+)?['"]([^'"]+)['"]\s*;?\s*$/gm;
|
|
7
6
|
const imports = [];
|
|
7
|
+
const fromImportRegex = /(^|\n)\s*import\s+[\s\S]*?\s+from\s+['"]([^'"]+)['"]\s*;?/g;
|
|
8
|
+
const sideEffectImportRegex = /(^|\n)\s*import\s+['"]([^'"]+)['"]\s*;?/g;
|
|
8
9
|
let match;
|
|
9
10
|
|
|
10
|
-
while ((match =
|
|
11
|
-
imports.push(match[
|
|
11
|
+
while ((match = fromImportRegex.exec(content)) !== null) {
|
|
12
|
+
imports.push(match[2]);
|
|
13
|
+
}
|
|
14
|
+
while ((match = sideEffectImportRegex.exec(content)) !== null) {
|
|
15
|
+
imports.push(match[2]);
|
|
12
16
|
}
|
|
13
17
|
|
|
14
18
|
return imports;
|
|
@@ -36,7 +40,12 @@ function processScriptFile(filePath, processedFiles = new Set()) {
|
|
|
36
40
|
importedContent += processScriptFile(importPath, processedFiles);
|
|
37
41
|
}
|
|
38
42
|
|
|
39
|
-
|
|
43
|
+
// Remove import statements (including multiline "import { ... } from '...'" forms).
|
|
44
|
+
content = content.replace(/(^|\n)\s*import\s+[\s\S]*?\s+from\s+['"][^'"]+['"]\s*;?/g, '$1');
|
|
45
|
+
content = content.replace(/(^|\n)\s*import\s+['"][^'"]+['"]\s*;?/g, '$1');
|
|
46
|
+
content = content.replace(/^\s*export\s+default\s+/gm, '');
|
|
47
|
+
content = content.replace(/^\s*export\s+\{[^}]*\}\s*;?\s*$/gm, '');
|
|
48
|
+
content = content.replace(/^\s*export\s+(?=(const|let|var|function|class)\b)/gm, '');
|
|
40
49
|
|
|
41
50
|
if (process.env.NODE_ENV === 'production') {
|
|
42
51
|
content = content.replace(/\/\*\*[\s\S]*?\*\//g, '');
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
# merge brings main in but we immediately restore root from stores/<alias>/ so store-specific data is kept.
|
|
5
5
|
# Runs on every push to main except pure store-sync commits ([stores-to-root], [root-to-stores]), so that:
|
|
6
6
|
# - Version-bump commits: staging-<alias> get the new version.
|
|
7
|
-
# - Hotfix backports
|
|
7
|
+
# - Hotfix backports:
|
|
8
|
+
# - staging-<alias> → main: skip syncing back into the same staging-<alias> (already has the change).
|
|
9
|
+
# - live-<alias> → main: sync into staging-<alias> too (so staging gets the live hotfix).
|
|
8
10
|
#
|
|
9
11
|
# Also runs when Post-Merge Tag or Nightly Hotfix Tag complete: version-bump pushes with GITHUB_TOKEN,
|
|
10
12
|
# which does not trigger push-based workflows, so we explicitly run sync after those workflows finish.
|
|
@@ -25,7 +27,7 @@ concurrency:
|
|
|
25
27
|
cancel-in-progress: false
|
|
26
28
|
|
|
27
29
|
jobs:
|
|
28
|
-
# Gate: skip only pure store-sync commits.
|
|
30
|
+
# Gate: skip only pure store-sync commits. For hotfix-backport, skip syncing back only when source was staging-<alias>.
|
|
29
31
|
# When triggered by workflow_run (version-bump finished), run sync if the workflow succeeded.
|
|
30
32
|
gate:
|
|
31
33
|
runs-on: ubuntu-latest
|
|
@@ -33,7 +35,7 @@ jobs:
|
|
|
33
35
|
if: github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success'
|
|
34
36
|
outputs:
|
|
35
37
|
should_run: ${{ steps.check.outputs.should_run }}
|
|
36
|
-
|
|
38
|
+
hotfix_skip_alias: ${{ steps.check.outputs.hotfix_skip_alias }}
|
|
37
39
|
steps:
|
|
38
40
|
- name: Check commit message and hotfix source
|
|
39
41
|
id: check
|
|
@@ -41,7 +43,7 @@ jobs:
|
|
|
41
43
|
if [ "${{ github.event_name }}" = "workflow_run" ]; then
|
|
42
44
|
echo "Triggered by workflow_run (version-bump finished); syncing main to staging."
|
|
43
45
|
echo "should_run=true" >> $GITHUB_OUTPUT
|
|
44
|
-
echo "
|
|
46
|
+
echo "hotfix_skip_alias=" >> $GITHUB_OUTPUT
|
|
45
47
|
exit 0
|
|
46
48
|
fi
|
|
47
49
|
|
|
@@ -50,22 +52,21 @@ jobs:
|
|
|
50
52
|
if echo "$COMMIT_MSG" | grep -qE "\[skip-store-sync\]|\[stores-to-root\]|\[root-to-stores\]"; then
|
|
51
53
|
echo "Skipping — store sync commit (avoid loop)"
|
|
52
54
|
echo "should_run=false" >> $GITHUB_OUTPUT
|
|
53
|
-
echo "
|
|
55
|
+
echo "hotfix_skip_alias=" >> $GITHUB_OUTPUT
|
|
54
56
|
exit 0
|
|
55
57
|
fi
|
|
56
58
|
|
|
57
59
|
echo "should_run=true" >> $GITHUB_OUTPUT
|
|
58
60
|
|
|
59
|
-
# If hotfix-backport
|
|
60
|
-
|
|
61
|
+
# If hotfix-backport came from staging-<alias>, skip syncing back to that same staging branch.
|
|
62
|
+
HOTFIX_SKIP_ALIAS=""
|
|
61
63
|
if echo "$COMMIT_MSG" | grep -q "\[hotfix-backport\]"; then
|
|
62
64
|
SOURCE_BRANCH=$(echo "$COMMIT_MSG" | sed -n 's/.*Merge \([^ ]*\) into main.*/\1/p' | head -1)
|
|
63
|
-
if [ -n "$SOURCE_BRANCH" ]; then
|
|
64
|
-
|
|
65
|
-
HOTFIX_SOURCE_ALIAS="${HOTFIX_SOURCE_ALIAS#live-}"
|
|
65
|
+
if [[ -n "$SOURCE_BRANCH" && "$SOURCE_BRANCH" == staging-* ]]; then
|
|
66
|
+
HOTFIX_SKIP_ALIAS="${SOURCE_BRANCH#staging-}"
|
|
66
67
|
fi
|
|
67
68
|
fi
|
|
68
|
-
echo "
|
|
69
|
+
echo "hotfix_skip_alias=$HOTFIX_SKIP_ALIAS" >> $GITHUB_OUTPUT
|
|
69
70
|
|
|
70
71
|
# Read store list from package.json
|
|
71
72
|
config:
|
|
@@ -88,7 +89,8 @@ jobs:
|
|
|
88
89
|
echo "stores=$STORES" >> $GITHUB_OUTPUT
|
|
89
90
|
echo "Store aliases: $STORES"
|
|
90
91
|
|
|
91
|
-
# Merge main into each staging-<alias>; root JSONs ignored (restored from stores/<alias>/).
|
|
92
|
+
# Merge main into each staging-<alias>; root JSONs ignored (restored from stores/<alias>/).
|
|
93
|
+
# Skip only staging-origin hotfix source branch (no need to merge back to same staging branch).
|
|
92
94
|
sync:
|
|
93
95
|
needs: [gate, config]
|
|
94
96
|
if: needs.gate.outputs.should_run == 'true'
|
|
@@ -103,7 +105,7 @@ jobs:
|
|
|
103
105
|
actions: write
|
|
104
106
|
env:
|
|
105
107
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
106
|
-
|
|
108
|
+
HOTFIX_SKIP_ALIAS: ${{ needs.gate.outputs.hotfix_skip_alias }}
|
|
107
109
|
steps:
|
|
108
110
|
- uses: actions/checkout@v4
|
|
109
111
|
with:
|
|
@@ -116,8 +118,8 @@ jobs:
|
|
|
116
118
|
ALIAS="${{ matrix.store }}"
|
|
117
119
|
STORE_DIR="stores/${ALIAS}"
|
|
118
120
|
|
|
119
|
-
if [ -n "$
|
|
120
|
-
echo "Hotfix came from staging-$ALIAS
|
|
121
|
+
if [ -n "$HOTFIX_SKIP_ALIAS" ] && [ "$HOTFIX_SKIP_ALIAS" = "$ALIAS" ]; then
|
|
122
|
+
echo "Hotfix came from staging-$ALIAS, skipping (no need to merge back to same staging branch)."
|
|
121
123
|
exit 0
|
|
122
124
|
fi
|
|
123
125
|
|