diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4465c1cd8..f6915756e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -102,6 +102,8 @@ jobs: name: Linux_X86-64_app_image - path: '*macOS_64bit.dmg' name: macOS_dmg + - path: '*macOS_64bit.zip' + name: macOS_zip - path: '*Windows_64bit.exe' name: Windows_X86-64_interactive_installer - path: '*Windows_64bit.msi' diff --git a/electron/build/template-package.json b/electron/build/template-package.json index 6d15db0a4..08b90379b 100644 --- a/electron/build/template-package.json +++ b/electron/build/template-package.json @@ -91,10 +91,7 @@ "hardenedRuntime": true, "gatekeeperAssess": false, "entitlements": "resources/entitlements.mac.plist", - "entitlementsInherit": "resources/entitlements.mac.plist", - "target": [ - "dmg" - ] + "entitlementsInherit": "resources/entitlements.mac.plist" }, "linux": { "target": [ diff --git a/electron/packager/index.js b/electron/packager/index.js index 784a5a38d..1dd3ed093 100644 --- a/electron/packager/index.js +++ b/electron/packager/index.js @@ -227,8 +227,7 @@ ${fs.readFileSync(path('..', 'build', 'package.json')).toString()} 'Installing dependencies' ); exec( - `yarn --network-timeout 1000000 --cwd ${path('..', 'build')} build${ - isElectronPublish ? ':publish' : '' + `yarn --network-timeout 1000000 --cwd ${path('..', 'build')} build${isElectronPublish ? ':publish' : '' }`, `Building the ${productName} application` ); @@ -393,11 +392,7 @@ ${fs.readFileSync(path('..', 'build', 'package.json')).toString()} for (const fileToCopy of filesToCopy) { echo(`🚢 >>> Copying ${fileToCopy} to ${targetFolder}.`); const isZip = await utils.isZip(fileToCopy); - if (isZip) { - await utils.adjustArchiveStructure(fileToCopy, targetFolder); - } else { - cp('-rf', fileToCopy, targetFolder); - } + cp('-rf', fileToCopy, targetFolder); echo(`👌 >>> Copied ${fileToCopy} to ${targetFolder}.`); } } @@ -491,8 +486,7 @@ ${fs.readFileSync(path('..', 'build', 'package.json')).toString()} if (expectedVersion) { if (!versions.has(expectedVersion)) { echo( - `Mismatching version configuration. Expected version was: '${expectedVersion}' actual was: '${ - Array.from(versions)[0] + `Mismatching version configuration. Expected version was: '${expectedVersion}' actual was: '${Array.from(versions)[0] }'.` ); shell.exit(1); diff --git a/electron/packager/package.json b/electron/packager/package.json index e1f6c72df..4841808e9 100644 --- a/electron/packager/package.json +++ b/electron/packager/package.json @@ -7,7 +7,7 @@ "scripts": { "prepare": "yarn test", "package": "node index.js", - "test": "mocha \"./test/**/*.test.js\"" + "test": "echo 'No test implemented'" }, "keywords": [], "author": "Arduino SA", diff --git a/electron/packager/test/resources/not-a-zip.dmg b/electron/packager/test/resources/not-a-zip.dmg deleted file mode 100644 index a0b7a61d1..000000000 Binary files a/electron/packager/test/resources/not-a-zip.dmg and /dev/null differ diff --git a/electron/packager/test/resources/zip with whitespace.zip b/electron/packager/test/resources/zip with whitespace.zip deleted file mode 100644 index 24f7680a8..000000000 Binary files a/electron/packager/test/resources/zip with whitespace.zip and /dev/null differ diff --git a/electron/packager/test/resources/zip-with-base-folder.zip b/electron/packager/test/resources/zip-with-base-folder.zip deleted file mode 100644 index b5f71f919..000000000 Binary files a/electron/packager/test/resources/zip-with-base-folder.zip and /dev/null differ diff --git a/electron/packager/test/resources/zip-with-symlink.zip b/electron/packager/test/resources/zip-with-symlink.zip deleted file mode 100644 index 259dba4a9..000000000 Binary files a/electron/packager/test/resources/zip-with-symlink.zip and /dev/null differ diff --git a/electron/packager/test/resources/zip-without-symlink.zip b/electron/packager/test/resources/zip-without-symlink.zip deleted file mode 100644 index 24f7680a8..000000000 Binary files a/electron/packager/test/resources/zip-without-symlink.zip and /dev/null differ diff --git a/electron/packager/test/utils.test.js b/electron/packager/test/utils.test.js deleted file mode 100644 index b2467b380..000000000 --- a/electron/packager/test/utils.test.js +++ /dev/null @@ -1,119 +0,0 @@ -const fs = require('fs'); -const path = require('path'); -const expect = require('chai').expect; -const track = require('temp').track(); -const unpack = require('../utils').unpack; -const testMe = require('../utils'); -const sinon = require('sinon'); - -describe('utils', () => { - - describe('adjustArchiveStructure', () => { - - let consoleStub; - - beforeEach(() => { - consoleStub = sinon.stub(console, 'log').value(() => { }); - }); - - afterEach(() => { - consoleStub.reset(); - track.cleanupSync(); - }); - - it('should reject when not a zip file', async () => { - try { - const invalid = path.join(__dirname, 'resources', 'not-a-zip.dmg'); - await testMe.adjustArchiveStructure(invalid, track.mkdirSync()); - throw new Error('Expected a rejection'); - } catch (e) { - expect(e).to.be.an.instanceOf(Error); - expect(e.message).to.be.equal('Expected a ZIP file.'); - } - }); - - it('should reject when target directory does not exist', async () => { - try { - const zip = path.join(__dirname, 'resources', 'zip-with-base-folder.zip'); - await testMe.adjustArchiveStructure(zip, path.join(__dirname, 'some', 'missing', 'path')); - throw new Error('Expected a rejection'); - } catch (e) { - expect(e).to.be.an.instanceOf(Error); - expect(e.message.endsWith('does not exist.')).to.be.true; - } - }); - - it('should reject when target is a file', async () => { - try { - const zip = path.join(__dirname, 'resources', 'zip-with-base-folder.zip'); - await testMe.adjustArchiveStructure(zip, path.join(__filename)); - throw new Error('Expected a rejection'); - } catch (e) { - expect(e).to.be.an.instanceOf(Error); - expect(e.message.endsWith('is not a directory.')).to.be.true; - } - }); - - it('should be a NOOP when the zip already has the desired base folder', async () => { - const zip = path.join(__dirname, 'resources', 'zip-with-base-folder.zip'); - const actual = await testMe.adjustArchiveStructure(zip, track.mkdirSync()); - expect(actual).to.be.equal(zip); - }); - - it('should handle whitespace in file path gracefully', async () => { - const zip = path.join(__dirname, 'resources', 'zip with whitespace.zip'); - const out = track.mkdirSync(); - const actual = await testMe.adjustArchiveStructure(zip, out, true); - expect(actual).to.be.equal(path.join(out, 'zip with whitespace.zip')); - console.log(actual); - expect(fs.existsSync(actual)).to.be.true; - - const verifyOut = track.mkdirSync(); - await unpack(actual, verifyOut); - - const root = path.join(verifyOut, 'zip with whitespace'); - expect(fs.existsSync(root)).to.be.true; - expect(fs.lstatSync(root).isDirectory()).to.be.true; - const subs = fs.readdirSync(root); - expect(subs).to.have.lengthOf(3); - expect(subs.sort()).to.be.deep.equal(['a.txt', 'b.txt', 'foo']); - }); - - it('should keep the symlinks after ZIP adjustments', async function () { - if (process.platform === 'win32') { - this.skip(); - } - const zip = path.join(__dirname, 'resources', 'zip-with-symlink.zip'); - const out = track.mkdirSync(); - const actual = await testMe.adjustArchiveStructure(zip, out, true); - expect(actual).to.be.equal(path.join(out, 'zip-with-symlink.zip')); - console.log(actual); - expect(fs.existsSync(actual)).to.be.true; - - const verifyOut = track.mkdirSync(); - await unpack(actual, verifyOut); - expect(fs.lstatSync(path.join(verifyOut, 'zip-with-symlink', 'folder', 'symlinked-sub')).isSymbolicLink()).to.be.true; - }); - - it('should adjust the archive structure if base folder is not present', async () => { - const zip = path.join(__dirname, 'resources', 'zip-without-symlink.zip'); - const out = track.mkdirSync(); - const actual = await testMe.adjustArchiveStructure(zip, out, true); - expect(actual).to.be.equal(path.join(out, 'zip-without-symlink.zip')); - console.log(actual); - expect(fs.existsSync(actual)).to.be.true; - - const verifyOut = track.mkdirSync(); - await unpack(actual, verifyOut); - - const root = path.join(verifyOut, 'zip-without-symlink'); - expect(fs.existsSync(root)).to.be.true; - expect(fs.lstatSync(root).isDirectory()).to.be.true; - const subs = fs.readdirSync(root); - expect(subs).to.have.lengthOf(3); - expect(subs.sort()).to.be.deep.equal(['a.txt', 'b.txt', 'foo']); - }); - - }); - -}); diff --git a/electron/packager/utils.js b/electron/packager/utils.js index 01be7f92e..2f9d37eae 100644 --- a/electron/packager/utils.js +++ b/electron/packager/utils.js @@ -50,67 +50,6 @@ function collectUnusedDependencies(pathToProject = process.cwd()) { }); } -/** - * `pathToZip` is a `path/to/your/app-name.zip`. - * If the `pathToZip` archive does not have a root directory with name `app-name`, it creates one, and move the content from the - * archive's root to the new root folder. If the archive already has the desired root folder, calling this function is a NOOP. - * If `pathToZip` is not a ZIP, rejects. `targetFolderName` is the destination folder not the new archive location. - */ -function adjustArchiveStructure(pathToZip, targetFolderName, noCleanup) { - return new Promise(async (resolve, reject) => { - if (!(await isZip(pathToZip))) { - reject(new Error(`Expected a ZIP file.`)); - return; - } - if (!fs.existsSync(targetFolderName)) { - reject(new Error(`${targetFolderName} does not exist.`)); - return; - } - if (!fs.lstatSync(targetFolderName).isDirectory()) { - reject(new Error(`${targetFolderName} is not a directory.`)); - return; - } - console.log(`⏱️ >>> Adjusting ZIP structure ${pathToZip}...`); - - const root = basename(pathToZip); - const resources = await list(pathToZip); - const hasBaseFolder = resources.find((name) => name === root); - if (hasBaseFolder) { - if ( - resources.filter((name) => name.indexOf(path.sep) === -1).length > 1 - ) { - console.warn( - `${pathToZip} ZIP has the desired root folder ${root}, however the ZIP contains other entries too: ${JSON.stringify( - resources - )}` - ); - } - console.log(`👌 <<< The ZIP already has the desired ${root} folder.`); - resolve(pathToZip); - return; - } - - const track = temp.track(); - try { - const unzipOut = path.join(track.mkdirSync(), root); - fs.mkdirSync(unzipOut); - await unpack(pathToZip, unzipOut); - const adjustedZip = path.join(targetFolderName, path.basename(pathToZip)); - await pack(unzipOut, adjustedZip); - console.log( - `👌 <<< Adjusted the ZIP structure. Moved the modified ${basename( - pathToZip - )} to the ${targetFolderName} folder.` - ); - resolve(adjustedZip); - } finally { - if (!noCleanup) { - track.cleanupSync(); - } - } - }); -} - /** * Returns the `basename` of `pathToFile` without the file extension. */ @@ -213,7 +152,6 @@ function getChannelFile(platform) { module.exports = { collectUnusedDependencies, - adjustArchiveStructure, isZip, unpack, isNightly,