mirror of
https://github.com/scratchfoundation/scratch-desktop.git
synced 2025-01-24 04:59:47 -05:00
modularize npm scripts, support non-signed builds, ...
This commit is contained in:
parent
8cf475416c
commit
d08841382a
4 changed files with 127 additions and 31 deletions
|
@ -68,6 +68,9 @@ commands:
|
||||||
paths:
|
paths:
|
||||||
- << parameters.npmCacheDir >>
|
- << parameters.npmCacheDir >>
|
||||||
key: npm-cache-{{ arch }}-{{ checksum "package-lock.json" }}
|
key: npm-cache-{{ arch }}-{{ checksum "package-lock.json" }}
|
||||||
|
- run:
|
||||||
|
name: Test
|
||||||
|
command: npm run test
|
||||||
- run:
|
- run:
|
||||||
name: Build
|
name: Build
|
||||||
command: npm run dist
|
command: npm run dist
|
||||||
|
|
|
@ -3,7 +3,6 @@ directories:
|
||||||
output: dist
|
output: dist
|
||||||
appId: edu.mit.scratch.scratch-desktop
|
appId: edu.mit.scratch.scratch-desktop
|
||||||
productName: "Scratch Desktop"
|
productName: "Scratch Desktop"
|
||||||
afterSign: "scripts/afterSign.js"
|
|
||||||
mac:
|
mac:
|
||||||
category: public.app-category.education
|
category: public.app-category.education
|
||||||
entitlements: buildResources/entitlements.mac.plist
|
entitlements: buildResources/entitlements.mac.plist
|
||||||
|
@ -19,7 +18,6 @@ mac:
|
||||||
target:
|
target:
|
||||||
- dmg
|
- dmg
|
||||||
- mas
|
- mas
|
||||||
type: distribution
|
|
||||||
mas:
|
mas:
|
||||||
category: public.app-category.education
|
category: public.app-category.education
|
||||||
entitlements: buildResources/entitlements.mas.plist
|
entitlements: buildResources/entitlements.mas.plist
|
||||||
|
|
21
package.json
21
package.json
|
@ -6,16 +6,21 @@
|
||||||
"version": "3.12.0",
|
"version": "3.12.0",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"postinstall": "node ./scripts/npm-in-gui.js install",
|
"clean": "rimraf ./dist ./static/assets && node ./scripts/npm-in-gui.js run clean",
|
||||||
"start": "electron-webpack dev --bail --display-error-details --env.minify=false",
|
"start": "electron-webpack dev --bail --display-error-details --env.minify=false",
|
||||||
"build-gui": "node ./scripts/npm-in-gui.js run build",
|
"compile": "npm run build-gui && electron-webpack --bail --display-error-details --env.minify=false",
|
||||||
"watch-gui": "node ./scripts/npm-in-gui.js run watch",
|
|
||||||
"clean": "rimraf ./dist ./static/assets ./node_modules/scratch-gui/build ./node_modules/scratch-gui/dist",
|
|
||||||
"compile": "rimraf ./dist/ && electron-webpack --bail --display-error-details --env.minify=false",
|
|
||||||
"fetch": "rimraf ./static/assets/ && mkdirp ./static/assets/ && node ./scripts/fetchMediaLibraryAssets.js",
|
"fetch": "rimraf ./static/assets/ && mkdirp ./static/assets/ && node ./scripts/fetchMediaLibraryAssets.js",
|
||||||
"dist": "npm run build-gui && npm run fetch && npm run compile -p && node ./scripts/electron-builder-wrapper.js",
|
"build": "npm run build:dev",
|
||||||
"dist:dir": "npm run dist -- --dir -c.compression=store -c.mac.identity=null",
|
"build:dev": "npm run compile && npm run doBuild -- --mode=dev",
|
||||||
"lint": "eslint --cache --color --ext .jsx,.js ."
|
"build:dir": "npm run compile && npm run doBuild -- --mode=dir",
|
||||||
|
"build:dist": "npm run compile && npm run doBuild -- --mode=dist",
|
||||||
|
"doBuild": "node ./scripts/electron-builder-wrapper.js",
|
||||||
|
"dist": "npm run clean && npm run compile && npm run fetch && npm run doBuild -- --mode=dist",
|
||||||
|
"test": "npm run test:lint",
|
||||||
|
"test:lint": "eslint --cache --color --ext .jsx,.js .",
|
||||||
|
"postinstall": "node ./scripts/npm-in-gui.js install",
|
||||||
|
"build-gui": "node ./scripts/npm-in-gui.js run build",
|
||||||
|
"watch-gui": "node ./scripts/npm-in-gui.js run watch"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|
|
@ -38,20 +38,40 @@ const getPlatformFlag = function () {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run `electron-builder` once to build one or more target(s).
|
* Run `electron-builder` once to build one or more target(s).
|
||||||
* @param {string} targetGroup - the target(s) to build in this pass.
|
* @param {object} wrapperConfig - overall configuration object for the wrapper script.
|
||||||
* If the `targetGroup` is `'nsis'` then the environment must contain code-signing config (CSC_* or WIN_CSC_*).
|
* @param {object} target - the target to build in this call.
|
||||||
* If the `targetGroup` is `'appx'` then code-signing config will be stripped from the environment if present.
|
* If the `target.name` is `'nsis'` then the environment must contain code-signing config (CSC_* or WIN_CSC_*).
|
||||||
|
* If the `target.name` is `'appx'` then code-signing config will be stripped from the environment if present.
|
||||||
*/
|
*/
|
||||||
const runBuilder = function (targetGroup) {
|
const runBuilder = function (wrapperConfig, target) {
|
||||||
// the appx build fails if CSC_* or WIN_CSC_* variables are set
|
// the AppX build fails if CSC_* or WIN_CSC_* variables are set
|
||||||
const shouldStripCSC = (targetGroup === 'appx');
|
const shouldStripCSC = (target.name === 'appx');
|
||||||
const childEnvironment = shouldStripCSC ? stripCSC(process.env) : process.env;
|
const childEnvironment = shouldStripCSC ? stripCSC(process.env) : process.env;
|
||||||
if ((targetGroup === 'nsis') && !(childEnvironment.CSC_LINK || childEnvironment.WIN_CSC_LINK)) {
|
if ((target.name === 'nsis') && !(childEnvironment.CSC_LINK || childEnvironment.WIN_CSC_LINK)) {
|
||||||
throw new Error(`NSIS build requires CSC_LINK or WIN_CSC_LINK`);
|
throw new Error(`NSIS build requires CSC_LINK or WIN_CSC_LINK`);
|
||||||
}
|
}
|
||||||
const platformFlag = getPlatformFlag();
|
const platformFlag = getPlatformFlag();
|
||||||
const customArgs = process.argv.slice(2); // remove `node` and `this-script.js`
|
let allArgs = [platformFlag, target.name];
|
||||||
const allArgs = [platformFlag, targetGroup, ...customArgs];
|
if (target.platform === 'darwin') {
|
||||||
|
allArgs.push(`--c.mac.type=${wrapperConfig.mode === 'dist' ? 'distribution' : 'development'}`);
|
||||||
|
}
|
||||||
|
if (wrapperConfig.doSign) {
|
||||||
|
// really this is "notarize only if we also sign"
|
||||||
|
allArgs.push('--c.afterSign=scripts/afterSign.js');
|
||||||
|
} else {
|
||||||
|
if (target.name === 'mas') {
|
||||||
|
// electron-builder doesn't seem to support this configuration even if mac.type is "development"
|
||||||
|
console.log(`skipping target "${target.name}" because code-signing is disabled`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (target.platform === 'darwin') {
|
||||||
|
allArgs.push('--c.mac.identity=null');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!wrapperConfig.doPackage) {
|
||||||
|
allArgs.push('--dir', '--c.compression=store');
|
||||||
|
}
|
||||||
|
allArgs = allArgs.concat(wrapperConfig.builderArgs);
|
||||||
console.log(`running electron-builder with arguments: ${allArgs}`);
|
console.log(`running electron-builder with arguments: ${allArgs}`);
|
||||||
const result = spawnSync('electron-builder', allArgs, {
|
const result = spawnSync('electron-builder', allArgs, {
|
||||||
env: childEnvironment,
|
env: childEnvironment,
|
||||||
|
@ -70,27 +90,97 @@ const runBuilder = function (targetGroup) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {Array.<string>} - the default list of target groups on this platform. Each item in the array represents
|
* @returns {Array.<object>} - the default list of targets on this platform. Each item in the array represents one
|
||||||
* one call to `runBuilder` for one or more build target(s).
|
* call to `runBuilder` for exactly one build target. In theory electron-builder can build two or more targets at the
|
||||||
|
* same time but doing so limits has unwanted side effects on both macOS and Windows (see function body).
|
||||||
*/
|
*/
|
||||||
const calculateTargets = function () {
|
const calculateTargets = function () {
|
||||||
|
const targets = {
|
||||||
|
macAppStore: {
|
||||||
|
name: 'mas',
|
||||||
|
platform: 'darwin'
|
||||||
|
},
|
||||||
|
macAppStoreDev: {
|
||||||
|
name: 'mas-dev',
|
||||||
|
platform: 'darwin'
|
||||||
|
},
|
||||||
|
macDirectDownload: {
|
||||||
|
name: 'dmg',
|
||||||
|
platform: 'darwin'
|
||||||
|
},
|
||||||
|
microsoftStore: {
|
||||||
|
name: 'appx',
|
||||||
|
platform: 'win32'
|
||||||
|
},
|
||||||
|
windowsDirectDownload: {
|
||||||
|
name: 'nsis:ia32',
|
||||||
|
platform: 'win32'
|
||||||
|
}
|
||||||
|
};
|
||||||
switch (process.platform) {
|
switch (process.platform) {
|
||||||
case 'win32':
|
case 'win32':
|
||||||
// run in two passes so we can skip signing the appx
|
// Run in two passes so we can skip signing the AppX for distribution through the MS Store.
|
||||||
return ['nsis:ia32', 'appx'];
|
return [targets.microsoftStore, targets.windowsDirectDownload];
|
||||||
case 'darwin':
|
case 'darwin':
|
||||||
// Running 'dmg' and 'mas' in the same pass causes electron-builder to skip signing the non-MAS app copy.
|
// Running 'dmg' and 'mas' in the same pass causes electron-builder to skip signing the non-MAS app copy.
|
||||||
// Running them as separate passes means they both get signed.
|
// Running them as separate passes means they can both get signed.
|
||||||
// Seems like a bug in electron-builder...
|
// Seems like a bug in electron-builder...
|
||||||
// Running the 'mas' build first means that its output is available while we wait for 'dmg' notarization.
|
// Running the 'mas' build first means that its output is available while we wait for 'dmg' notarization.
|
||||||
// Add 'mas-dev' here to test a 'mas'-like build locally. You'll need a Mac Developer provisioning profile.
|
// Add macAppStoreDev here to test a MAS-like build locally. You'll need a Mac Developer provisioning profile.
|
||||||
return ['mas', 'dmg'];
|
return [targets.macAppStore, targets.macDirectDownload];
|
||||||
}
|
}
|
||||||
throw new Error(`Could not determine targets for platform: ${process.platform}`);
|
throw new Error(`Could not determine targets for platform: ${process.platform}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: allow user to specify targets? We could theoretically build NSIS on Mac, for example.
|
const parseArgs = function () {
|
||||||
const targets = calculateTargets();
|
const scriptArgs = process.argv.slice(2); // remove `node` and `this-script.js`
|
||||||
for (const targetGroup of targets) {
|
const builderArgs = [];
|
||||||
runBuilder(targetGroup);
|
let mode = 'dev'; // default
|
||||||
}
|
|
||||||
|
for (const arg of scriptArgs) {
|
||||||
|
const modeSplit = arg.split(/--mode(\s+|=)/);
|
||||||
|
if (modeSplit.length === 3) {
|
||||||
|
mode = modeSplit[2];
|
||||||
|
} else {
|
||||||
|
builderArgs.push(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let doPackage;
|
||||||
|
let doSign;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case 'dev':
|
||||||
|
doPackage = true;
|
||||||
|
doSign = false;
|
||||||
|
break;
|
||||||
|
case 'dir':
|
||||||
|
doPackage = false;
|
||||||
|
doSign = false;
|
||||||
|
break;
|
||||||
|
case 'dist':
|
||||||
|
doPackage = true;
|
||||||
|
doSign = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: allow user to specify targets? We could theoretically build NSIS on Mac, for example.
|
||||||
|
const targets = calculateTargets();
|
||||||
|
|
||||||
|
return {
|
||||||
|
builderArgs,
|
||||||
|
doPackage, // false = build to directory
|
||||||
|
doSign,
|
||||||
|
mode,
|
||||||
|
targets
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const main = function () {
|
||||||
|
const wrapperConfig = parseArgs();
|
||||||
|
|
||||||
|
for (const target of wrapperConfig.targets) {
|
||||||
|
runBuilder(wrapperConfig, target);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
main();
|
||||||
|
|
Loading…
Reference in a new issue