@by-association-only/theme-backup 1.0.0 → 1.0.2
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/.github/workflows/npm-publish.yml +20 -0
- package/README.md +3 -15
- package/index.js +87 -2
- package/package.json +1 -1
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
name: Publish package to npm
|
|
2
|
+
on:
|
|
3
|
+
release:
|
|
4
|
+
types: [published]
|
|
5
|
+
jobs:
|
|
6
|
+
build:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
id-token: write
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
- uses: actions/setup-node@v4
|
|
14
|
+
with:
|
|
15
|
+
node-version: '20.x'
|
|
16
|
+
registry-url: 'https://registry.npmjs.org'
|
|
17
|
+
- run: npm ci
|
|
18
|
+
- run: npm publish --access public
|
|
19
|
+
env:
|
|
20
|
+
NODE_AUTH_TOKEN: ${{ secrets.npm_token }}
|
package/README.md
CHANGED
|
@@ -16,19 +16,7 @@ This tool helps you create backups of Shopify themes across multiple stores in y
|
|
|
16
16
|
|
|
17
17
|
## Setup
|
|
18
18
|
|
|
19
|
-
1)
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
npm i @by-association-only/theme-backup --save-dev
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
or
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
yarn add @by-association-only/theme-backup --save-dev
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
2) Add a config file in the root: `.bao-stores` (or use existing `.bao-translation-checker`)
|
|
19
|
+
1) Add a config file in the root: `.bao-stores` (or use existing `.bao-translation-checker`)
|
|
32
20
|
|
|
33
21
|
List each store name on a separate line (the part before .myshopify.com).
|
|
34
22
|
|
|
@@ -43,10 +31,10 @@ acmestore
|
|
|
43
31
|
acmestore-us
|
|
44
32
|
```
|
|
45
33
|
|
|
46
|
-
|
|
34
|
+
2) Run the backup tool:
|
|
47
35
|
|
|
48
36
|
```bash
|
|
49
|
-
|
|
37
|
+
npx @by-association-only/theme-backup
|
|
50
38
|
```
|
|
51
39
|
|
|
52
40
|
## Usage
|
package/index.js
CHANGED
|
@@ -410,7 +410,16 @@ async function deleteThemes(store, themes) {
|
|
|
410
410
|
async function backupTheme(store, theme) {
|
|
411
411
|
const date = new Date()
|
|
412
412
|
const today = `${String(date.getDate()).padStart(2, '0')}/${String(date.getMonth() + 1).padStart(2, '0')}/${date.getFullYear()}` // DD/MM/YYYY
|
|
413
|
-
|
|
413
|
+
let backupName = `${theme.name} (Backup ${today})`
|
|
414
|
+
|
|
415
|
+
// Check if name exceeds Shopify's 50 character limit
|
|
416
|
+
if (backupName.length > 50) {
|
|
417
|
+
console.log(chalk.yellow(`\n⚠ Generated backup name is too long (${backupName.length} characters)`))
|
|
418
|
+
console.log(chalk.gray(` Original: "${backupName}"`))
|
|
419
|
+
console.log(chalk.yellow('\nPlease enter a custom name for this backup:'))
|
|
420
|
+
backupName = await promptTextInput('Enter custom backup name', 50)
|
|
421
|
+
}
|
|
422
|
+
|
|
414
423
|
const tempPath = path.join(process.cwd(), '.temp-backup')
|
|
415
424
|
|
|
416
425
|
try {
|
|
@@ -446,6 +455,70 @@ async function backupTheme(store, theme) {
|
|
|
446
455
|
}
|
|
447
456
|
}
|
|
448
457
|
|
|
458
|
+
// Function to prompt user for text input
|
|
459
|
+
async function promptTextInput(message, maxLength = 50) {
|
|
460
|
+
// Remove all existing listeners to prevent conflicts
|
|
461
|
+
process.stdin.removeAllListeners('data')
|
|
462
|
+
process.stdin.setRawMode(true)
|
|
463
|
+
process.stdin.resume()
|
|
464
|
+
|
|
465
|
+
let input = ''
|
|
466
|
+
|
|
467
|
+
const updateDisplay = () => {
|
|
468
|
+
process.stdout.write('\x1B[2J\x1B[H') // Clear screen
|
|
469
|
+
console.log(chalk.yellow(`\n${message}`))
|
|
470
|
+
console.log(chalk.gray(`(Max ${maxLength} characters)`))
|
|
471
|
+
console.log(chalk.cyan(`\n> ${input}`))
|
|
472
|
+
if (input.length > maxLength) {
|
|
473
|
+
console.log(chalk.red(`\n⚠ Name is too long (${input.length}/${maxLength} characters)`))
|
|
474
|
+
}
|
|
475
|
+
console.log(chalk.gray('\nPress Enter to confirm, Ctrl+C to cancel'))
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
updateDisplay()
|
|
479
|
+
|
|
480
|
+
return new Promise((resolve) => {
|
|
481
|
+
const handleKey = (data) => {
|
|
482
|
+
const key = data.toString()
|
|
483
|
+
|
|
484
|
+
if (key === '\x03') { // Ctrl+C
|
|
485
|
+
process.stdin.removeAllListeners('data')
|
|
486
|
+
process.stdin.setRawMode(false)
|
|
487
|
+
process.stdin.pause()
|
|
488
|
+
console.log(chalk.yellow('\nCancelled...'))
|
|
489
|
+
process.exit(0)
|
|
490
|
+
return
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
if (key === '\r') { // Enter
|
|
494
|
+
if (input.length === 0) {
|
|
495
|
+
updateDisplay()
|
|
496
|
+
return
|
|
497
|
+
}
|
|
498
|
+
if (input.length > maxLength) {
|
|
499
|
+
updateDisplay()
|
|
500
|
+
return
|
|
501
|
+
}
|
|
502
|
+
process.stdin.removeAllListeners('data')
|
|
503
|
+
process.stdin.setRawMode(false)
|
|
504
|
+
process.stdin.pause()
|
|
505
|
+
resolve(input.trim())
|
|
506
|
+
return
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
if (key === '\x7F') { // Backspace
|
|
510
|
+
input = input.slice(0, -1)
|
|
511
|
+
} else if (key.length === 1 && key >= ' ' && key <= '~') { // Printable characters
|
|
512
|
+
input += key
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
updateDisplay()
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
process.stdin.on('data', handleKey)
|
|
519
|
+
})
|
|
520
|
+
}
|
|
521
|
+
|
|
449
522
|
// Function to prompt user for yes/no
|
|
450
523
|
async function promptYesNo(message) {
|
|
451
524
|
process.stdin.setRawMode(true)
|
|
@@ -517,7 +590,16 @@ async function runBackup() {
|
|
|
517
590
|
console.log(chalk.green('✓ Authentication verified\n'))
|
|
518
591
|
}
|
|
519
592
|
|
|
520
|
-
for (
|
|
593
|
+
for (let i = 0; i < stores.length; i++) {
|
|
594
|
+
const store = stores[i]
|
|
595
|
+
|
|
596
|
+
// Clear screen before processing each store (except the first)
|
|
597
|
+
if (i > 0) {
|
|
598
|
+
// Use multiple methods for maximum compatibility
|
|
599
|
+
process.stdout.write('\x1B[2J\x1B[H') // ANSI clear
|
|
600
|
+
console.log('\n'.repeat(50)) // Fallback: push content off screen
|
|
601
|
+
}
|
|
602
|
+
|
|
521
603
|
console.log(chalk.bold(`\nProcessing ${store}:`))
|
|
522
604
|
|
|
523
605
|
// Get all themes
|
|
@@ -563,6 +645,9 @@ async function runBackup() {
|
|
|
563
645
|
}
|
|
564
646
|
}
|
|
565
647
|
|
|
648
|
+
// Clear screen before theme selection to remove any previous store's theme list
|
|
649
|
+
process.stdout.write('\x1B[2J\x1B[H')
|
|
650
|
+
|
|
566
651
|
// Select theme to backup
|
|
567
652
|
const selectedTheme = await selectTheme(store, 'Please select theme to backup')
|
|
568
653
|
if (!selectedTheme) {
|