Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"@parcel/reporter-cli": "^2.7.0",
"ajv": "^8",
"ajv-formats": "^2.1.1",
"archiver": "^7.0.1",
"archiver": "^8.0.0",
"chalk": "^4",
"chokidar": "^3.5.2",
"execa": "^5.0.0",
Expand Down
7 changes: 4 additions & 3 deletions src/commands/app/pack.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ const { Flags, Args } = require('@oclif/core')
const path = require('node:path')
const fs = require('fs-extra')
const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-app:pack', { provider: 'debug' })
const archiver = require('archiver')
const yaml = require('js-yaml')
const execa = require('execa')
const { loadConfigFile, writeFile } = require('../../lib/import-helper')
Expand Down Expand Up @@ -260,10 +259,12 @@ class Pack extends BaseCommand {
* @param {boolean} pathInZip internal path in zip
* @returns {Promise} returns with a blank promise when done
*/
zipHelper (filePath, out, pathInZip = false) {
async zipHelper (filePath, out, pathInZip = false) {
aioLogger.debug(`Creating zip of file/folder '${filePath}'`)
// archiver 8 is ESM-only and exposes a class API; load it lazily via dynamic import from this CommonJS command
const { ZipArchive } = await import('archiver')
const stream = fs.createWriteStream(out)
const archive = archiver('zip', { zlib: { level: 9 } })
const archive = new ZipArchive({ zlib: { level: 9 } })

return new Promise((resolve, reject) => {
stream.on('close', () => resolve())
Expand Down
29 changes: 20 additions & 9 deletions test/commands/app/pack.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,18 @@ const fs = require('fs-extra')
const path = require('node:path')
const importHelper = require('../../../src/lib/import-helper')
const yaml = require('js-yaml')
const archiver = require('archiver')

const libConfig = require('@adobe/aio-cli-lib-app-config')

// mocks
jest.mock('execa')
jest.mock('fs-extra')
jest.mock('../../../src/lib/import-helper')
jest.mock('archiver')
// archiver 8 is ESM-only with a class API; the current mock instance is set per-test.
let currentArchiverMock
jest.unstable_mockModule('archiver', () => ({
ZipArchive: jest.fn().mockImplementation(() => currentArchiverMock)
}))

const mockGetFullConfig = jest.fn()

Expand Down Expand Up @@ -63,8 +66,6 @@ beforeEach(() => {
fs.copy.mockClear()
fs.createWriteStream.mockClear()
fs.lstatSync.mockClear()

archiver.mockClear()
})

test('exports', async () => {
Expand Down Expand Up @@ -293,21 +294,29 @@ test('zipHelper', async () => {
finalize: jest.fn()
}

archiver.mockImplementation(() => archiverMock)
currentArchiverMock = archiverMock

// zipHelper is async (loads ESM archiver via dynamic import); flush microtasks so the
// archive is set up before triggering the stream 'close'/'error' handlers.
const flush = () => new Promise(resolve => setImmediate(resolve))

const command = new TheCommand()
command.argv = []

// not a directory, just a file (see lstatSync mock 1)
command.zipHelper('my-file', 'app.zip')
const p1 = command.zipHelper('my-file', 'app.zip')
await flush()
endStream()
await p1
expect(archiverMock.directory).not.toHaveBeenCalled()
expect(archiverMock.file).toHaveBeenCalledWith('my-file', { name: 'my-file' })
archiverMock.file.mockClear()

// a directory (see lstatSync mock 2)
command.zipHelper('my-folder', 'app.zip')
const p2 = command.zipHelper('my-folder', 'app.zip')
await flush()
endStream()
await p2
expect(archiverMock.file).not.toHaveBeenCalled()
expect(archiverMock.directory).toHaveBeenCalledWith('my-folder', false)
archiverMock.directory.mockClear()
Expand All @@ -318,8 +327,10 @@ test('zipHelper', async () => {
archiverMock.destroy.mockClear()

// archiving error, for coverage (see lstatSync mock 4)
command.zipHelper('my-file', 'app.zip').catch(console.error)
onError()
const p4 = command.zipHelper('my-file', 'app.zip').catch(() => {})
await flush()
onError(new Error('archive error'))
await p4
})

describe('filesToPack', () => {
Expand Down
Loading