Fix Windows artifact naming in desktop packaging
- Fix the naming convention in Electron output to align with previous artifact naming to not break external/internal URLs. - In desktop execution tests, make artifact locator logic stricter to test regression.
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
import { join } from 'path';
|
||||
import { readdir } from 'fs/promises';
|
||||
import { die } from '../../../utils/log';
|
||||
import { exists } from '../../../utils/io';
|
||||
import { getAppName } from '../../../utils/npm';
|
||||
|
||||
export async function findByFilePattern(
|
||||
pattern: string,
|
||||
directory: string,
|
||||
projectRootDir: string,
|
||||
): Promise<ArtifactLocation> {
|
||||
if (!directory) { throw new Error('Missing directory'); }
|
||||
if (!pattern) { throw new Error('Missing file pattern'); }
|
||||
|
||||
if (!await exists(directory)) {
|
||||
return die(`Directory does not exist: ${directory}`);
|
||||
}
|
||||
|
||||
const directoryContents = await readdir(directory);
|
||||
const appName = await getAppName(projectRootDir);
|
||||
const regexPattern = pattern
|
||||
/* eslint-disable no-template-curly-in-string */
|
||||
.replaceAll('${name}', escapeRegExp(appName))
|
||||
.replaceAll('${version}', '\\d+\\.\\d+\\.\\d+')
|
||||
.replaceAll('${ext}', '.*');
|
||||
/* eslint-enable no-template-curly-in-string */
|
||||
const regex = new RegExp(`^${regexPattern}$`);
|
||||
const foundFileNames = directoryContents.filter((file) => regex.test(file));
|
||||
if (!foundFileNames.length) {
|
||||
return die(`No files found matching pattern "${pattern}" in ${directory} directory.`);
|
||||
}
|
||||
if (foundFileNames.length > 1) {
|
||||
return die(`Found multiple files matching pattern "${pattern}": ${foundFileNames.join(', ')}`);
|
||||
}
|
||||
return {
|
||||
absolutePath: join(directory, foundFileNames[0]),
|
||||
};
|
||||
}
|
||||
|
||||
function escapeRegExp(string: string) {
|
||||
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
}
|
||||
|
||||
interface ArtifactLocation {
|
||||
readonly absolutePath?: string;
|
||||
}
|
||||
@@ -1,15 +1,18 @@
|
||||
import { access, chmod } from 'fs/promises';
|
||||
import { constants } from 'fs';
|
||||
import { findSingleFileByExtension } from '../../utils/io';
|
||||
import { log } from '../../utils/log';
|
||||
import { ExtractionResult } from './extraction-result';
|
||||
import { ExtractionResult } from './common/extraction-result';
|
||||
import { findByFilePattern } from './common/app-artifact-locator';
|
||||
|
||||
export async function prepareLinuxApp(
|
||||
desktopDistPath: string,
|
||||
projectRootDir: string,
|
||||
): Promise<ExtractionResult> {
|
||||
const { absolutePath: appFile } = await findSingleFileByExtension(
|
||||
'AppImage',
|
||||
const { absolutePath: appFile } = await findByFilePattern(
|
||||
// eslint-disable-next-line no-template-curly-in-string
|
||||
'${name}-${version}.AppImage',
|
||||
desktopDistPath,
|
||||
projectRootDir,
|
||||
);
|
||||
await makeExecutable(appFile);
|
||||
return {
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
import { runCommand } from '../../utils/run-command';
|
||||
import { findSingleFileByExtension, exists } from '../../utils/io';
|
||||
import { exists } from '../../utils/io';
|
||||
import { log, die, LogLevel } from '../../utils/log';
|
||||
import { sleep } from '../../utils/sleep';
|
||||
import { ExtractionResult } from './extraction-result';
|
||||
import { ExtractionResult } from './common/extraction-result';
|
||||
import { findByFilePattern } from './common/app-artifact-locator';
|
||||
|
||||
export async function prepareMacOsApp(
|
||||
desktopDistPath: string,
|
||||
projectRootDir: string,
|
||||
): Promise<ExtractionResult> {
|
||||
const { absolutePath: dmgPath } = await findSingleFileByExtension('dmg', desktopDistPath);
|
||||
const { absolutePath: dmgPath } = await findByFilePattern(
|
||||
// eslint-disable-next-line no-template-curly-in-string
|
||||
'${name}-${version}.dmg',
|
||||
desktopDistPath,
|
||||
projectRootDir,
|
||||
);
|
||||
const { mountPath } = await mountDmg(dmgPath);
|
||||
const appPath = await findMacAppExecutablePath(mountPath);
|
||||
return {
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
import { mkdtemp, rm } from 'fs/promises';
|
||||
import { join } from 'path';
|
||||
import { tmpdir } from 'os';
|
||||
import { findSingleFileByExtension, exists } from '../../utils/io';
|
||||
import { exists } from '../../utils/io';
|
||||
import { log, die, LogLevel } from '../../utils/log';
|
||||
import { runCommand } from '../../utils/run-command';
|
||||
import { ExtractionResult } from './extraction-result';
|
||||
import { ExtractionResult } from './common/extraction-result';
|
||||
import { findByFilePattern } from './common/app-artifact-locator';
|
||||
|
||||
export async function prepareWindowsApp(
|
||||
desktopDistPath: string,
|
||||
projectRootDir: string,
|
||||
): Promise<ExtractionResult> {
|
||||
const workdir = await mkdtemp(join(tmpdir(), 'win-nsis-installation-'));
|
||||
if (await exists(workdir)) {
|
||||
log(`Temporary directory ${workdir} already exists, cleaning up...`);
|
||||
await rm(workdir, { recursive: true });
|
||||
}
|
||||
const appExecutablePath = await installNsis(workdir, desktopDistPath);
|
||||
const appExecutablePath = await installNsis(workdir, desktopDistPath, projectRootDir);
|
||||
return {
|
||||
appExecutablePath,
|
||||
cleanup: async () => {
|
||||
@@ -31,16 +33,26 @@ export async function prepareWindowsApp(
|
||||
async function installNsis(
|
||||
installationPath: string,
|
||||
desktopDistPath: string,
|
||||
projectRootDir: string,
|
||||
): Promise<string> {
|
||||
const { absolutePath: installerPath } = await findSingleFileByExtension('exe', desktopDistPath);
|
||||
|
||||
const { absolutePath: installerPath } = await findByFilePattern(
|
||||
// eslint-disable-next-line no-template-curly-in-string
|
||||
'${name}-Setup-${version}.exe',
|
||||
desktopDistPath,
|
||||
projectRootDir,
|
||||
);
|
||||
log(`Silently installing contents of ${installerPath} to ${installationPath}...`);
|
||||
const { error } = await runCommand(`"${installerPath}" /S /D=${installationPath}`);
|
||||
if (error) {
|
||||
return die(`Failed to install.\n${error}`);
|
||||
}
|
||||
|
||||
const { absolutePath: appExecutablePath } = await findSingleFileByExtension('exe', installationPath);
|
||||
const { absolutePath: appExecutablePath } = await findByFilePattern(
|
||||
// eslint-disable-next-line no-template-curly-in-string
|
||||
'${name}.exe',
|
||||
installationPath,
|
||||
projectRootDir,
|
||||
);
|
||||
|
||||
return appExecutablePath;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user