@smartimpact-it/json-merge-shopify
Version:
260 lines (209 loc) • 8.16 kB
Markdown
# JSON Merger and formatter for Shopify
## JSON Merger
The library handles merging JSON objects and arrays.
```bash
npm install --save @smartimpact-it/json-merge-shopify
```
```javascript
import { Merger } from '@smartimpact-it/json-merge-shopify';
const merger = new Merger({
ancestor,
ours,
theirs,
preferred,
filename,
});
const merged = merger.merge();
```
## JSON formatter
This formats JSON files to be Shopify compatible.
```javascript
import { formatJson } from '@smartimpact-it/json-merge-shopify';
const formatted = formatJson(json);
```
## Git Branch Merger
This `GitMerger` functionality is intended to workaround Shopify's limitations for the Git integration.
To use it, you will need 2 or 3 branches:
- `main` branch: this is the branch that you will be merging into
- `live-mirror` branch: this is the branch that you will be merging from; this branch needs to be connected to Shopify (i.e. the `live` branch). We never write to this branch, we only read from it. Only Shopify should be writing to this branch.
- `production` branch (optional): this is the branch that you be deploying from. It will not be connected directly to Shopify's git integration, but with a Github Action you can deploy this branch to Shopify.
To use it, import the `GitMerger` class. It has the following options:
- `gitRoot`: the root of the git repository
- `createCommit`: whether or not to create a commit with the changes
- `mainBranch`: the name of the main branch (default: `main`)
- `liveMirrorBranch`: the name of the live mirror branch (default: `live-mirror`)
- `productionBranch`: the name of the production branch (default: `production`)
- `commitMessage`: the commit message to use (default: `[AUTOMATED] Update JSON files from ``#liveMirror#`` branch: #files#`)
- `preferred`: the preferred strategy for the merger (default: `theirs`)
- `jsonPaths`: the paths to the JSON files to merge (default: `['templates/**/*.json', 'locales/*.json', 'config/*.json']`)
- `exitIfNoExistingDeployment` (default: `true`): whether or not to exit if there is no commit on the `production` branch
- `checkJsonValidity` (default: `true`): whether or not to check the validity of the JSON files using `shopify theme check`
```javascript title="path/to/json-merger.js"
const { GitMerger } = require('@smartimpact-it/json-merge-shopify');
const path = require('path');
const gitRoot = path.resolve(__dirname, '../../../'); // The root of the git repository
(async () => {
const createCommit =
process.argv.includes('--commit') || process.env.COMMIT_CHANGES == 'true';
// Initialize the merger
const merger = new GitMerger({
gitRoot,
createCommit,
});
// Run the merge
await merger.run();
})();
```
### Config file
You can also use a config file to specify the options. The config file can be a JSON file (`shopify-git-merger.config.json`) or a JS file (`shopify-git-merger.config.js`) that exports an object with the options.
Then pass the path to the config file to the `GitMerger` constructor.
```javascript
import { GitMerger } from '@smartimpact-it/json-merge-shopify';
const gitRoot = path.resolve(__dirname, '../../../'); // The root of the git repository
const merger = new GitMerger('shopify-git-merger.config.json', {
gitRoot,
});
```
Or you can pass `null` as the first argument and the `GitMerger` will look for the config file in the root of the git repository.
```javascript
import { GitMerger } from '@smartimpact-it/json-merge-shopify';
const gitRoot = path.resolve(__dirname, '../../../'); // The root of the git repository
const merger = new GitMerger(null, {
gitRoot,
});
```
### Github Workflows
You will need 2 workflows:
- on the `live-mirror` branch - to check if JSON files have been modified by Shopify and then trigger the second workflow
- on the `main` branch - to merge the JSON changes from the `live-mirror` branch
```yaml title=".github/workflows/check-json-changes.yml"
name: Check modified JSON files
concurrency:
group: live-mirror
cancel-in-progress: false
on:
push:
branches:
- live-mirror
workflow_dispatch:
env:
NODE_VERSION: 18
NPM_VERSION: 9
jobs:
check-json:
name: Check if JSON files have been modified
runs-on: ubuntu-latest
if: contains(toJSON(github.event.head_commit.message), 'Update from Shopify')
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 2 # Needed to get the previous commits
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v35.9.2
with:
files: |
templates/**/*.json
sections/**/*.json
locales/**/*.json
config/*.json
- name: Trigger merge if necessary
if: steps.changed-files.outputs.any_changed == 'true'
uses: actions/github-script@v6
with:
script: |
# Check if there is any production deployment
# Remove this if you don't want to check for a production deployment
const lastRun = await github.rest.actions.listWorkflowRuns({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: 'production.yml',
branch: 'production',
status: 'success',
per_page: 1,
});
if (lastRun.data.total_count === 0) {
console.log('No successful production runs found');
return;
}
# Trigger the merge workflow
await github.rest.actions.createWorkflowDispatch({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: 'merge-live-mirror-json.yml',
ref: 'main',
inputs: {
merge: 'true',
},
});
```
```yaml title=".github/workflows/merge-json-changes.yml"
name: Merge JSON files
concurrency:
group: main
cancel-in-progress: true
on:
workflow_dispatch:
env:
NODE_VERSION: 18
NPM_VERSION: 9
COMMIT_CHANGES: true
jobs:
merge-json:
name: Merge JSON files
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-node@v3
with:
node-version: 18
- uses: ruby/setup-ruby@v1
with:
ruby-version: 3.3
bundler: 'latest'
- name: Get npm cache directory
id: npm-cache-dir
shell: bash
run: echo "dir=$(npm config get cache)" >> $GITHUB_OUTPUT
- name: Load NPM packages from cache
id: npm-cache
uses: actions/cache@v3
with:
path: |
${{ steps.npm-cache-dir.outputs.dir }}
**/node_modules
key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-${{ env.NODE_VERSION }}-
${{ runner.os }}-node-
- name: Upgrade NPM to the correct version
shell: bash
env:
NPM_VERSION: ${{ env.NPM_VERSION }}
run: npm i -g npm@$NPM_VERSION
- name: Install Shopify CLI
run: npm install -g @shopify/cli @shopify/theme
- name: Install node modules
if: steps.npm-cache.outputs.cache-hit != 'true'
run: npm install
- name: Run the merge process
uses: mathiasvr/command-output@v2.0.0
id: merge-json
env:
COMMIT_CHANGES: ${{ env.COMMIT_CHANGES }}
with:
run: |
git config user.name github-actions
git config user.email github-actions@github.com
git status
node path/to/json-merger.js --commit
git status
- name: Push the changes, if there are any
if: success()
run: |
git status | grep 'Your branch is ahead' && git push && echo 'Pushed changes' || echo "No changes to push"
```
### Github Action
You can also use the [`siit-dev/merge-json-shopify-branches` pre-built Github Action](https://github.com/siit-dev/merge-json-shopify-branches).