2020-04-26 20:33:39 +00:00
|
|
|
const { appConfig } = require('../config');
|
2019-09-18 00:02:42 +00:00
|
|
|
const packageJson = require('../package.json');
|
2018-10-20 02:11:58 +00:00
|
|
|
const childProcess = require('child_process');
|
2017-11-20 16:07:36 +00:00
|
|
|
const webpack = require('webpack');
|
2020-02-06 13:41:56 +00:00
|
|
|
const licenseChecker = require('license-checker');
|
2017-11-20 16:07:36 +00:00
|
|
|
const rimraf = require('rimraf');
|
|
|
|
const ncp = require('ncp').ncp;
|
|
|
|
const path = require('path');
|
|
|
|
const mkdirp = require('mkdirp');
|
2017-11-26 20:45:40 +00:00
|
|
|
const fs = require('fs');
|
2020-04-26 20:33:39 +00:00
|
|
|
const { APP_ID_INSOMNIA, APP_ID_DESIGNER } = require('../config');
|
2017-11-20 16:07:36 +00:00
|
|
|
|
2017-11-26 20:45:40 +00:00
|
|
|
// Start build if ran from CLI
|
2017-11-26 23:04:47 +00:00
|
|
|
if (require.main === module) {
|
2017-11-26 20:45:40 +00:00
|
|
|
process.nextTick(async () => {
|
|
|
|
await module.exports.start();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-04-26 20:33:39 +00:00
|
|
|
module.exports.start = async function(forcedVersion = null) {
|
|
|
|
const buildContext = getBuildContext();
|
|
|
|
if (!buildContext.version) {
|
|
|
|
console.log(`[build] Skipping build for ref "${buildContext.gitRef}"`);
|
|
|
|
process.exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (process.env.APP_ID) {
|
|
|
|
console.log('Should not set APP_ID for builds. Use Git tag instead');
|
|
|
|
process.exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Configure APP_ID env based on what we detected
|
|
|
|
if (buildContext.app === 'designer') {
|
|
|
|
process.env.APP_ID = APP_ID_DESIGNER;
|
|
|
|
} else {
|
|
|
|
process.env.APP_ID = APP_ID_INSOMNIA;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (appConfig().version !== buildContext.version) {
|
2020-05-14 22:54:07 +00:00
|
|
|
console.log(
|
|
|
|
`[build] App version mismatch with Git tag ${appConfig().version} != ${buildContext.version}`,
|
|
|
|
);
|
2020-04-26 20:33:39 +00:00
|
|
|
process.exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// These must be required after APP_ID environment variable is set above
|
|
|
|
const configRenderer = require('../webpack/webpack.config.production.babel');
|
|
|
|
const configMain = require('../webpack/webpack.config.electron.babel');
|
|
|
|
|
|
|
|
console.log(`[build] Starting build for ref "${buildContext.gitRef}"`);
|
|
|
|
console.log(`[build] npm: ${childProcess.spawnSync('npm', ['--version']).stdout}`.trim());
|
|
|
|
console.log(`[build] node: ${childProcess.spawnSync('node', ['--version']).stdout}`.trim());
|
2018-10-20 02:11:58 +00:00
|
|
|
|
2019-11-26 20:50:06 +00:00
|
|
|
if (process.version.indexOf('v10.') !== 0) {
|
|
|
|
console.log('[build] Node v10.x.x is required to build');
|
2019-10-30 14:24:32 +00:00
|
|
|
process.exit(1);
|
|
|
|
}
|
|
|
|
|
2017-11-20 16:07:36 +00:00
|
|
|
// Remove folders first
|
|
|
|
console.log('[build] Removing existing directories');
|
|
|
|
await emptyDir('../build');
|
|
|
|
|
|
|
|
// Build the things
|
2020-02-06 13:41:56 +00:00
|
|
|
console.log('[build] Building license list');
|
|
|
|
await buildLicenseList('../', '../build/opensource-licenses.txt');
|
2019-04-19 22:56:50 +00:00
|
|
|
console.log('[build] Building Webpack renderer');
|
2017-11-20 16:07:36 +00:00
|
|
|
await buildWebpack(configRenderer);
|
2019-04-19 22:56:50 +00:00
|
|
|
console.log('[build] Building Webpack main');
|
2017-11-20 16:07:36 +00:00
|
|
|
await buildWebpack(configMain);
|
|
|
|
|
|
|
|
// Copy necessary files
|
|
|
|
console.log('[build] Copying files');
|
|
|
|
await copyFiles('../bin', '../build/');
|
|
|
|
await copyFiles('../app/static', '../build/static');
|
2020-04-26 20:33:39 +00:00
|
|
|
await copyFiles(`../app/icons/${appConfig().appId}`, '../build/');
|
2017-11-20 16:07:36 +00:00
|
|
|
|
2017-11-26 20:45:40 +00:00
|
|
|
// Generate package.json
|
2020-05-14 22:54:07 +00:00
|
|
|
await generatePackageJson('../package.json', '../build/package.json', forcedVersion);
|
2017-11-26 20:45:40 +00:00
|
|
|
|
2017-11-20 16:07:36 +00:00
|
|
|
// Install Node modules
|
|
|
|
console.log('[build] Installing dependencies');
|
|
|
|
await install('../build/');
|
|
|
|
|
|
|
|
console.log('[build] Complete!');
|
2020-04-26 20:33:39 +00:00
|
|
|
return buildContext;
|
2017-11-26 20:45:40 +00:00
|
|
|
};
|
2017-11-20 16:07:36 +00:00
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
async function buildWebpack(config) {
|
2017-11-20 16:07:36 +00:00
|
|
|
return new Promise((resolve, reject) => {
|
2019-09-18 00:02:42 +00:00
|
|
|
const compiler = webpack(config);
|
|
|
|
compiler.run((err, stats) => {
|
2019-04-19 22:56:50 +00:00
|
|
|
if (err) {
|
2017-11-20 16:07:36 +00:00
|
|
|
reject(err);
|
2019-04-19 22:56:50 +00:00
|
|
|
} else if (stats.hasErrors()) {
|
|
|
|
reject(new Error('Failed to build webpack'));
|
2019-09-18 00:02:42 +00:00
|
|
|
console.log(stats.toJson().errors);
|
2017-11-20 16:07:36 +00:00
|
|
|
} else {
|
|
|
|
resolve();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
async function emptyDir(relPath) {
|
2017-11-20 16:07:36 +00:00
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
const dir = path.resolve(__dirname, relPath);
|
|
|
|
rimraf(dir, err => {
|
|
|
|
if (err) {
|
|
|
|
reject(err);
|
|
|
|
} else {
|
|
|
|
mkdirp.sync(dir);
|
|
|
|
resolve();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
async function copyFiles(relSource, relDest) {
|
2017-11-20 16:07:36 +00:00
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
const source = path.resolve(__dirname, relSource);
|
|
|
|
const dest = path.resolve(__dirname, relDest);
|
2020-04-26 20:33:39 +00:00
|
|
|
console.log(`[build] copy "${relSource}" to "${relDest}"`);
|
2017-11-20 16:07:36 +00:00
|
|
|
ncp(source, dest, err => {
|
|
|
|
if (err) {
|
|
|
|
reject(err);
|
|
|
|
} else {
|
|
|
|
resolve();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-02-06 13:41:56 +00:00
|
|
|
async function buildLicenseList(relSource, relDest) {
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
const source = path.resolve(__dirname, relSource);
|
|
|
|
const dest = path.resolve(__dirname, relDest);
|
|
|
|
mkdirp.sync(path.dirname(dest));
|
|
|
|
|
|
|
|
licenseChecker.init({ start: source, production: true }, (err, packages) => {
|
|
|
|
if (err) {
|
|
|
|
return reject(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
const out = [];
|
|
|
|
for (const pkgName of Object.keys(packages)) {
|
|
|
|
const { licenses, repository, publisher, email, licenseFile: lf } = packages[pkgName];
|
|
|
|
const licenseFile = (lf || '').includes('README') ? null : lf;
|
|
|
|
const txt = licenseFile ? fs.readFileSync(licenseFile) : '[no license file]';
|
|
|
|
const body = [
|
|
|
|
'-------------------------------------------------------------------------',
|
|
|
|
'',
|
|
|
|
`PACKAGE: ${pkgName}`,
|
|
|
|
licenses ? `LICENSES: ${licenses}` : null,
|
|
|
|
repository ? `REPOSITORY: ${repository}` : null,
|
|
|
|
publisher ? `PUBLISHER: ${publisher}` : null,
|
|
|
|
email ? `EMAIL: ${email}` : null,
|
|
|
|
'\n' + txt,
|
|
|
|
]
|
|
|
|
.filter(v => v !== null)
|
|
|
|
.join('\n');
|
|
|
|
|
|
|
|
out.push(`${body}\n\n`);
|
|
|
|
}
|
|
|
|
|
|
|
|
const header = [
|
|
|
|
'This application bundles the following third-party packages in ',
|
|
|
|
'accordance with the following licenses:',
|
|
|
|
'-------------------------------------------------------------------------',
|
|
|
|
'',
|
|
|
|
'',
|
|
|
|
].join('\n');
|
|
|
|
|
|
|
|
fs.writeFileSync(dest, header + out.join('\n\n'));
|
|
|
|
resolve();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-06-25 17:42:50 +00:00
|
|
|
async function install(relDir) {
|
2019-09-18 00:02:42 +00:00
|
|
|
return new Promise(resolve => {
|
2017-11-20 16:07:36 +00:00
|
|
|
const prefix = path.resolve(__dirname, relDir);
|
2018-10-20 02:11:58 +00:00
|
|
|
|
2020-04-26 20:33:39 +00:00
|
|
|
// Link all plugins
|
|
|
|
const plugins = path.resolve(__dirname, '../../../plugins');
|
|
|
|
for (const dir of fs.readdirSync(plugins)) {
|
|
|
|
if (dir.indexOf('.') === 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log(`[build] Linking plugin ${dir}`);
|
|
|
|
const p = path.join(plugins, dir);
|
|
|
|
childProcess.spawnSync('npm', ['link', p], {
|
|
|
|
cwd: prefix,
|
|
|
|
shell: true,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// Link all packages
|
|
|
|
const packages = path.resolve(__dirname, '../../../packages');
|
|
|
|
for (const dir of fs.readdirSync(packages)) {
|
|
|
|
// Don't link ourselves
|
|
|
|
if (dir === packageJson.name) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dir.indexOf('.') === 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log(`[build] Linking local package ${dir}`);
|
|
|
|
const p = path.join(packages, dir);
|
|
|
|
childProcess.spawnSync('npm', ['link', p], {
|
|
|
|
cwd: prefix,
|
|
|
|
shell: true,
|
|
|
|
});
|
|
|
|
}
|
2019-09-18 00:02:42 +00:00
|
|
|
|
2018-10-20 02:11:58 +00:00
|
|
|
const p = childProcess.spawn('npm', ['install', '--production', '--no-optional'], {
|
|
|
|
cwd: prefix,
|
2018-12-12 17:36:11 +00:00
|
|
|
shell: true,
|
2018-10-20 02:11:58 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
p.stdout.on('data', data => {
|
|
|
|
console.log(data.toString());
|
|
|
|
});
|
|
|
|
|
|
|
|
p.stderr.on('data', data => {
|
|
|
|
console.log(data.toString());
|
|
|
|
});
|
|
|
|
|
|
|
|
p.on('exit', code => {
|
|
|
|
console.log('child process exited with code ' + code.toString());
|
|
|
|
resolve();
|
|
|
|
});
|
2017-11-20 16:07:36 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-04-26 20:33:39 +00:00
|
|
|
function generatePackageJson(relBasePkg, relOutPkg, forcedVersion) {
|
2017-11-26 20:45:40 +00:00
|
|
|
// Read package.json's
|
|
|
|
const basePath = path.resolve(__dirname, relBasePkg);
|
|
|
|
const outPath = path.resolve(__dirname, relOutPkg);
|
|
|
|
|
|
|
|
const basePkg = JSON.parse(fs.readFileSync(basePath));
|
|
|
|
|
2020-04-26 20:33:39 +00:00
|
|
|
const app = appConfig();
|
2017-11-26 23:04:47 +00:00
|
|
|
const appPkg = {
|
2020-04-26 20:33:39 +00:00
|
|
|
name: app.name,
|
|
|
|
version: forcedVersion || app.version,
|
|
|
|
productName: app.productName,
|
|
|
|
longName: app.longName,
|
2017-11-26 23:04:47 +00:00
|
|
|
description: basePkg.description,
|
2017-11-26 23:05:44 +00:00
|
|
|
license: basePkg.license,
|
2017-11-26 23:04:47 +00:00
|
|
|
homepage: basePkg.homepage,
|
|
|
|
author: basePkg.author,
|
2020-04-26 20:33:39 +00:00
|
|
|
copyright: `Copyright © ${new Date().getFullYear()} ${basePkg.author}`,
|
2017-11-26 23:04:47 +00:00
|
|
|
main: 'main.min.js',
|
2018-12-12 17:36:11 +00:00
|
|
|
dependencies: {},
|
2017-11-26 23:04:47 +00:00
|
|
|
};
|
|
|
|
|
2020-04-26 20:33:39 +00:00
|
|
|
console.log(`[build] Generated build config for ${appPkg.name} ${appPkg.version}`);
|
|
|
|
|
2017-11-26 23:04:47 +00:00
|
|
|
for (const key of Object.keys(appPkg)) {
|
|
|
|
if (key === undefined) {
|
|
|
|
throw new Error(`[build] missing "app.${key}" from package.json`);
|
|
|
|
}
|
|
|
|
}
|
2017-11-26 20:45:40 +00:00
|
|
|
|
|
|
|
// Figure out which dependencies to pack
|
|
|
|
const allDependencies = Object.keys(basePkg.dependencies);
|
|
|
|
const packedDependencies = basePkg.packedDependencies;
|
2018-10-17 16:42:33 +00:00
|
|
|
const unpackedDependencies = allDependencies.filter(name => !packedDependencies.includes(name));
|
2017-11-26 20:45:40 +00:00
|
|
|
|
|
|
|
// Add dependencies
|
2020-04-26 20:33:39 +00:00
|
|
|
console.log(`[build] Adding ${unpackedDependencies.length} node dependencies`);
|
2017-11-26 20:45:40 +00:00
|
|
|
for (const name of unpackedDependencies) {
|
|
|
|
const version = basePkg.dependencies[name];
|
|
|
|
if (!version) {
|
|
|
|
throw new Error(`Failed to find packed dep "${name}" in dependencies`);
|
|
|
|
}
|
|
|
|
appPkg.dependencies[name] = version;
|
|
|
|
}
|
|
|
|
|
|
|
|
fs.writeFileSync(outPath, JSON.stringify(appPkg, null, 2));
|
|
|
|
}
|
2020-04-26 20:33:39 +00:00
|
|
|
|
|
|
|
// Only release if we're building a tag that ends in a version number
|
|
|
|
function getBuildContext() {
|
|
|
|
const {
|
|
|
|
GITHUB_REF,
|
|
|
|
GITHUB_SHA,
|
|
|
|
TRAVIS_TAG,
|
|
|
|
TRAVIS_COMMIT,
|
|
|
|
TRAVIS_CURRENT_BRANCH,
|
|
|
|
GIT_TAG,
|
|
|
|
} = process.env;
|
|
|
|
|
|
|
|
const gitCommit = GITHUB_SHA || TRAVIS_COMMIT;
|
|
|
|
const gitRef = GITHUB_REF || TRAVIS_TAG || TRAVIS_CURRENT_BRANCH || GIT_TAG || '';
|
|
|
|
const tagMatch = gitRef.match(/(designer|core)@(\d{4}\.\d+\.\d+(-(alpha|beta)\.\d+)?)$/);
|
|
|
|
|
|
|
|
const app = tagMatch ? tagMatch[1] : null;
|
|
|
|
const version = tagMatch ? tagMatch[2] : null;
|
|
|
|
|
|
|
|
return {
|
|
|
|
app,
|
|
|
|
version,
|
|
|
|
gitRef,
|
|
|
|
gitCommit,
|
|
|
|
};
|
|
|
|
}
|