Skip to content

Commit ada57bf

Browse files
authored
Merge pull request #374 from zendesk/luis/themes-migrate-css-js
feat(themes): send style.css and script.js through themes:migrate
2 parents c58039a + 6ac415d commit ada57bf

5 files changed

Lines changed: 116 additions & 3 deletions

File tree

packages/zcli-themes/src/lib/migrate.test.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import * as sinon from 'sinon'
2+
import * as fs from 'fs'
3+
import * as path from 'path'
24
import { expect } from '@oclif/test'
35
import * as getManifest from './getManifest'
46
import * as getTemplates from './getTemplates'
@@ -7,6 +9,7 @@ import * as getAssets from './getAssets'
79
import * as rewriteManifest from './rewriteManifest'
810
import * as rewriteTemplates from './rewriteTemplates'
911
import * as rewriteAssets from './rewriteAssets'
12+
import * as rewriteJsAndCss from './rewriteJsAndCss'
1013
import * as axios from 'axios'
1114
import { request } from '@zendesk/zcli-core'
1215
import migrate from './migrate'
@@ -39,8 +42,13 @@ describe('migrate', () => {
3942
const rewriteManifestStub = sinon.stub(rewriteManifest, 'default')
4043
const rewriteTemplatesStub = sinon.stub(rewriteTemplates, 'default')
4144
const rewriteAssetsStub = sinon.stub(rewriteAssets, 'default')
45+
const rewriteJsAndCssStub = sinon.stub(rewriteJsAndCss, 'default')
46+
const readFileSyncStub = sinon.stub(fs, 'readFileSync')
4247
const requestStub = sinon.stub(request, 'requestAPI')
4348

49+
readFileSyncStub.withArgs(path.join('theme/path', 'style.css'), 'utf8').returns('body { color: red; }')
50+
readFileSyncStub.withArgs(path.join('theme/path', 'script.js'), 'utf8').returns('console.log("hi")')
51+
4452
getManifestStub.withArgs('theme/path').returns(manifest)
4553
getTemplatesStub.withArgs('theme/path').returns({
4654
home_page: '<h1>Home</h1>',
@@ -87,7 +95,9 @@ describe('migrate', () => {
8795
templates: {
8896
home_page: '<h1>Updated Home</h1>',
8997
'article_pages/product_updates': '<h1>Updated Product updates</h1>',
90-
'custom_pages/faq': '<h1>Updated FAQ</h1>'
98+
'custom_pages/faq': '<h1>Updated FAQ</h1>',
99+
css: '/* migrated css */',
100+
js: '/* migrated js */'
91101
},
92102
assets: {
93103
'category_tree.js': Buffer.from('console.log("tree")').toString('base64')
@@ -112,6 +122,8 @@ describe('migrate', () => {
112122
home_page: '<h1>Home</h1>',
113123
'article_pages/product_updates': '<h1>Product updates</h1>',
114124
'custom_pages/faq': '<h1>FAQ</h1>',
125+
css: 'body { color: red; }',
126+
js: 'console.log("hi")',
115127
assets: {
116128
'background.png': 'background.png'
117129
},
@@ -135,6 +147,13 @@ describe('migrate', () => {
135147
})
136148
).to.equal(true)
137149

150+
expect(
151+
rewriteJsAndCssStub.calledWith('theme/path', {
152+
css: '/* migrated css */',
153+
js: '/* migrated js */'
154+
})
155+
).to.equal(true)
156+
138157
expect(
139158
rewriteAssetsStub.calledWith('theme/path', {
140159
'category_tree.js': Buffer.from('console.log("tree")').toString('base64')
@@ -145,6 +164,7 @@ describe('migrate', () => {
145164
})
146165

147166
it('propagates AxiosError on request failure', async () => {
167+
sinon.stub(fs, 'readFileSync').returns('')
148168
sinon.stub(getManifest, 'default').returns(manifest)
149169
sinon.stub(getTemplates, 'default').returns({})
150170
sinon.stub(getVariables, 'default').returns([])

packages/zcli-themes/src/lib/migrate.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import * as fs from 'fs'
2+
import * as path from 'path'
13
import type { MigrateResponse, MigrationReport } from '../types'
24
import getManifest from './getManifest'
35
import getTemplates from './getTemplates'
@@ -7,12 +9,15 @@ import { request } from '@zendesk/zcli-core'
79
import rewriteTemplates from './rewriteTemplates'
810
import rewriteManifest from './rewriteManifest'
911
import rewriteAssets from './rewriteAssets'
12+
import rewriteJsAndCss from './rewriteJsAndCss'
1013

1114
export default async function migrate (themePath: string): Promise<MigrationReport> {
1215
const manifest = getManifest(themePath)
1316
const templates = getTemplates(themePath)
1417
const variables = getVariables(themePath, manifest.settings)
1518
const assets = getAssets(themePath)
19+
const css = fs.readFileSync(path.join(themePath, 'style.css'), 'utf8')
20+
const js = fs.readFileSync(path.join(themePath, 'script.js'), 'utf8')
1621

1722
const variablesPayload = variables.reduce((payload, variable) => ({
1823
...payload,
@@ -34,6 +39,8 @@ export default async function migrate (themePath: string): Promise<MigrationRepo
3439
data: {
3540
templates: {
3641
...templates,
42+
css,
43+
js,
3744
assets: assetsPayload,
3845
variables: variablesPayload,
3946
metadata: metadataPayload
@@ -43,8 +50,10 @@ export default async function migrate (themePath: string): Promise<MigrationRepo
4350
})
4451

4552
const response = data as MigrateResponse
53+
const { css: migratedCss, js: migratedJs, ...templateEntries } = response.templates
4654
rewriteManifest(themePath, response.metadata.api_version)
47-
rewriteTemplates(themePath, response.templates)
55+
rewriteJsAndCss(themePath, { css: migratedCss, js: migratedJs })
56+
rewriteTemplates(themePath, templateEntries)
4857
rewriteAssets(themePath, response.assets)
4958
return response.migration_report
5059
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import * as sinon from 'sinon'
2+
import * as fs from 'fs'
3+
import * as path from 'path'
4+
import { expect } from '@oclif/test'
5+
import rewriteJsAndCss from './rewriteJsAndCss'
6+
7+
describe('rewriteJsAndCss', () => {
8+
beforeEach(() => {
9+
sinon.restore()
10+
})
11+
12+
it('writes style.css and script.js to the theme root', () => {
13+
const writeFileSyncStub = sinon.stub(fs, 'writeFileSync')
14+
15+
rewriteJsAndCss('theme/path', {
16+
css: 'body { color: red; }',
17+
js: 'console.log("hi")'
18+
})
19+
20+
expect(writeFileSyncStub.callCount).to.equal(2)
21+
expect(writeFileSyncStub.firstCall.args[0]).to.equal(path.join('theme/path', 'style.css'))
22+
expect(writeFileSyncStub.firstCall.args[1]).to.equal('body { color: red; }')
23+
expect(writeFileSyncStub.secondCall.args[0]).to.equal(path.join('theme/path', 'script.js'))
24+
expect(writeFileSyncStub.secondCall.args[1]).to.equal('console.log("hi")')
25+
})
26+
27+
it('throws if style.css cannot be written', () => {
28+
const cssPath = path.join('theme/path', 'style.css')
29+
const writeFileSyncStub = sinon.stub(fs, 'writeFileSync')
30+
writeFileSyncStub.withArgs(cssPath).throws(new Error('Permission denied'))
31+
32+
expect(() => {
33+
rewriteJsAndCss('theme/path', { css: 'a', js: 'b' })
34+
}).to.throw(`Failed to write file: ${cssPath}`)
35+
})
36+
37+
it('throws if script.js cannot be written', () => {
38+
const jsPath = path.join('theme/path', 'script.js')
39+
const writeFileSyncStub = sinon.stub(fs, 'writeFileSync')
40+
writeFileSyncStub.withArgs(jsPath).throws(new Error('Permission denied'))
41+
42+
expect(() => {
43+
rewriteJsAndCss('theme/path', { css: 'a', js: 'b' })
44+
}).to.throw(`Failed to write file: ${jsPath}`)
45+
})
46+
})
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { CLIError } from '@oclif/core/lib/errors'
2+
import * as fs from 'fs'
3+
import * as path from 'path'
4+
import * as chalk from 'chalk'
5+
6+
export default function rewriteJsAndCss (
7+
themePath: string,
8+
{ css, js }: { css: string; js: string }
9+
) {
10+
const cssPath = path.join(themePath, 'style.css')
11+
const jsPath = path.join(themePath, 'script.js')
12+
13+
try {
14+
fs.writeFileSync(cssPath, css)
15+
} catch (error) {
16+
throw new CLIError(chalk.red(`Failed to write file: ${cssPath}`))
17+
}
18+
19+
try {
20+
fs.writeFileSync(jsPath, js)
21+
} catch (error) {
22+
throw new CLIError(chalk.red(`Failed to write file: ${jsPath}`))
23+
}
24+
}

packages/zcli-themes/tests/functional/migrate.test.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ describe('themes:migrate', function () {
1111
let fetchStub: sinon.SinonStub
1212
let manifestBackup: string
1313
let templateBackup: string
14+
let styleBackup: string
15+
let scriptBackup: string
1416
const migratedAssetPath = path.join(baseThemePath, 'assets/category_tree.js')
1517
const partialsDir = path.join(baseThemePath, 'templates/partials')
1618

@@ -25,6 +27,8 @@ describe('themes:migrate', function () {
2527
path.join(baseThemePath, 'templates/document_head.hbs'),
2628
'utf8'
2729
)
30+
styleBackup = fs.readFileSync(path.join(baseThemePath, 'style.css'), 'utf8')
31+
scriptBackup = fs.readFileSync(path.join(baseThemePath, 'script.js'), 'utf8')
2832
})
2933

3034
afterEach(() => {
@@ -35,6 +39,8 @@ describe('themes:migrate', function () {
3539
path.join(baseThemePath, 'templates/document_head.hbs'),
3640
templateBackup
3741
)
42+
fs.writeFileSync(path.join(baseThemePath, 'style.css'), styleBackup)
43+
fs.writeFileSync(path.join(baseThemePath, 'script.js'), scriptBackup)
3844
// Clean up migrated asset
3945
if (fs.existsSync(migratedAssetPath)) {
4046
fs.unlinkSync(migratedAssetPath)
@@ -65,7 +71,9 @@ describe('themes:migrate', function () {
6571
},
6672
templates: {
6773
document_head: '{{!chat (obsolete)}}',
68-
'partials/user_info': '<div>{{user.name}}</div>'
74+
'partials/user_info': '<div>{{user.name}}</div>',
75+
css: '/* migrated */\nbody {}',
76+
js: '/* migrated */\nconsole.log("hi")'
6977
},
7078
assets: {
7179
'category_tree.js': Buffer.from('console.log("category_tree");\n').toString('base64')
@@ -113,6 +121,12 @@ describe('themes:migrate', function () {
113121
const asset = fs.readFileSync(migratedAssetPath, 'utf8')
114122
expect(asset).to.equal('console.log("category_tree");\n')
115123

124+
// Verify root style.css and script.js were rewritten
125+
const style = fs.readFileSync(path.join(baseThemePath, 'style.css'), 'utf8')
126+
expect(style).to.equal('/* migrated */\nbody {}')
127+
const script = fs.readFileSync(path.join(baseThemePath, 'script.js'), 'utf8')
128+
expect(script).to.equal('/* migrated */\nconsole.log("hi")')
129+
116130
// Verify migration report was printed
117131
expect(ctx.stdout).to.contain('Theme migrated successfully')
118132
expect(ctx.stdout).to.contain('document_head')

0 commit comments

Comments
 (0)