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 0263e57818..aae294f4af 100644 --- a/packages/api/core/src/api/init.ts +++ b/packages/api/core/src/api/init.ts @@ -1,7 +1,9 @@ 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'; import findTemplate from './init-scripts/find-template'; import initDirectory from './init-scripts/init-directory'; @@ -36,6 +38,17 @@ export interface InitOptions { template?: string; } +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.`); + } + + 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, @@ -51,6 +64,8 @@ export default async ({ await initGit(dir); const templateModule = await findTemplate(dir, template); + await validateTemplate(template, templateModule); + if (typeof templateModule.initializeTemplate === 'function') { await templateModule.initializeTemplate(dir, { copyCIFiles }); const packageJSON = await readRawPackageJson(dir); diff --git a/packages/api/core/test/fixture/custom_init/index.js b/packages/api/core/test/fixture/custom_init/index.js index 80c99dc6c9..608d19119a 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) => { 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(); diff --git a/packages/template/base/src/BaseTemplate.ts b/packages/template/base/src/BaseTemplate.ts index b76619adae..d5e9b3babc 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 requiredForgeVersion = 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..5235d8de52 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 { + requiredForgeVersion?: string; dependencies?: string[]; devDependencies?: string[]; initializeTemplate?: (dir: string, options: InitTemplateOptions) => void;