Refactor build configs and improve CI/CD checks
This commit makes the build process more robust, simplifies configurations and reduce the risk of incomplete or erroneous deployments. - Centralize output directory definitions by introducing `dist-dirs.json`. - Add `verify-build-artifacts` utility to ensure correct build outputs and `print-dist-dir` to determine distribution directory. - Add steps in CI/CD pipeline to verify build artifacts. - Migrate Electron Builder config from YAML to CJS for capability to read JSON. - Fix `release-site.yaml` failing due to pointing to wrong distribution directory, change it to use `print-dist-dir`. - Improve `check-desktop-runtime-errors` to verify build artifacts for more reliable builds. Ensure tests fail and succeed reliably. - Update `.gitignore` and configure ESLint to use it to define and ignore build artifact directories from one place, remove `.eslintignore` that does not add anything after this change. - Keep `"main"` field in `package.json` as `electron-vite` depends on it (alex8088/electron-vite#270). - Improve documentation
This commit is contained in:
@@ -1,7 +1,13 @@
|
||||
import { join } from 'path';
|
||||
import distDirs from '@/../dist-dirs.json' assert { type: 'json' };
|
||||
|
||||
export const DESKTOP_BUILD_COMMAND = 'npm run electron:prebuild && npm run electron:build -- --publish never';
|
||||
export const DESKTOP_BUILD_COMMAND = [
|
||||
'npm run electron:prebuild',
|
||||
'npm run check:verify-build-artifacts -- --electron-unbundled',
|
||||
'npm run electron:build -- --publish never',
|
||||
'npm run check:verify-build-artifacts -- --electron-bundled',
|
||||
].join(' && ');
|
||||
export const PROJECT_DIR = process.cwd();
|
||||
export const DESKTOP_DIST_PATH = join(PROJECT_DIR, 'dist');
|
||||
export const DESKTOP_DIST_PATH = join(PROJECT_DIR, distDirs.electronBundled);
|
||||
export const APP_EXECUTION_DURATION_IN_SECONDS = 60; // Long enough for CI runners
|
||||
export const SCREENSHOT_PATH = join(PROJECT_DIR, 'screenshot.png');
|
||||
|
||||
@@ -60,7 +60,11 @@ export async function npmBuild(
|
||||
cwd: projectDir,
|
||||
});
|
||||
if (error) {
|
||||
log(error, LogLevel.Warn); // Cannot disable Vue CLI errors, stderr contains false-positives.
|
||||
die(error);
|
||||
}
|
||||
|
||||
if (await isDirMissingOrEmpty(distDir)) {
|
||||
die(`The desktop application build process did not produce the expected artifacts. The output directory "${distDir}" is empty or missing.`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +1,67 @@
|
||||
import { test } from 'vitest';
|
||||
import {
|
||||
describe, it, beforeAll, afterAll,
|
||||
} from 'vitest';
|
||||
import { main } from './check-desktop-runtime-errors/main';
|
||||
import { COMMAND_LINE_FLAGS, CommandLineFlag } from './check-desktop-runtime-errors/cli-args';
|
||||
|
||||
test('should have no desktop runtime errors', async () => {
|
||||
// arrange
|
||||
setCommandLineFlagsFromEnvironmentVariables();
|
||||
let exitCode: number;
|
||||
global.process.exit = (code?: number): never => {
|
||||
exitCode = code;
|
||||
return undefined as never;
|
||||
};
|
||||
// act
|
||||
await main();
|
||||
// assert
|
||||
expect(exitCode).to.equal(0);
|
||||
}, {
|
||||
timeout: 60 /* minutes */ * 10000,
|
||||
describe('desktop runtime error checks', () => {
|
||||
const { waitForExitCode } = useInterceptedProcessExitOrCompletion(beforeAll, afterAll);
|
||||
it('should successfully execute the main function and exit with a zero status code', async () => {
|
||||
// arrange
|
||||
setCommandLineFlagsFromEnvironmentVariables();
|
||||
// act
|
||||
const exitCode = await waitForExitCode(
|
||||
() => main(),
|
||||
);
|
||||
// assert
|
||||
expect(exitCode).to.equal(0);
|
||||
}, {
|
||||
timeout: 60 /* minutes */ * 60000,
|
||||
});
|
||||
});
|
||||
|
||||
function useInterceptedProcessExitOrCompletion(
|
||||
beforeTest: (callback: () => void) => void,
|
||||
afterTest: (callback: () => void) => void,
|
||||
) {
|
||||
const originalFunction = global.process.exit;
|
||||
let isExitCodeReceived = false;
|
||||
let exitCodeResolver: (value: number | undefined) => void;
|
||||
const waitForExitCode = (runner: () => Promise<void>) => new Promise<number | undefined>(
|
||||
(resolve, reject) => {
|
||||
exitCodeResolver = resolve;
|
||||
runner()
|
||||
.catch((error) => {
|
||||
if (isExitCodeReceived) {
|
||||
return;
|
||||
}
|
||||
console.error('Process did not call `process.exit` but threw an error:', error);
|
||||
reject(error);
|
||||
})
|
||||
.then(() => {
|
||||
if (isExitCodeReceived) {
|
||||
return;
|
||||
}
|
||||
console.log('Process completed without calling `process.exit`. Treating as `0` exit code.');
|
||||
exitCodeResolver(0);
|
||||
});
|
||||
},
|
||||
);
|
||||
beforeTest(() => {
|
||||
global.process.exit = (code?: number): never => {
|
||||
exitCodeResolver(code);
|
||||
isExitCodeReceived = true;
|
||||
return undefined as never;
|
||||
};
|
||||
});
|
||||
afterTest(() => {
|
||||
global.process.exit = originalFunction;
|
||||
});
|
||||
return {
|
||||
waitForExitCode,
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
Map environment variables to CLI arguments for compatibility with Vitest.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user