@softlimit/theme-envy 0.1.10-alpha → 0.1.11-alpha
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +1 -0
- package/helpers/functions/deploy/README.md +19 -0
- package/helpers/functions/deploy/build-promise.js +14 -0
- package/helpers/functions/deploy/duplicate-live-theme.js +96 -0
- package/helpers/functions/deploy/env.js +5 -0
- package/helpers/functions/deploy/index.js +46 -0
- package/helpers/functions/deploy/push-theme.js +32 -0
- package/index.js +9 -0
- package/init/functions/copy-starter-config-files/.github/workflows/deploy.yml +53 -0
- package/init/functions/copy-starter-config-files/index.js +7 -0
- package/init/functions/copy-starter-config-files/utils/post-deploy.js +9 -0
- package/package.json +2 -1
package/README.md
CHANGED
@@ -107,6 +107,7 @@ Commands:
|
|
107
107
|
build [options] [env] Build Shopify theme
|
108
108
|
clean Empty output directory
|
109
109
|
convert [options] [source] Convert an existing Shopify theme to Theme Envy directory structure
|
110
|
+
deploy Deploy your theme to Shopify by copying the live theme then pushing changes to codebase on top of it
|
110
111
|
dev Start development process and sync with Shopify using the Shopify CLI
|
111
112
|
find-orphans Find unused snippets, partials, and assets in your Shopify theme
|
112
113
|
init [options] [source] Initialize a new Shopify theme project with Theme Envy directory structure
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# CI/CD with Github Workflow
|
2
|
+
|
3
|
+
During the `init` command, Theme Envy copies a `deploy.yml` workflow file into your project. This file is used to build and deploy your project to Github Pages.
|
4
|
+
|
5
|
+
## Variable and Secret Requirements
|
6
|
+
|
7
|
+
This workflow requires one environment secret to be set in your Github repository settings.
|
8
|
+
|
9
|
+
First, set up a 'production' environment for this workflow to run in.
|
10
|
+
|
11
|
+
Next, install Theme Access in your store and create a new theme access token.
|
12
|
+
|
13
|
+
Save this access token as an environment secret called `SHOPIFY_CLI_THEME_TOKEN`.
|
14
|
+
|
15
|
+
## Triggering the workflow
|
16
|
+
|
17
|
+
The deploy workflow is triggered by any added tag that starts with `v`. This is usually done when you create a new release.
|
18
|
+
|
19
|
+
For testing purposes, it will also run on any push to a branch named `deploy-release-action`.
|
@@ -0,0 +1,14 @@
|
|
1
|
+
const path = require('path')
|
2
|
+
const themeBuild = require(path.resolve(__dirname, '../../../build/index.js'))
|
3
|
+
const themeClean = require('../dist-clean.js')
|
4
|
+
|
5
|
+
module.exports = function(newThemeID) {
|
6
|
+
themeClean()
|
7
|
+
const promise = new Promise((resolve, reject) => {
|
8
|
+
themeBuild()
|
9
|
+
ThemeEnvy.events.on('build:complete', () => {
|
10
|
+
resolve(newThemeID)
|
11
|
+
})
|
12
|
+
})
|
13
|
+
return promise
|
14
|
+
}
|
@@ -0,0 +1,96 @@
|
|
1
|
+
/*
|
2
|
+
Exports function: duplicateLiveTheme
|
3
|
+
Returns a promise that resolves to the new theme ID
|
4
|
+
*/
|
5
|
+
const { spawn } = require('child_process')
|
6
|
+
const path = require('path')
|
7
|
+
const env = require('./env.js')
|
8
|
+
process.env.SHOPIFY_CLI_THEME_TOKEN = env.password
|
9
|
+
process.env.SHOPIFY_FLAG_STORE = ThemeEnvy.store
|
10
|
+
const dist = path.resolve(process.cwd(), ThemeEnvy.outputPath)
|
11
|
+
|
12
|
+
module.exports = async ({ themeName, type = 'unpublished' }) => {
|
13
|
+
/*
|
14
|
+
Download live theme from shopify to dist folder
|
15
|
+
*/
|
16
|
+
const _downloadLiveTheme = async () => {
|
17
|
+
console.log('Downloading Live Theme')
|
18
|
+
return new Promise((resolve, reject) => {
|
19
|
+
try {
|
20
|
+
const pull = spawn('shopify', ['theme', 'pull', '--live', '--path=' + dist], {
|
21
|
+
stdio: 'inherit'
|
22
|
+
})
|
23
|
+
pull.on('close', resolve)
|
24
|
+
|
25
|
+
const handleError = (error) => {
|
26
|
+
console.log(error)
|
27
|
+
reject(error)
|
28
|
+
}
|
29
|
+
|
30
|
+
pull.on('error', handleError)
|
31
|
+
} catch (error) {
|
32
|
+
const err = new Error('Could not download live theme')
|
33
|
+
reject(err)
|
34
|
+
throw err
|
35
|
+
}
|
36
|
+
})
|
37
|
+
}
|
38
|
+
|
39
|
+
// push without context templates first
|
40
|
+
const _shopifyNewTheme = async () => {
|
41
|
+
console.log(`Creating Theme: ${themeName}`)
|
42
|
+
return new Promise((resolve, reject) => {
|
43
|
+
try {
|
44
|
+
const push = spawn('shopify', ['theme', 'push', '--ignore=templates/\*.context.\*.json', '--ignore=sections/\*.context.\*.json', `--${type}`, '--json', (type === 'unpublished' && ('--theme=' + themeName)), '--path=' + dist])
|
45
|
+
push.stdout.setEncoding('utf8')
|
46
|
+
push.stdout.on('data', data => {
|
47
|
+
console.log(data)
|
48
|
+
if (data.includes('{"theme":')) {
|
49
|
+
// extract theme id from data
|
50
|
+
const themeID = data.match(/"id":(\d+)/)[1]
|
51
|
+
resolve(themeID)
|
52
|
+
}
|
53
|
+
})
|
54
|
+
const handleError = (error) => {
|
55
|
+
reject(error)
|
56
|
+
}
|
57
|
+
push.stderr.on('data', handleError)
|
58
|
+
push.on('error', handleError)
|
59
|
+
} catch {
|
60
|
+
throw new Error('Could not create new theme')
|
61
|
+
}
|
62
|
+
})
|
63
|
+
}
|
64
|
+
|
65
|
+
// then do another push to the same theme and only push context templates
|
66
|
+
const _pushAdditionalTemplates = async (themeId) => {
|
67
|
+
console.log(`Updating additional templates on theme: ${themeId}`)
|
68
|
+
return new Promise((resolve, reject) => {
|
69
|
+
try {
|
70
|
+
const push = spawn('shopify', ['theme', 'push', '--only=templates/\*.context.\*.json', '--only=sections/\*.context.\*.json', '--json', '--theme=' + themeId, '--path=' + dist])
|
71
|
+
push.stdout.setEncoding('utf8')
|
72
|
+
push.stdout.on('data', data => {
|
73
|
+
console.log(data)
|
74
|
+
if (data.includes('{"theme":')) {
|
75
|
+
// extract theme id from data
|
76
|
+
const themeID = data.match(/"id":(\d+)/)[1]
|
77
|
+
resolve(themeID)
|
78
|
+
}
|
79
|
+
})
|
80
|
+
} catch {
|
81
|
+
throw new Error('Could not push to new theme')
|
82
|
+
}
|
83
|
+
})
|
84
|
+
}
|
85
|
+
|
86
|
+
/*
|
87
|
+
do everything
|
88
|
+
*/
|
89
|
+
return _downloadLiveTheme()
|
90
|
+
.then(_shopifyNewTheme)
|
91
|
+
.then(themeId => _pushAdditionalTemplates(themeId))
|
92
|
+
.catch((err) => {
|
93
|
+
console.error(err.toString())
|
94
|
+
throw new Error('Theme download/backup failed')
|
95
|
+
})
|
96
|
+
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
/**
|
2
|
+
* @description theme-envy deploy duplicates the live theme, then pushes a build of the current theme to that new theme
|
3
|
+
* @example npx theme-envy deploy
|
4
|
+
* @returns {Void}
|
5
|
+
*/
|
6
|
+
|
7
|
+
const path = require('path')
|
8
|
+
const fs = require('fs')
|
9
|
+
const packageSettings = require(path.resolve(process.cwd(), 'package.json'))
|
10
|
+
const duplicateLiveTheme = require('./duplicate-live-theme')
|
11
|
+
const buildPromise = require('./build-promise')
|
12
|
+
const pushTheme = require('./push-theme')
|
13
|
+
const themeClean = require('../dist-clean')
|
14
|
+
const themeName = `${packageSettings.version} ${packageSettings.description}`
|
15
|
+
|
16
|
+
module.exports = function() {
|
17
|
+
// clean the dist directory
|
18
|
+
themeClean()
|
19
|
+
|
20
|
+
// duplicate live theme into output path
|
21
|
+
duplicateLiveTheme({ themeName })
|
22
|
+
|
23
|
+
// build theme from src
|
24
|
+
.then(buildPromise)
|
25
|
+
|
26
|
+
// push theme to new theme id
|
27
|
+
.then(pushTheme)
|
28
|
+
|
29
|
+
// get the theme id from the pushed theme and run post deploy scripts
|
30
|
+
.then(themeID => {
|
31
|
+
const postDeployPath = path.resolve(process.cwd(), 'utils/post-deploy.js')
|
32
|
+
if (fs.existsSync(postDeployPath)) {
|
33
|
+
const postDeploy = require(postDeployPath)
|
34
|
+
postDeploy({ themeName, themeID })
|
35
|
+
}
|
36
|
+
|
37
|
+
// all done, log that the deploy is complete
|
38
|
+
console.log('DEPLOY COMPLETE')
|
39
|
+
})
|
40
|
+
// catch any errors and log them
|
41
|
+
.catch(error => {
|
42
|
+
console.log('Could not deploy theme')
|
43
|
+
console.log(error)
|
44
|
+
process.exit()
|
45
|
+
})
|
46
|
+
}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
const { spawn } = require('child_process')
|
2
|
+
const path = require('path')
|
3
|
+
const dist = path.resolve(process.cwd(), ThemeEnvy.outputPath)
|
4
|
+
|
5
|
+
module.exports = async (newThemeID) => {
|
6
|
+
return new Promise((resolve, reject) => {
|
7
|
+
try {
|
8
|
+
// shopify push
|
9
|
+
const push = spawn('shopify', ['theme', 'push', '--theme=' + newThemeID, '--ignore=*.json', '--path=' + dist])
|
10
|
+
push.stdout.setEncoding('utf8')
|
11
|
+
push.stdout.on('data', data => {
|
12
|
+
console.log(data)
|
13
|
+
})
|
14
|
+
push.on('close', () => {
|
15
|
+
resolve(newThemeID)
|
16
|
+
})
|
17
|
+
const handleError = (error) => {
|
18
|
+
reject(error)
|
19
|
+
console.error(error.message)
|
20
|
+
throw new Error('Could not push theme')
|
21
|
+
}
|
22
|
+
push.stderr.on('data', handleError)
|
23
|
+
push.on('error', handleError)
|
24
|
+
return newThemeID
|
25
|
+
} catch (error) {
|
26
|
+
console.log(error)
|
27
|
+
reject(error)
|
28
|
+
// exit the process
|
29
|
+
process.exit()
|
30
|
+
}
|
31
|
+
})
|
32
|
+
}
|
package/index.js
CHANGED
@@ -19,6 +19,7 @@ const themeEnvyCommands = {
|
|
19
19
|
build: require('#Build'),
|
20
20
|
clean: require('#Helpers/functions/dist-clean.js'),
|
21
21
|
convert: require('#Convert'),
|
22
|
+
deploy: require('#Helpers/functions/deploy/index.js'),
|
22
23
|
dev: require('#Helpers/functions/dev.js'),
|
23
24
|
init: require('#Init'),
|
24
25
|
ignore: require('#Ignore'),
|
@@ -88,6 +89,14 @@ This does the following things:
|
|
88
89
|
themeEnvyCommands.init(source, options)
|
89
90
|
})
|
90
91
|
|
92
|
+
program
|
93
|
+
.command('deploy')
|
94
|
+
.description('Deploy your theme to Shopify by copying the live theme then pushing changes to codebase on top of it')
|
95
|
+
.action((options, command) => {
|
96
|
+
scriptMessage(command.name())
|
97
|
+
themeEnvyCommands.deploy()
|
98
|
+
})
|
99
|
+
|
91
100
|
program
|
92
101
|
.command('dev')
|
93
102
|
.description('Start development process and sync with Shopify using the Shopify CLI')
|
@@ -0,0 +1,53 @@
|
|
1
|
+
name: Deploy Production Theme
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
# trigger on v* tags
|
6
|
+
tags:
|
7
|
+
- 'v*'
|
8
|
+
# allow tests from pushes to branch
|
9
|
+
branches:
|
10
|
+
- 'deploy-release-action'
|
11
|
+
|
12
|
+
# or manually
|
13
|
+
workflow_dispatch:
|
14
|
+
|
15
|
+
jobs:
|
16
|
+
deploy:
|
17
|
+
runs-on: ubuntu-latest
|
18
|
+
environment: production
|
19
|
+
|
20
|
+
# connects organization and repo variables and secrets to the runner
|
21
|
+
env:
|
22
|
+
SHOPIFY_FLAG_STORE: ${{ vars.SHOPIFY_FLAG_STORE }}
|
23
|
+
SHOPIFY_CLI_THEME_TOKEN: ${{ secrets.SHOPIFY_CLI_THEME_TOKEN }}
|
24
|
+
SHOPIFY_CLI_TTY: 0
|
25
|
+
steps:
|
26
|
+
# load the current repo on the runner
|
27
|
+
- name: checkout repo
|
28
|
+
uses: actions/checkout@v3
|
29
|
+
with:
|
30
|
+
token: ${{ secrets.WORKFLOW_REPO_ACCESS }}
|
31
|
+
|
32
|
+
# set up node
|
33
|
+
- name: use node
|
34
|
+
uses: actions/setup-node@v3
|
35
|
+
with:
|
36
|
+
node-version: '18.13.0'
|
37
|
+
|
38
|
+
# set up ruby
|
39
|
+
- name: use ruby
|
40
|
+
uses: ruby/setup-ruby@v1
|
41
|
+
with:
|
42
|
+
ruby-version: '3.0'
|
43
|
+
|
44
|
+
# install dependencies
|
45
|
+
- name: install dependencies
|
46
|
+
run: |
|
47
|
+
gem install bundler
|
48
|
+
npm install -g npm@8.19.2
|
49
|
+
npm install
|
50
|
+
|
51
|
+
# run deployment script from framework bin scripts
|
52
|
+
- name: deploy new theme
|
53
|
+
run: npx theme-envy deploy
|
@@ -25,4 +25,11 @@ module.exports = function({ target, opts }) {
|
|
25
25
|
if (err) return console.error(err)
|
26
26
|
console.log(`${logSymbols.success} Utils starter files copied`)
|
27
27
|
})
|
28
|
+
|
29
|
+
// copy github deploy workflow
|
30
|
+
const githubDeploySrc = path.resolve(__dirname, './.github/workflows/deploy.yml')
|
31
|
+
fs.copy(githubDeploySrc, path.resolve(target, '.github/workflows/deploy.yml'), err => {
|
32
|
+
if (err) return console.error(err)
|
33
|
+
console.log(`${logSymbols.success} GitHub deploy workflow copied`)
|
34
|
+
})
|
28
35
|
}
|
@@ -0,0 +1,9 @@
|
|
1
|
+
/**
|
2
|
+
* @description runs directly after a deployment to Shopify to run any additional processes or notifications a user may want to run
|
3
|
+
* @param {string} themeId - The theme ID that was just deployed
|
4
|
+
* @returns {Void}
|
5
|
+
*/
|
6
|
+
|
7
|
+
module.exports = ({ themeName, themeID }) => {
|
8
|
+
// placeholder
|
9
|
+
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@softlimit/theme-envy",
|
3
|
-
"version": "0.1.
|
3
|
+
"version": "0.1.11-alpha",
|
4
4
|
"description": "Softlimit Shopify Theme Development Environment",
|
5
5
|
"bin": {
|
6
6
|
"theme-envy": "./index.js"
|
@@ -84,6 +84,7 @@
|
|
84
84
|
},
|
85
85
|
"devDependencies": {
|
86
86
|
"caller": "^1.1.0",
|
87
|
+
"dotenv": "^16.4.5",
|
87
88
|
"jsdoc": "^4.0.2"
|
88
89
|
}
|
89
90
|
}
|