mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-07-13 14:26:37 +00:00
fix generation of updater channel files in CI (#840)
This commit is contained in:
parent
f660058c75
commit
77b430675d
13
.github/workflows/build.yml
vendored
13
.github/workflows/build.yml
vendored
@ -60,9 +60,7 @@ jobs:
|
|||||||
if [ $IS_FORK = true ]; then
|
if [ $IS_FORK = true ]; then
|
||||||
echo "Skipping the app signing: building from a fork."
|
echo "Skipping the app signing: building from a fork."
|
||||||
else
|
else
|
||||||
export BUILD_SUFFIX="linux";
|
|
||||||
if [ "${{ runner.OS }}" = "macOS" ]; then
|
if [ "${{ runner.OS }}" = "macOS" ]; then
|
||||||
export BUILD_SUFFIX="mac";
|
|
||||||
export CSC_LINK="${{ runner.temp }}/signing_certificate.p12"
|
export CSC_LINK="${{ runner.temp }}/signing_certificate.p12"
|
||||||
# APPLE_SIGNING_CERTIFICATE_P12 secret was produced by following the procedure from:
|
# APPLE_SIGNING_CERTIFICATE_P12 secret was produced by following the procedure from:
|
||||||
# https://www.kencochrane.com/2020/08/01/build-and-sign-golang-binaries-for-macos-with-github-actions/#exporting-the-developer-certificate
|
# https://www.kencochrane.com/2020/08/01/build-and-sign-golang-binaries-for-macos-with-github-actions/#exporting-the-developer-certificate
|
||||||
@ -71,7 +69,6 @@ jobs:
|
|||||||
export CSC_KEY_PASSWORD="${{ secrets.KEYCHAIN_PASSWORD }}"
|
export CSC_KEY_PASSWORD="${{ secrets.KEYCHAIN_PASSWORD }}"
|
||||||
|
|
||||||
elif [ "${{ runner.OS }}" = "Windows" ]; then
|
elif [ "${{ runner.OS }}" = "Windows" ]; then
|
||||||
export BUILD_SUFFIX="";
|
|
||||||
export CSC_LINK="${{ runner.temp }}/signing_certificate.pfx"
|
export CSC_LINK="${{ runner.temp }}/signing_certificate.pfx"
|
||||||
npm config set msvs_version 2017 --global
|
npm config set msvs_version 2017 --global
|
||||||
echo "${{ secrets.WINDOWS_SIGNING_CERTIFICATE_PFX }}" | base64 --decode > "$CSC_LINK"
|
echo "${{ secrets.WINDOWS_SIGNING_CERTIFICATE_PFX }}" | base64 --decode > "$CSC_LINK"
|
||||||
@ -81,15 +78,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
yarn --cwd ./electron/packager/
|
yarn --cwd ./electron/packager/
|
||||||
yarn --cwd ./electron/packager/ package
|
yarn --cwd ./electron/packager/ package
|
||||||
|
|
||||||
export BUILD_PREFIX="stable"
|
|
||||||
if [ "$IS_NIGHTLY" = true ]; then
|
|
||||||
export BUILD_PREFIX="nightly"
|
|
||||||
fi
|
|
||||||
|
|
||||||
mv electron/build/dist/latest-$BUILD_SUFFIX.yml electron/build/dist/$BUILD_PREFIX-$BUILD_SUFFIX.yml
|
|
||||||
rm electron/build/dist/alpha* electron/build/dist/beta*
|
|
||||||
|
|
||||||
- name: Upload [GitHub Actions]
|
- name: Upload [GitHub Actions]
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
|
@ -106,7 +106,7 @@ function getChannel() {
|
|||||||
return 'nightly';
|
return 'nightly';
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'none';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function timestamp() {
|
function timestamp() {
|
||||||
|
@ -1,347 +1,440 @@
|
|||||||
//@ts-check
|
//@ts-check
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
|
const fs = require('fs');
|
||||||
|
const join = require('path').join;
|
||||||
|
const shell = require('shelljs');
|
||||||
|
const glob = require('glob');
|
||||||
|
const isCI = require('is-ci');
|
||||||
|
shell.env.THEIA_ELECTRON_SKIP_REPLACE_FFMPEG = '1'; // Do not run the ffmpeg validation for the packager.
|
||||||
|
shell.env.NODE_OPTIONS = '--max_old_space_size=4096'; // Increase heap size for the CI
|
||||||
|
shell.env.PUPPETEER_SKIP_CHROMIUM_DOWNLOAD = 'true'; // Skip download and avoid `ERROR: Failed to download Chromium`.
|
||||||
|
const template = require('./config').generateTemplate(
|
||||||
|
new Date().toISOString()
|
||||||
|
);
|
||||||
|
const utils = require('./utils');
|
||||||
|
const merge = require('deepmerge');
|
||||||
|
const { isRelease, isElectronPublish, getChannelFile } = utils;
|
||||||
|
const { version } = template;
|
||||||
|
const { productName } = template.build;
|
||||||
|
|
||||||
const fs = require('fs');
|
echo(`📦 Building ${isRelease ? 'release ' : ''}version '${version}'...`);
|
||||||
const join = require('path').join;
|
|
||||||
const shell = require('shelljs');
|
|
||||||
const glob = require('glob');
|
|
||||||
const isCI = require('is-ci');
|
|
||||||
shell.env.THEIA_ELECTRON_SKIP_REPLACE_FFMPEG = '1'; // Do not run the ffmpeg validation for the packager.
|
|
||||||
shell.env.NODE_OPTIONS = '--max_old_space_size=4096'; // Increase heap size for the CI
|
|
||||||
shell.env.PUPPETEER_SKIP_CHROMIUM_DOWNLOAD = 'true'; // Skip download and avoid `ERROR: Failed to download Chromium`.
|
|
||||||
const template = require('./config').generateTemplate(new Date().toISOString());
|
|
||||||
const utils = require('./utils');
|
|
||||||
const merge = require('deepmerge');
|
|
||||||
const { isRelease, isElectronPublish, getChannelFile } = utils;
|
|
||||||
const { version } = template;
|
|
||||||
const { productName } = template.build;
|
|
||||||
|
|
||||||
echo(`📦 Building ${isRelease ? 'release ' : ''}version '${version}'...`);
|
const workingCopy = 'working-copy';
|
||||||
|
|
||||||
const workingCopy = 'working-copy';
|
/**
|
||||||
|
* Relative path from the `__dirname` to the root where the `arduino-ide-extension` and the `electron-app` folders are.
|
||||||
|
* This could come handy when moving the location of the `electron/packager`.
|
||||||
|
*/
|
||||||
|
const rootPath = join('..', '..');
|
||||||
|
|
||||||
/**
|
// This is a HACK! We rename the root `node_modules` to something else. Otherwise, due to the hoisting,
|
||||||
* Relative path from the `__dirname` to the root where the `arduino-ide-extension` and the `electron-app` folders are.
|
// multiple Theia extensions will be picked up.
|
||||||
* This could come handy when moving the location of the `electron/packager`.
|
if (fs.existsSync(path(rootPath, 'node_modules'))) {
|
||||||
*/
|
// We either do this or change the project structure.
|
||||||
const rootPath = join('..', '..');
|
echo(
|
||||||
|
"🔧 >>> [Hack] Renaming the root 'node_modules' folder to '.node_modules'..."
|
||||||
|
);
|
||||||
|
mv('-f', path(rootPath, 'node_modules'), path(rootPath, '.node_modules'));
|
||||||
|
echo(
|
||||||
|
"👌 <<< [Hack] Renamed the root 'node_modules' folder to '.node_modules'."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// This is a HACK! We rename the root `node_modules` to something else. Otherwise, due to the hoisting,
|
//---------------------------+
|
||||||
// multiple Theia extensions will be picked up.
|
// Clean the previous state. |
|
||||||
if (fs.existsSync(path(rootPath, 'node_modules'))) {
|
//---------------------------+
|
||||||
// We either do this or change the project structure.
|
// rm -rf ../working-copy
|
||||||
echo('🔧 >>> [Hack] Renaming the root \'node_modules\' folder to \'.node_modules\'...');
|
rm('-rf', path('..', workingCopy));
|
||||||
mv('-f', path(rootPath, 'node_modules'), path(rootPath, '.node_modules'));
|
// Clean up the `./electron/build` folder.
|
||||||
echo('👌 <<< [Hack] Renamed the root \'node_modules\' folder to \'.node_modules\'.')
|
const resourcesToKeep = [
|
||||||
}
|
'patch',
|
||||||
|
'resources',
|
||||||
|
'scripts',
|
||||||
|
'template-package.json',
|
||||||
|
];
|
||||||
|
fs.readdirSync(path('..', 'build'))
|
||||||
|
.filter((filename) => resourcesToKeep.indexOf(filename) === -1)
|
||||||
|
.forEach((filename) => rm('-rf', path('..', 'build', filename)));
|
||||||
|
|
||||||
//---------------------------+
|
const extensions = require('./extensions.json');
|
||||||
// Clean the previous state. |
|
echo(
|
||||||
//---------------------------+
|
`Building the application with the following extensions:\n${extensions
|
||||||
// rm -rf ../working-copy
|
.map((ext) => ` - ${ext}`)
|
||||||
rm('-rf', path('..', workingCopy));
|
.join(',\n')}`
|
||||||
// Clean up the `./electron/build` folder.
|
);
|
||||||
const resourcesToKeep = ['patch', 'resources', 'scripts', 'template-package.json'];
|
const allDependencies = [...extensions, 'electron-app'];
|
||||||
for (const filename of fs.readdirSync(path('..', 'build')).filter(filename => resourcesToKeep.indexOf(filename) === -1)) {
|
|
||||||
rm('-rf', path('..', 'build', filename));
|
|
||||||
}
|
|
||||||
|
|
||||||
const extensions = require('./extensions.json');
|
//----------------------------------------------------------------------------------------------+
|
||||||
echo(`Building the application with the following extensions:\n${extensions.map(ext => ` - ${ext}`).join(',\n')}`);
|
// Copy the following items into the `working-copy` folder. Make sure to reuse the `yarn.lock`. |
|
||||||
const allDependencies = [
|
//----------------------------------------------------------------------------------------------+
|
||||||
...extensions,
|
mkdir('-p', path('..', workingCopy));
|
||||||
'electron-app'
|
for (const name of [
|
||||||
]
|
...allDependencies,
|
||||||
|
'yarn.lock',
|
||||||
|
'package.json',
|
||||||
|
'lerna.json',
|
||||||
|
]) {
|
||||||
|
cp('-rf', path(rootPath, name), path('..', workingCopy));
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------------------+
|
//----------------------------------------------+
|
||||||
// Copy the following items into the `working-copy` folder. Make sure to reuse the `yarn.lock`. |
|
// Sanity check: all versions must be the same. |
|
||||||
//----------------------------------------------------------------------------------------------+
|
//----------------------------------------------+
|
||||||
mkdir('-p', path('..', workingCopy));
|
verifyVersions(allDependencies);
|
||||||
for (const name of [...allDependencies, 'yarn.lock', 'package.json', 'lerna.json']) {
|
//----------------------------------------------------------------------+
|
||||||
cp('-rf', path(rootPath, name), path('..', workingCopy));
|
// Use the nightly patch version if not a release but requires publish. |
|
||||||
}
|
//----------------------------------------------------------------------+
|
||||||
|
if (!isRelease) {
|
||||||
//----------------------------------------------+
|
for (const dependency of allDependencies) {
|
||||||
// Sanity check: all versions must be the same. |
|
const pkg = require(`../working-copy/${dependency}/package.json`);
|
||||||
//----------------------------------------------+
|
pkg.version = version;
|
||||||
verifyVersions(allDependencies);
|
for (const dependency in pkg.dependencies) {
|
||||||
//----------------------------------------------------------------------+
|
if (allDependencies.indexOf(dependency) !== -1) {
|
||||||
// Use the nightly patch version if not a release but requires publish. |
|
pkg.dependencies[dependency] = version;
|
||||||
//----------------------------------------------------------------------+
|
|
||||||
if (!isRelease) {
|
|
||||||
for (const dependency of allDependencies) {
|
|
||||||
const pkg = require(`../working-copy/${dependency}/package.json`);
|
|
||||||
pkg.version = version;
|
|
||||||
for (const dependency in pkg.dependencies) {
|
|
||||||
if (allDependencies.indexOf(dependency) !== -1) {
|
|
||||||
pkg.dependencies[dependency] = version;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fs.writeFileSync(path('..', workingCopy, dependency, 'package.json'), JSON.stringify(pkg, null, 2));
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
fs.writeFileSync(
|
||||||
|
path('..', workingCopy, dependency, 'package.json'),
|
||||||
|
JSON.stringify(pkg, null, 2)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
verifyVersions(allDependencies);
|
}
|
||||||
|
verifyVersions(allDependencies);
|
||||||
|
|
||||||
//-------------------------------------------------------------+
|
//-------------------------------------------------------------+
|
||||||
// Save some time: no need to build the `browser-app` example. |
|
// Save some time: no need to build the `browser-app` example. |
|
||||||
//-------------------------------------------------------------+
|
//-------------------------------------------------------------+
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
let pkg = require('../working-copy/package.json');
|
let pkg = require('../working-copy/package.json');
|
||||||
const workspaces = pkg.workspaces;
|
const workspaces = pkg.workspaces;
|
||||||
// We cannot remove the `electron-app`. Otherwise, there is not way to collect the unused dependencies.
|
// We cannot remove the `electron-app`. Otherwise, there is not way to collect the unused dependencies.
|
||||||
const dependenciesToRemove = ['browser-app'];
|
const dependenciesToRemove = ['browser-app'];
|
||||||
for (const dependencyToRemove of dependenciesToRemove) {
|
for (const dependencyToRemove of dependenciesToRemove) {
|
||||||
const index = workspaces.indexOf(dependencyToRemove);
|
const index = workspaces.indexOf(dependencyToRemove);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
workspaces.splice(index, 1);
|
workspaces.splice(index, 1);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pkg.workspaces = workspaces;
|
}
|
||||||
fs.writeFileSync(path('..', workingCopy, 'package.json'), JSON.stringify(pkg, null, 2));
|
pkg.workspaces = workspaces;
|
||||||
|
fs.writeFileSync(
|
||||||
|
path('..', workingCopy, 'package.json'),
|
||||||
|
JSON.stringify(pkg, null, 2)
|
||||||
|
);
|
||||||
|
|
||||||
//-------------------------------------------------------------------------------------------------+
|
//-------------------------------------------------------------------------------------------------+
|
||||||
// Rebuild the extension with the copied `yarn.lock`. It is a must to use the same Theia versions. |
|
// Rebuild the extension with the copied `yarn.lock`. It is a must to use the same Theia versions. |
|
||||||
//-------------------------------------------------------------------------------------------------+
|
//-------------------------------------------------------------------------------------------------+
|
||||||
exec(`yarn --network-timeout 1000000 --cwd ${path('..', workingCopy)}`, `Building the ${productName} application`);
|
exec(
|
||||||
|
`yarn --network-timeout 1000000 --cwd ${path('..', workingCopy)}`,
|
||||||
|
`Building the ${productName} application`
|
||||||
|
);
|
||||||
|
|
||||||
//-------------------------------------------------------------------------------------------------------------------------+
|
//-------------------------------------------------------------------------------------------------------------------------+
|
||||||
// Test the application. With this approach, we cannot publish test results to GH Actions but save 6-10 minutes per builds |
|
// Test the application. With this approach, we cannot publish test results to GH Actions but save 6-10 minutes per builds |
|
||||||
//-------------------------------------------------------------------------------------------------------------------------+
|
//-------------------------------------------------------------------------------------------------------------------------+
|
||||||
exec(`yarn --network-timeout 1000000 --cwd ${path('..', workingCopy)} test`, `Testing the ${productName} application`);
|
exec(
|
||||||
|
`yarn --network-timeout 1000000 --cwd ${path('..', workingCopy)} test`,
|
||||||
|
`Testing the ${productName} application`
|
||||||
|
);
|
||||||
|
|
||||||
// Collect all unused dependencies by the backend. We have to remove them from the electron app.
|
// Collect all unused dependencies by the backend. We have to remove them from the electron app.
|
||||||
// The `bundle.js` already contains everything we need for the frontend.
|
// The `bundle.js` already contains everything we need for the frontend.
|
||||||
// We have to do it before changing the dependencies to `local-path`.
|
// We have to do it before changing the dependencies to `local-path`.
|
||||||
const unusedDependencies = await utils.collectUnusedDependencies('../working-copy/electron-app/');
|
const unusedDependencies = await utils.collectUnusedDependencies(
|
||||||
|
'../working-copy/electron-app/'
|
||||||
|
);
|
||||||
|
|
||||||
//-------------------------------------------------------------------------------------------------------------+
|
//-------------------------------------------------------------------------------------------------------------+
|
||||||
// Change the regular NPM dependencies to `local-paths`, so that we can build them without any NPM registries. |
|
// Change the regular NPM dependencies to `local-paths`, so that we can build them without any NPM registries. |
|
||||||
//-------------------------------------------------------------------------------------------------------------+
|
//-------------------------------------------------------------------------------------------------------------+
|
||||||
for (const extension of extensions) {
|
for (const extension of extensions) {
|
||||||
if (extension !== 'arduino-ide-extension') { // Do not unlink self.
|
if (extension !== 'arduino-ide-extension') {
|
||||||
// @ts-ignore
|
// Do not unlink self.
|
||||||
pkg = require(`../working-copy/${extension}/package.json`);
|
// @ts-ignore
|
||||||
// @ts-ignore
|
pkg = require(`../working-copy/${extension}/package.json`);
|
||||||
pkg.dependencies['arduino-ide-extension'] = 'file:../arduino-ide-extension';
|
// @ts-ignore
|
||||||
fs.writeFileSync(path('..', workingCopy, extension, 'package.json'), JSON.stringify(pkg, null, 2));
|
pkg.dependencies['arduino-ide-extension'] =
|
||||||
}
|
'file:../arduino-ide-extension';
|
||||||
|
fs.writeFileSync(
|
||||||
|
path('..', workingCopy, extension, 'package.json'),
|
||||||
|
JSON.stringify(pkg, null, 2)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------+
|
//------------------------------------------------------------------------------------+
|
||||||
// Merge the `working-copy/package.json` with `electron/build/template-package.json`. |
|
// Merge the `working-copy/package.json` with `electron/build/template-package.json`. |
|
||||||
//------------------------------------------------------------------------------------+
|
//------------------------------------------------------------------------------------+
|
||||||
|
// @ts-ignore
|
||||||
|
pkg = require('../working-copy/electron-app/package.json');
|
||||||
|
template.build.files = [
|
||||||
|
...template.build.files,
|
||||||
|
...unusedDependencies.map((name) => `!node_modules/${name}`),
|
||||||
|
];
|
||||||
|
|
||||||
|
const dependencies = {};
|
||||||
|
for (const extension of extensions) {
|
||||||
|
dependencies[extension] = `file:../working-copy/${extension}`;
|
||||||
|
}
|
||||||
|
// @ts-ignore
|
||||||
|
pkg.dependencies = { ...pkg.dependencies, ...dependencies };
|
||||||
|
pkg.devDependencies = { ...pkg.devDependencies, ...template.devDependencies };
|
||||||
|
// Deep-merging the Theia application configuration. We enable the electron window reload in dev mode but not for the final product. (arduino/arduino-pro-ide#187)
|
||||||
|
// @ts-ignore
|
||||||
|
const theia = merge(pkg.theia || {}, template.theia || {});
|
||||||
|
const content = {
|
||||||
|
...pkg,
|
||||||
|
...template,
|
||||||
|
theia,
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
pkg = require('../working-copy/electron-app/package.json');
|
dependencies: pkg.dependencies,
|
||||||
template.build.files = [...template.build.files, ...unusedDependencies.map(name => `!node_modules/${name}`)];
|
devDependencies: pkg.devDependencies,
|
||||||
|
};
|
||||||
|
const overwriteMerge = (destinationArray, sourceArray, options) =>
|
||||||
|
sourceArray;
|
||||||
|
fs.writeFileSync(
|
||||||
|
path('..', 'build', 'package.json'),
|
||||||
|
JSON.stringify(
|
||||||
|
merge(content, template, { arrayMerge: overwriteMerge }),
|
||||||
|
null,
|
||||||
|
2
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
const dependencies = {};
|
echo(`📜 Effective 'package.json' for the ${productName} application is:
|
||||||
for (const extension of extensions) {
|
|
||||||
dependencies[extension] = `file:../working-copy/${extension}`;
|
|
||||||
}
|
|
||||||
// @ts-ignore
|
|
||||||
pkg.dependencies = { ...pkg.dependencies, ...dependencies };
|
|
||||||
pkg.devDependencies = { ...pkg.devDependencies, ...template.devDependencies };
|
|
||||||
// Deep-merging the Theia application configuration. We enable the electron window reload in dev mode but not for the final product. (arduino/arduino-pro-ide#187)
|
|
||||||
// @ts-ignore
|
|
||||||
const theia = merge((pkg.theia || {}), (template.theia || {}));
|
|
||||||
const content = {
|
|
||||||
...pkg,
|
|
||||||
...template,
|
|
||||||
theia,
|
|
||||||
// @ts-ignore
|
|
||||||
dependencies: pkg.dependencies,
|
|
||||||
devDependencies: pkg.devDependencies
|
|
||||||
};
|
|
||||||
const overwriteMerge = (destinationArray, sourceArray, options) => sourceArray;
|
|
||||||
fs.writeFileSync(path('..', 'build', 'package.json'), JSON.stringify(merge(content, template, { arrayMerge: overwriteMerge }), null, 2));
|
|
||||||
|
|
||||||
echo(`📜 Effective 'package.json' for the ${productName} application is:
|
|
||||||
-----------------------
|
-----------------------
|
||||||
${fs.readFileSync(path('..', 'build', 'package.json')).toString()}
|
${fs.readFileSync(path('..', 'build', 'package.json')).toString()}
|
||||||
-----------------------
|
-----------------------
|
||||||
`);
|
`);
|
||||||
|
|
||||||
// Make sure the original `yarn.lock` file is used from the electron application.
|
// Make sure the original `yarn.lock` file is used from the electron application.
|
||||||
if (fs.existsSync(path('..', 'build', 'yarn.lock'))) {
|
if (fs.existsSync(path('..', 'build', 'yarn.lock'))) {
|
||||||
echo(`${path('..', 'build', 'yarn.lock')} must not exist.`);
|
echo(`${path('..', 'build', 'yarn.lock')} must not exist.`);
|
||||||
|
shell.exit(1);
|
||||||
|
}
|
||||||
|
cp('-rf', path(rootPath, 'yarn.lock'), path('..', 'build'));
|
||||||
|
if (!fs.existsSync(path('..', 'build', 'yarn.lock'))) {
|
||||||
|
echo(`${path('..', 'build', 'yarn.lock')} does not exist.`);
|
||||||
|
shell.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------+
|
||||||
|
// Install all private and public dependencies for the electron application and build Theia. |
|
||||||
|
//-------------------------------------------------------------------------------------------+
|
||||||
|
exec(
|
||||||
|
`yarn --network-timeout 1000000 --cwd ${path('..', 'build')}`,
|
||||||
|
'Installing dependencies'
|
||||||
|
);
|
||||||
|
exec(
|
||||||
|
`yarn --network-timeout 1000000 --cwd ${path('..', 'build')} build${
|
||||||
|
isElectronPublish ? ':publish' : ''
|
||||||
|
}`,
|
||||||
|
`Building the ${productName} application`
|
||||||
|
);
|
||||||
|
exec(
|
||||||
|
`yarn --network-timeout 1000000 --cwd ${path('..', 'build')} rebuild`,
|
||||||
|
'Rebuild native dependencies'
|
||||||
|
);
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------+
|
||||||
|
// Create a throw away dotenv file which we use to feed the builder with input. |
|
||||||
|
//------------------------------------------------------------------------------+
|
||||||
|
const dotenv = 'electron-builder.env';
|
||||||
|
if (fs.existsSync(path('..', 'build', dotenv))) {
|
||||||
|
rm('-rf', path('..', 'build', dotenv));
|
||||||
|
}
|
||||||
|
// For the releases we use the desired tag as is defined by `$(Release.Tag)` from Azure.
|
||||||
|
// For the preview builds we use the version from the `electron/build/package.json` with the short commit hash.
|
||||||
|
fs.writeFileSync(path('..', 'build', dotenv), `ARDUINO_VERSION=${version}`);
|
||||||
|
|
||||||
|
//-----------------------------------+
|
||||||
|
// Package the electron application. |
|
||||||
|
//-----------------------------------+
|
||||||
|
exec(
|
||||||
|
`yarn --network-timeout 1000000 --cwd ${path('..', 'build')} package`,
|
||||||
|
`Packaging your ${productName} application`
|
||||||
|
);
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------------------------------+
|
||||||
|
// Copy to another folder. Azure does not support wildcard for `PublishBuildArtifacts@1.pathToPublish` |
|
||||||
|
//-----------------------------------------------------------------------------------------------------+
|
||||||
|
if (isCI) {
|
||||||
|
try {
|
||||||
|
await copyFilesToBuildArtifacts();
|
||||||
|
} catch (e) {
|
||||||
|
echo(JSON.stringify(e));
|
||||||
|
shell.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
echo(`🎉 Success. Your application is at: ${path('..', 'build', 'dist')}`);
|
||||||
|
|
||||||
|
restore();
|
||||||
|
|
||||||
|
//--------+
|
||||||
|
// Utils. |
|
||||||
|
//--------+
|
||||||
|
function exec(command, toEcho) {
|
||||||
|
if (toEcho) {
|
||||||
|
echo(`⏱️ >>> ${toEcho}...`);
|
||||||
|
}
|
||||||
|
const { code, stderr, stdout } = shell.exec(command);
|
||||||
|
if (code !== 0) {
|
||||||
|
echo(`🔥 Error when executing ${command} => ${stderr}`);
|
||||||
|
shell.exit(1);
|
||||||
|
}
|
||||||
|
if (toEcho) {
|
||||||
|
echo(`👌 <<< ${toEcho}.`);
|
||||||
|
}
|
||||||
|
return stdout;
|
||||||
|
}
|
||||||
|
|
||||||
|
function cp(options, source, destination) {
|
||||||
|
shell.cp(options, source, destination);
|
||||||
|
assertNoError();
|
||||||
|
}
|
||||||
|
|
||||||
|
function rm(options, ...files) {
|
||||||
|
shell.rm(options, files);
|
||||||
|
assertNoError();
|
||||||
|
}
|
||||||
|
|
||||||
|
function mv(options, source, destination) {
|
||||||
|
shell.mv(options, source, destination);
|
||||||
|
assertNoError();
|
||||||
|
}
|
||||||
|
|
||||||
|
function mkdir(options, ...dir) {
|
||||||
|
shell.mkdir(options, dir);
|
||||||
|
assertNoError();
|
||||||
|
}
|
||||||
|
|
||||||
|
function echo(command) {
|
||||||
|
return shell.echo(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertNoError() {
|
||||||
|
const error = shell.error();
|
||||||
|
if (error) {
|
||||||
|
echo(error);
|
||||||
|
restore();
|
||||||
|
shell.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function restore() {
|
||||||
|
if (fs.existsSync(path(rootPath, '.node_modules'))) {
|
||||||
|
echo(
|
||||||
|
"🔧 >>> [Restore] Renaming the root '.node_modules' folder to 'node_modules'..."
|
||||||
|
);
|
||||||
|
mv('-f', path(rootPath, '.node_modules'), path(rootPath, 'node_modules'));
|
||||||
|
echo(
|
||||||
|
"👌 >>> [Restore] Renamed the root '.node_modules' folder to 'node_modules'."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function copyFilesToBuildArtifacts() {
|
||||||
|
echo(`🚢 Detected CI, moving build artifacts...`);
|
||||||
|
const { platform } = process;
|
||||||
|
const cwd = path('..', 'build', 'dist');
|
||||||
|
const targetFolder = path('..', 'build', 'dist', 'build-artifacts');
|
||||||
|
mkdir('-p', targetFolder);
|
||||||
|
const filesToCopy = [];
|
||||||
|
const channelFile = getChannelFile(platform);
|
||||||
|
// Channel file might be an empty string if we're not building a
|
||||||
|
// nightly or a full release. This can happen when building a package
|
||||||
|
// locally or a tester build when creating a new PR on GH.
|
||||||
|
if (!!channelFile && fs.existsSync(join(cwd, channelFile))) {
|
||||||
|
const channelFilePath = join(cwd, channelFile);
|
||||||
|
const newChannelFilePath = channelFilePath
|
||||||
|
?.replace('latest', 'stable')
|
||||||
|
?.replace('beta', 'nightly');
|
||||||
|
echo(`🔨 >>> Renaming ${channelFilePath} to ${newChannelFilePath}.`);
|
||||||
|
cp('-f', channelFilePath, newChannelFilePath);
|
||||||
|
filesToCopy.push(newChannelFilePath);
|
||||||
|
}
|
||||||
|
switch (platform) {
|
||||||
|
case 'linux': {
|
||||||
|
filesToCopy.push(
|
||||||
|
...glob
|
||||||
|
.sync('**/arduino-ide*.{zip,AppImage}', { cwd })
|
||||||
|
.map((p) => join(cwd, p))
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'win32': {
|
||||||
|
filesToCopy.push(
|
||||||
|
...glob
|
||||||
|
.sync('**/arduino-ide*.{exe,msi,zip}', { cwd })
|
||||||
|
.map((p) => join(cwd, p))
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'darwin': {
|
||||||
|
filesToCopy.push(
|
||||||
|
...glob
|
||||||
|
.sync('**/arduino-ide*.{dmg,zip}', { cwd })
|
||||||
|
.map((p) => join(cwd, p))
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
echo(`Unsupported platform: ${platform}.`);
|
||||||
shell.exit(1);
|
shell.exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cp('-rf', path(rootPath, 'yarn.lock'), path('..', 'build'));
|
if (!filesToCopy.length) {
|
||||||
if (!fs.existsSync(path('..', 'build', 'yarn.lock'))) {
|
echo(`Could not collect any build artifacts from ${cwd}.`);
|
||||||
echo(`${path('..', 'build', 'yarn.lock')} does not exist.`);
|
shell.exit(1);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
echo(`👌 >>> Copied ${fileToCopy} to ${targetFolder}.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Joins tha path from `__dirname`.
|
||||||
|
*/
|
||||||
|
function path(...paths) {
|
||||||
|
return join(__dirname, ...paths);
|
||||||
|
}
|
||||||
|
|
||||||
|
function verifyVersions(allDependencies, expectedVersion) {
|
||||||
|
const versions = new Set();
|
||||||
|
for (const dependency of allDependencies) {
|
||||||
|
versions.add(
|
||||||
|
require(`../working-copy/${dependency}/package.json`).version
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (versions.size !== 1) {
|
||||||
|
echo(
|
||||||
|
`Mismatching version configuration. All dependencies must have the same version. Versions were: ${JSON.stringify(
|
||||||
|
Array.from(versions),
|
||||||
|
null,
|
||||||
|
2
|
||||||
|
)}.`
|
||||||
|
);
|
||||||
|
shell.exit(1);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
if (expectedVersion) {
|
||||||
|
if (!versions.has(expectedVersion)) {
|
||||||
|
echo(
|
||||||
|
`Mismatching version configuration. Expected version was: '${expectedVersion}' actual was: '${
|
||||||
|
Array.from(versions)[0]
|
||||||
|
}'.`
|
||||||
|
);
|
||||||
shell.exit(1);
|
shell.exit(1);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
//-------------------------------------------------------------------------------------------+
|
|
||||||
// Install all private and public dependencies for the electron application and build Theia. |
|
|
||||||
//-------------------------------------------------------------------------------------------+
|
|
||||||
exec(`yarn --network-timeout 1000000 --cwd ${path('..', 'build')}`, 'Installing dependencies');
|
|
||||||
exec(`yarn --network-timeout 1000000 --cwd ${path('..', 'build')} build${isElectronPublish ? ':publish' : ''}`, `Building the ${productName} application`);
|
|
||||||
exec(`yarn --network-timeout 1000000 --cwd ${path('..', 'build')} rebuild`, 'Rebuild native dependencies');
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------+
|
|
||||||
// Create a throw away dotenv file which we use to feed the builder with input. |
|
|
||||||
//------------------------------------------------------------------------------+
|
|
||||||
const dotenv = 'electron-builder.env';
|
|
||||||
if (fs.existsSync(path('..', 'build', dotenv))) {
|
|
||||||
rm('-rf', path('..', 'build', dotenv));
|
|
||||||
}
|
|
||||||
// For the releases we use the desired tag as is defined by `$(Release.Tag)` from Azure.
|
|
||||||
// For the preview builds we use the version from the `electron/build/package.json` with the short commit hash.
|
|
||||||
fs.writeFileSync(path('..', 'build', dotenv), `ARDUINO_VERSION=${version}`);
|
|
||||||
|
|
||||||
//-----------------------------------+
|
|
||||||
// Package the electron application. |
|
|
||||||
//-----------------------------------+
|
|
||||||
exec(`yarn --network-timeout 1000000 --cwd ${path('..', 'build')} package`, `Packaging your ${productName} application`);
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------------------------------+
|
|
||||||
// Copy to another folder. Azure does not support wildcard for `PublishBuildArtifacts@1.pathToPublish` |
|
|
||||||
//-----------------------------------------------------------------------------------------------------+
|
|
||||||
if (isCI) {
|
|
||||||
try {
|
|
||||||
await copyFilesToBuildArtifacts();
|
|
||||||
} catch (e) {
|
|
||||||
echo(JSON.stringify(e));
|
|
||||||
shell.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
echo(`🎉 Success. Your application is at: ${path('..', 'build', 'dist')}`);
|
|
||||||
|
|
||||||
restore();
|
|
||||||
|
|
||||||
//--------+
|
|
||||||
// Utils. |
|
|
||||||
//--------+
|
|
||||||
function exec(command, toEcho) {
|
|
||||||
if (toEcho) {
|
|
||||||
echo(`⏱️ >>> ${toEcho}...`);
|
|
||||||
}
|
|
||||||
const { code, stderr, stdout } = shell.exec(command);
|
|
||||||
if (code !== 0) {
|
|
||||||
echo(`🔥 Error when executing ${command} => ${stderr}`);
|
|
||||||
shell.exit(1);
|
|
||||||
}
|
|
||||||
if (toEcho) {
|
|
||||||
echo(`👌 <<< ${toEcho}.`);
|
|
||||||
}
|
|
||||||
return stdout;
|
|
||||||
}
|
|
||||||
|
|
||||||
function cp(options, source, destination) {
|
|
||||||
shell.cp(options, source, destination);
|
|
||||||
assertNoError();
|
|
||||||
}
|
|
||||||
|
|
||||||
function rm(options, ...files) {
|
|
||||||
shell.rm(options, files);
|
|
||||||
assertNoError();
|
|
||||||
}
|
|
||||||
|
|
||||||
function mv(options, source, destination) {
|
|
||||||
shell.mv(options, source, destination);
|
|
||||||
assertNoError();
|
|
||||||
}
|
|
||||||
|
|
||||||
function mkdir(options, ...dir) {
|
|
||||||
shell.mkdir(options, dir);
|
|
||||||
assertNoError();
|
|
||||||
}
|
|
||||||
|
|
||||||
function echo(command) {
|
|
||||||
return shell.echo(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertNoError() {
|
|
||||||
const error = shell.error();
|
|
||||||
if (error) {
|
|
||||||
echo(error);
|
|
||||||
restore();
|
|
||||||
shell.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function restore() {
|
|
||||||
if (fs.existsSync(path(rootPath, '.node_modules'))) {
|
|
||||||
echo('🔧 >>> [Restore] Renaming the root \'.node_modules\' folder to \'node_modules\'...');
|
|
||||||
mv('-f', path(rootPath, '.node_modules'), path(rootPath, 'node_modules'));
|
|
||||||
echo('👌 >>> [Restore] Renamed the root \'.node_modules\' folder to \'node_modules\'.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function copyFilesToBuildArtifacts() {
|
|
||||||
echo(`🚢 Detected CI, moving build artifacts...`);
|
|
||||||
const { platform } = process;
|
|
||||||
const cwd = path('..', 'build', 'dist');
|
|
||||||
const targetFolder = path('..', 'build', 'dist', 'build-artifacts');
|
|
||||||
mkdir('-p', targetFolder);
|
|
||||||
const filesToCopy = [];
|
|
||||||
const channelFile = getChannelFile(platform);
|
|
||||||
// Channel file might be an empty string if we're not building a
|
|
||||||
// nightly or a full release. This can happen when building a package
|
|
||||||
// locally or a tester build when creating a new PR on GH.
|
|
||||||
if (channelFile) {
|
|
||||||
filesToCopy.push(channelFile)
|
|
||||||
}
|
|
||||||
switch (platform) {
|
|
||||||
case 'linux': {
|
|
||||||
filesToCopy.push(...glob.sync('**/arduino-ide*.{zip,AppImage}', { cwd }).map(p => join(cwd, p)));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'win32': {
|
|
||||||
filesToCopy.push(...glob.sync('**/arduino-ide*.{exe,msi,zip}', { cwd }).map(p => join(cwd, p)));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'darwin': {
|
|
||||||
filesToCopy.push(...glob.sync('**/arduino-ide*.{dmg,zip}', { cwd }).map(p => join(cwd, p)));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
echo(`Unsupported platform: ${platform}.`);
|
|
||||||
shell.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!filesToCopy.length) {
|
|
||||||
echo(`Could not collect any build artifacts from ${cwd}.`);
|
|
||||||
shell.exit(1);
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
echo(`👌 >>> Copied ${fileToCopy} to ${targetFolder}.`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Joins tha path from `__dirname`.
|
|
||||||
*/
|
|
||||||
function path(...paths) {
|
|
||||||
return join(__dirname, ...paths);
|
|
||||||
}
|
|
||||||
|
|
||||||
function verifyVersions(allDependencies, expectedVersion) {
|
|
||||||
const versions = new Set();
|
|
||||||
for (const dependency of allDependencies) {
|
|
||||||
versions.add(require(`../working-copy/${dependency}/package.json`).version);
|
|
||||||
}
|
|
||||||
if (versions.size !== 1) {
|
|
||||||
echo(`Mismatching version configuration. All dependencies must have the same version. Versions were: ${JSON.stringify(Array.from(versions), null, 2)}.`);
|
|
||||||
shell.exit(1);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
if (expectedVersion) {
|
|
||||||
if (!versions.has(expectedVersion)) {
|
|
||||||
echo(`Mismatching version configuration. Expected version was: '${expectedVersion}' actual was: '${Array.from(versions)[0]}'.`);
|
|
||||||
shell.exit(1);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
@ -199,9 +199,9 @@ function git(command) {
|
|||||||
function getChannelFile(platform) {
|
function getChannelFile(platform) {
|
||||||
let currentChannel = '';
|
let currentChannel = '';
|
||||||
if (isNightly) {
|
if (isNightly) {
|
||||||
currentChannel = 'nightly';
|
currentChannel = 'beta';
|
||||||
} else if (isRelease) {
|
} else if (isRelease) {
|
||||||
currentChannel = 'stable';
|
currentChannel = 'latest';
|
||||||
} else {
|
} else {
|
||||||
// We're not creating a nightly build nor releasing
|
// We're not creating a nightly build nor releasing
|
||||||
// a new version, no need for a channel file.
|
// a new version, no need for a channel file.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user