From ca0ab40541f326a6e2326f4f8dde6c5cc508f855 Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Thu, 29 Jul 2021 07:54:12 -0700 Subject: [PATCH 01/10] feat!(core): require minimum Forge version in templates BREAKING CHANGE: Electron Forge templates compatible with v6 must specify the minimum Forge version supported by the template, using the `minimumForgeVersion` attribute on the class implementing `ForgeTemplate`. This is largely to prevent the built-in templates from v5 from being used with v6. Note that actually checking whether the version matches has not been implemented yet. --- packages/api/core/src/api/init.ts | 4 ++++ packages/template/base/src/BaseTemplate.ts | 2 ++ packages/utils/types/src/index.ts | 1 + 3 files changed, 7 insertions(+) diff --git a/packages/api/core/src/api/init.ts b/packages/api/core/src/api/init.ts index 0263e57818..1478817543 100644 --- a/packages/api/core/src/api/init.ts +++ b/packages/api/core/src/api/init.ts @@ -51,6 +51,10 @@ export default async ({ await initGit(dir); const templateModule = await findTemplate(dir, template); + if (!templateModule.minimumForgeVersion) { + throw new Error(`Cannot use a template (${template}) with this version of Electron Forge that does not specify its minimum required Forge version.`); + } + if (typeof templateModule.initializeTemplate === 'function') { await templateModule.initializeTemplate(dir, { copyCIFiles }); const packageJSON = await readRawPackageJson(dir); diff --git a/packages/template/base/src/BaseTemplate.ts b/packages/template/base/src/BaseTemplate.ts index b76619adae..f05afda7b0 100644 --- a/packages/template/base/src/BaseTemplate.ts +++ b/packages/template/base/src/BaseTemplate.ts @@ -14,6 +14,8 @@ const tmplDir = path.resolve(__dirname, '../tmpl'); export class BaseTemplate implements ForgeTemplate { public templateDir = tmplDir; + public minimumForgeVersion = currentForgeVersion; + get devDependencies(): string[] { const packageJSONPath = path.join(this.templateDir, 'package.json'); if (fs.pathExistsSync(packageJSONPath)) { diff --git a/packages/utils/types/src/index.ts b/packages/utils/types/src/index.ts index dde45a6478..8c5e40dbd1 100644 --- a/packages/utils/types/src/index.ts +++ b/packages/utils/types/src/index.ts @@ -124,6 +124,7 @@ export interface InitTemplateOptions { } export interface ForgeTemplate { + minimumForgeVersion?: string; dependencies?: string[]; devDependencies?: string[]; initializeTemplate?: (dir: string, options: InitTemplateOptions) => void; From 79bc20a8533d4edeb4a48b486034b99a3964771e Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Thu, 29 Jul 2021 22:55:49 -0700 Subject: [PATCH 02/10] Implement minimum version check --- packages/api/core/src/api/init.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/api/core/src/api/init.ts b/packages/api/core/src/api/init.ts index 1478817543..823b0838f1 100644 --- a/packages/api/core/src/api/init.ts +++ b/packages/api/core/src/api/init.ts @@ -2,6 +2,7 @@ import { asyncOra } from '@electron-forge/async-ora'; import debug from 'debug'; import fs from 'fs-extra'; import path from 'path'; +import semver from 'semver'; import findTemplate from './init-scripts/find-template'; import initDirectory from './init-scripts/init-directory'; @@ -55,6 +56,11 @@ export default async ({ throw new Error(`Cannot use a template (${template}) with this version of Electron Forge that does not specify its minimum required Forge version.`); } + const forgeVersion = (await readRawPackageJson(path.join(__dirname, '..', '..', 'package.json'))).version; + if (semver.lt(forgeVersion, templateModule.minimumForgeVersion)) { + throw new Error(`Template (${template}) is not compatible with this version of Electron Forge (${forgeVersion}), it requires version ${templateModule.minimumForgeVersion} or later`); + } + if (typeof templateModule.initializeTemplate === 'function') { await templateModule.initializeTemplate(dir, { copyCIFiles }); const packageJSON = await readRawPackageJson(dir); From aa011bc8da74dbc75f82667119fbfca794ce187e Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Thu, 29 Jul 2021 23:05:09 -0700 Subject: [PATCH 03/10] s/minimumForgeVersion/requiredForgeVersion/g --- packages/api/core/src/api/init.ts | 8 ++++---- packages/template/base/src/BaseTemplate.ts | 2 +- packages/utils/types/src/index.ts | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/api/core/src/api/init.ts b/packages/api/core/src/api/init.ts index 823b0838f1..c7ad2fdfd7 100644 --- a/packages/api/core/src/api/init.ts +++ b/packages/api/core/src/api/init.ts @@ -52,13 +52,13 @@ export default async ({ await initGit(dir); const templateModule = await findTemplate(dir, template); - if (!templateModule.minimumForgeVersion) { - throw new Error(`Cannot use a template (${template}) with this version of Electron Forge that does not specify its minimum required Forge version.`); + if (!templateModule.requiredForgeVersion) { + throw new Error(`Cannot use a template (${template}) with this version of Electron Forge that does not specify its required Forge version.`); } const forgeVersion = (await readRawPackageJson(path.join(__dirname, '..', '..', 'package.json'))).version; - if (semver.lt(forgeVersion, templateModule.minimumForgeVersion)) { - throw new Error(`Template (${template}) is not compatible with this version of Electron Forge (${forgeVersion}), it requires version ${templateModule.minimumForgeVersion} or later`); + if (!semver.satisfies(forgeVersion, templateModule.requiredForgeVersion)) { + throw new Error(`Template (${template}) is not compatible with this version of Electron Forge (${forgeVersion}), it requires ${templateModule.requiredForgeVersion}`); } if (typeof templateModule.initializeTemplate === 'function') { diff --git a/packages/template/base/src/BaseTemplate.ts b/packages/template/base/src/BaseTemplate.ts index f05afda7b0..d5e9b3babc 100644 --- a/packages/template/base/src/BaseTemplate.ts +++ b/packages/template/base/src/BaseTemplate.ts @@ -14,7 +14,7 @@ const tmplDir = path.resolve(__dirname, '../tmpl'); export class BaseTemplate implements ForgeTemplate { public templateDir = tmplDir; - public minimumForgeVersion = currentForgeVersion; + public requiredForgeVersion = currentForgeVersion; get devDependencies(): string[] { const packageJSONPath = path.join(this.templateDir, 'package.json'); diff --git a/packages/utils/types/src/index.ts b/packages/utils/types/src/index.ts index 8c5e40dbd1..5235d8de52 100644 --- a/packages/utils/types/src/index.ts +++ b/packages/utils/types/src/index.ts @@ -124,7 +124,7 @@ export interface InitTemplateOptions { } export interface ForgeTemplate { - minimumForgeVersion?: string; + requiredForgeVersion?: string; dependencies?: string[]; devDependencies?: string[]; initializeTemplate?: (dir: string, options: InitTemplateOptions) => void; From fd9adfdeca9245dc6b9a287a0c5baa7d8fab93a1 Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Thu, 29 Jul 2021 23:16:23 -0700 Subject: [PATCH 04/10] Fix test --- packages/api/core/test/fixture/custom_init/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/api/core/test/fixture/custom_init/index.js b/packages/api/core/test/fixture/custom_init/index.js index 80c99dc6c9..29aa9907e3 100644 --- a/packages/api/core/test/fixture/custom_init/index.js +++ b/packages/api/core/test/fixture/custom_init/index.js @@ -3,6 +3,7 @@ const fs = require('fs-extra'); const path = require('path'); module.exports = { + requiredForgeVersion: '>= 6.0.0-beta.1' dependencies: ['debug'], devDependencies: ['lodash'], initializeTemplate: async (directory) => { From 4efe1b7e200f08da8126242bfccd247e5fbc5f02 Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Thu, 29 Jul 2021 23:22:29 -0700 Subject: [PATCH 05/10] Fix typo --- packages/api/core/test/fixture/custom_init/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/api/core/test/fixture/custom_init/index.js b/packages/api/core/test/fixture/custom_init/index.js index 29aa9907e3..608d19119a 100644 --- a/packages/api/core/test/fixture/custom_init/index.js +++ b/packages/api/core/test/fixture/custom_init/index.js @@ -3,7 +3,7 @@ const fs = require('fs-extra'); const path = require('path'); module.exports = { - requiredForgeVersion: '>= 6.0.0-beta.1' + requiredForgeVersion: '>= 6.0.0-beta.1', dependencies: ['debug'], devDependencies: ['lodash'], initializeTemplate: async (directory) => { From 784486b343d139559884377ffdbcd003129694d7 Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Thu, 29 Jul 2021 23:41:01 -0700 Subject: [PATCH 06/10] readRawPackageJson takes a directory --- packages/api/core/src/api/init.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/api/core/src/api/init.ts b/packages/api/core/src/api/init.ts index c7ad2fdfd7..00b841aff6 100644 --- a/packages/api/core/src/api/init.ts +++ b/packages/api/core/src/api/init.ts @@ -56,7 +56,7 @@ export default async ({ throw new Error(`Cannot use a template (${template}) with this version of Electron Forge that does not specify its required Forge version.`); } - const forgeVersion = (await readRawPackageJson(path.join(__dirname, '..', '..', 'package.json'))).version; + const forgeVersion = (await readRawPackageJson(path.join(__dirname, '..', '..'))).version; if (!semver.satisfies(forgeVersion, templateModule.requiredForgeVersion)) { throw new Error(`Template (${template}) is not compatible with this version of Electron Forge (${forgeVersion}), it requires ${templateModule.requiredForgeVersion}`); } From 7dfc6b417e2127a6bd80c394ca717a7ee8ad8716 Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Fri, 30 Jul 2021 01:01:49 -0700 Subject: [PATCH 07/10] Add tests for thrown errors --- packages/api/core/package.json | 5 +-- packages/api/core/src/api/init.ts | 2 +- .../index.js | 1 + .../template-sans-forge-version/index.js | 1 + .../template-sans-forge-version/package.json | 1 + packages/api/core/test/slow/api_spec_slow.ts | 34 +++++++++++++++++++ 6 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 packages/api/core/test/fixture/template-nonmatching-forge-version/index.js create mode 100644 packages/api/core/test/fixture/template-sans-forge-version/index.js create mode 100644 packages/api/core/test/fixture/template-sans-forge-version/package.json diff --git a/packages/api/core/package.json b/packages/api/core/package.json index 8fff42d934..02b93af884 100644 --- a/packages/api/core/package.json +++ b/packages/api/core/package.json @@ -9,9 +9,10 @@ "license": "MIT", "scripts": { "coverage:base": "nyc yarn test:base", - "test": "yarn test:base test/**/**/*_spec.ts", + "test": "yarn test:base test/**/*_spec.ts test/**/*_spec_slow.ts", "test:base": "cross-env TS_NODE_FILES=1 mocha --config ../../../.mocharc.js", - "test:fast": "yarn test:base test/fast/**/*_spec.ts" + "test:fast": "yarn test:base test/fast/**/*_spec.ts", + "test:slow": "yarn test:base test/slow/**/*_spec_slow.ts" }, "devDependencies": { "@electron-forge/maker-appx": "6.0.0-beta.59", diff --git a/packages/api/core/src/api/init.ts b/packages/api/core/src/api/init.ts index 00b841aff6..c10202d36c 100644 --- a/packages/api/core/src/api/init.ts +++ b/packages/api/core/src/api/init.ts @@ -53,7 +53,7 @@ export default async ({ const templateModule = await findTemplate(dir, template); if (!templateModule.requiredForgeVersion) { - throw new Error(`Cannot use a template (${template}) with this version of Electron Forge that does not specify its required Forge version.`); + throw new Error(`Cannot use a template (${template}) with this version of Electron Forge, as it does not specify its required Forge version.`); } const forgeVersion = (await readRawPackageJson(path.join(__dirname, '..', '..'))).version; diff --git a/packages/api/core/test/fixture/template-nonmatching-forge-version/index.js b/packages/api/core/test/fixture/template-nonmatching-forge-version/index.js new file mode 100644 index 0000000000..46f54afa04 --- /dev/null +++ b/packages/api/core/test/fixture/template-nonmatching-forge-version/index.js @@ -0,0 +1 @@ +module.exports = { requiredForgeVersion: "6.0.0-beta.0" } diff --git a/packages/api/core/test/fixture/template-sans-forge-version/index.js b/packages/api/core/test/fixture/template-sans-forge-version/index.js new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/packages/api/core/test/fixture/template-sans-forge-version/index.js @@ -0,0 +1 @@ + diff --git a/packages/api/core/test/fixture/template-sans-forge-version/package.json b/packages/api/core/test/fixture/template-sans-forge-version/package.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/packages/api/core/test/fixture/template-sans-forge-version/package.json @@ -0,0 +1 @@ +{} diff --git a/packages/api/core/test/slow/api_spec_slow.ts b/packages/api/core/test/slow/api_spec_slow.ts index 0c8bf5b5fe..93655a6afe 100644 --- a/packages/api/core/test/slow/api_spec_slow.ts +++ b/packages/api/core/test/slow/api_spec_slow.ts @@ -121,6 +121,40 @@ for (const nodeInstaller of ['npm', 'yarn']) { }); }); + describe('init (with a templater sans required Forge version)', () => { + before(async () => { + dir = await ensureTestDirIsNonexistent(); + }); + + it('should fail in initializing', async () => { + await expect(forge.init({ + dir, + template: path.resolve(__dirname, '../fixture/template-sans-forge-version'), + })).to.eventually.be.rejectedWith(/it does not specify its required Forge version\.$/); + }); + + after(async () => { + await fs.remove(dir); + }); + }); + + describe('init (with a templater with a non-matching Forge version)', () => { + before(async () => { + dir = await ensureTestDirIsNonexistent(); + }); + + it('should fail in initializing', async () => { + await expect(forge.init({ + dir, + template: path.resolve(__dirname, '../fixture/template-nonmatching-forge-version'), + })).to.eventually.be.rejectedWith(/is not compatible with this version of Electron Forge/); + }); + + after(async () => { + await fs.remove(dir); + }); + }); + describe('init (with a nonexistent templater)', () => { before(async () => { dir = await ensureTestDirIsNonexistent(); From 9d33f5b7666d47571ae0251a4198c11681ff8e3e Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Fri, 30 Jul 2021 07:19:21 -0700 Subject: [PATCH 08/10] refactor: move validation code to its own function --- packages/api/core/src/api/init.ts | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/packages/api/core/src/api/init.ts b/packages/api/core/src/api/init.ts index c10202d36c..f046248a89 100644 --- a/packages/api/core/src/api/init.ts +++ b/packages/api/core/src/api/init.ts @@ -1,5 +1,6 @@ import { asyncOra } from '@electron-forge/async-ora'; import debug from 'debug'; +import { ForgeTemplate } from '@electron-forge/shared-types'; import fs from 'fs-extra'; import path from 'path'; import semver from 'semver'; @@ -37,6 +38,17 @@ export interface InitOptions { template?: string; } +function validateTemplate(template: string, templateModule: ForgeTemplate): void { + if (!templateModule.requiredForgeVersion) { + throw new Error(`Cannot use a template (${template}) with this version of Electron Forge, as it does not specify its required Forge version.`); + } + + const forgeVersion = (await readRawPackageJson(path.join(__dirname, '..', '..'))).version; + if (!semver.satisfies(forgeVersion, templateModule.requiredForgeVersion)) { + throw new Error(`Template (${template}) is not compatible with this version of Electron Forge (${forgeVersion}), it requires ${templateModule.requiredForgeVersion}`); + } +} + export default async ({ dir = process.cwd(), interactive = false, @@ -52,14 +64,7 @@ export default async ({ await initGit(dir); const templateModule = await findTemplate(dir, template); - if (!templateModule.requiredForgeVersion) { - throw new Error(`Cannot use a template (${template}) with this version of Electron Forge, as it does not specify its required Forge version.`); - } - - const forgeVersion = (await readRawPackageJson(path.join(__dirname, '..', '..'))).version; - if (!semver.satisfies(forgeVersion, templateModule.requiredForgeVersion)) { - throw new Error(`Template (${template}) is not compatible with this version of Electron Forge (${forgeVersion}), it requires ${templateModule.requiredForgeVersion}`); - } + validateTemplate(template, templateModule); if (typeof templateModule.initializeTemplate === 'function') { await templateModule.initializeTemplate(dir, { copyCIFiles }); From 7b627431d0138f083bf82c52be810d9530818b26 Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Fri, 30 Jul 2021 07:23:35 -0700 Subject: [PATCH 09/10] async function --- packages/api/core/src/api/init.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/api/core/src/api/init.ts b/packages/api/core/src/api/init.ts index f046248a89..59b4ad394d 100644 --- a/packages/api/core/src/api/init.ts +++ b/packages/api/core/src/api/init.ts @@ -38,7 +38,7 @@ export interface InitOptions { template?: string; } -function validateTemplate(template: string, templateModule: ForgeTemplate): void { +async function validateTemplate(template: string, templateModule: ForgeTemplate): void { if (!templateModule.requiredForgeVersion) { throw new Error(`Cannot use a template (${template}) with this version of Electron Forge, as it does not specify its required Forge version.`); } @@ -64,7 +64,7 @@ export default async ({ await initGit(dir); const templateModule = await findTemplate(dir, template); - validateTemplate(template, templateModule); + await validateTemplate(template, templateModule); if (typeof templateModule.initializeTemplate === 'function') { await templateModule.initializeTemplate(dir, { copyCIFiles }); From 2fa573a1985503e566c921477f4abf05e4f0bf3a Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Fri, 30 Jul 2021 07:27:32 -0700 Subject: [PATCH 10/10] Fix return type --- packages/api/core/src/api/init.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/api/core/src/api/init.ts b/packages/api/core/src/api/init.ts index 59b4ad394d..aae294f4af 100644 --- a/packages/api/core/src/api/init.ts +++ b/packages/api/core/src/api/init.ts @@ -38,7 +38,7 @@ export interface InitOptions { template?: string; } -async function validateTemplate(template: string, templateModule: ForgeTemplate): void { +async function validateTemplate(template: string, templateModule: ForgeTemplate): Promise { if (!templateModule.requiredForgeVersion) { throw new Error(`Cannot use a template (${template}) with this version of Electron Forge, as it does not specify its required Forge version.`); }