@softlimit/theme-envy 0.1.10-alpha → 0.1.12-alpha

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -13,6 +13,9 @@ module.exports = function(path) {
13
13
  if (path.includes('sections/')) {
14
14
  return `sections/${filename}`
15
15
  }
16
+ if (path.includes('blocks/')) {
17
+ return `blocks/${filename}`
18
+ }
16
19
  if (path.includes('layout/')) {
17
20
  return `layout/${filename}`
18
21
  }
@@ -9,7 +9,7 @@ const path = require('path')
9
9
  const { parseSchema } = require('#Helpers')
10
10
 
11
11
  module.exports = function({ source, filePath }) {
12
- if (!filePath.includes('sections')) return source
12
+ if (!filePath.includes('sections') && !filePath.includes('blocks')) return source
13
13
  // inject installs into inlined schema with {% schema %} {% endschema %} tags
14
14
  const hasSchemaTag = source.match(/{% schema %}/g)
15
15
  if (hasSchemaTag) return injectInstallsSchema({ source, filePath })
@@ -21,6 +21,9 @@ module.exports = function({ source, filePath }) {
21
21
  }
22
22
 
23
23
  function injectJsSchema({ source, filePath, schema }) {
24
+ if (filePath.includes('blocks')) {
25
+ console.log('inject block schema', filePath, schema)
26
+ }
24
27
  // regexp for a quoted string within our schema match
25
28
  const schemaFile = schema[0].match(/'(.*)'/)[1] || schema[0].match(/"(.*)"/)[1]
26
29
  // load the file export
@@ -18,8 +18,8 @@ module.exports = function({ file, mode, verbose }) {
18
18
  const outputPath = `${ThemeEnvy.outputPath}/${shopifyPath}`
19
19
  let source = fs.readFileSync(file, 'utf8')
20
20
 
21
- // inject schema .js into liquid section files
22
- if (file.includes('sections/')) source = sectionSchemaInject({ source, filePath: file })
21
+ // inject schema .js into liquid section or block files
22
+ if (file.includes('sections/') || file.includes('blocks/')) source = sectionSchemaInject({ source, filePath: file })
23
23
 
24
24
  // apply our custom liquid tags: partial, hook, theme
25
25
  source = extendLiquid({ source, filePath: file })
@@ -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,5 @@
1
+ /* eslint-disable no-undef */
2
+ require('dotenv').config()
3
+ module.exports = {
4
+ password: process.env.SHOPIFY_CLI_THEME_TOKEN,
5
+ }
@@ -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
+ }
@@ -10,7 +10,7 @@
10
10
  const fs = require('fs-extra')
11
11
  const path = require('path')
12
12
 
13
- const directories = ['assets', 'config', 'layout', 'locales', 'sections', 'snippets', 'templates']
13
+ const directories = ['assets', 'blocks', 'config', 'layout', 'locales', 'sections', 'snippets', 'templates']
14
14
  const envyDirectories = ['theme-envy/elements', 'theme-envy/features', 'theme-envy/partials', 'theme-envy/schema']
15
15
  function ensureDirectory(root, dir) {
16
16
  fs.ensureDirSync(path.resolve(root, dir))
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.10-alpha",
3
+ "version": "0.1.12-alpha",
4
4
  "description": "Softlimit Shopify Theme Development Environment",
5
5
  "bin": {
6
6
  "theme-envy": "./index.js"
@@ -36,7 +36,7 @@
36
36
  "url": "https://github.com/softlimit/theme-envy"
37
37
  },
38
38
  "engines": {
39
- "npm": "8.x"
39
+ "npm": ">=8.x"
40
40
  },
41
41
  "standard-version": {
42
42
  "scripts": {
@@ -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
  }