Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions packages/compass-e2e-tests/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,8 @@
fixtures/*.csv
fixtures/*.json
hadron-build-info.json

# Ignoring sandboxes (created per test run)
.smoke-sandboxes/
# Cache of downloaded binaries
.smoke-downloads/
5 changes: 5 additions & 0 deletions packages/compass-e2e-tests/.prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,8 @@ fixtures
.nyc_output
coverage
hadron-build-info.json

# Ignoring sandboxes (created per test run)
.smoke-sandboxes/
# Cache of downloaded binaries
.smoke-downloads/
80 changes: 0 additions & 80 deletions packages/compass-e2e-tests/helpers/buildinfo.ts

This file was deleted.

189 changes: 189 additions & 0 deletions packages/compass-e2e-tests/helpers/smoke-test/build-info.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import assert from 'node:assert/strict';
import fs from 'node:fs';
import path from 'node:path';

import { handler as writeBuildInfo } from 'hadron-build/commands/info';

import { type PackageKind } from './packages';
import { type SmokeTestsContext } from './context';
import { pick } from 'lodash';

function assertObjectHasKeys(
obj: unknown,
name: string,
keys: readonly string[]
) {
assert(
typeof obj === 'object' && obj !== null,
'Expected buildInfo to be an object'
);

for (const key of keys) {
assert(key in obj, `Expected '${name}' to have '${key}'`);
}
}

// subsets of the hadron-build info result

export const commonKeys = ['productName'] as const;
export type CommonBuildInfo = Record<typeof commonKeys[number], string>;

export function assertCommonBuildInfo(
buildInfo: unknown
): asserts buildInfo is CommonBuildInfo {
assertObjectHasKeys(buildInfo, 'buildInfo', commonKeys);
}

export const windowsFilenameKeys = [
'windows_setup_filename',
'windows_msi_filename',
'windows_zip_filename',
'windows_nupkg_full_filename',
] as const;
export type WindowsBuildInfo = CommonBuildInfo &
Record<typeof windowsFilenameKeys[number], string>;

export function assertBuildInfoIsWindows(
buildInfo: unknown
): asserts buildInfo is WindowsBuildInfo {
assertObjectHasKeys(buildInfo, 'buildInfo', commonKeys);
assertObjectHasKeys(buildInfo, 'buildInfo', windowsFilenameKeys);
}

export const osxFilenameKeys = [
'osx_dmg_filename',
'osx_zip_filename',
] as const;
export type OSXBuildInfo = CommonBuildInfo &
Record<typeof osxFilenameKeys[number], string>;

export function assertBuildInfoIsOSX(
buildInfo: unknown
): asserts buildInfo is OSXBuildInfo {
assertObjectHasKeys(buildInfo, 'buildInfo', commonKeys);
assertObjectHasKeys(buildInfo, 'buildInfo', osxFilenameKeys);
}

export const ubuntuFilenameKeys = [
'linux_deb_filename',
'linux_tar_filename',
] as const;
export type UbuntuBuildInfo = CommonBuildInfo &
Record<typeof ubuntuFilenameKeys[number], string>;

export function assertBuildInfoIsUbuntu(
buildInfo: unknown
): asserts buildInfo is UbuntuBuildInfo {
assertObjectHasKeys(buildInfo, 'buildInfo', commonKeys);
assertObjectHasKeys(buildInfo, 'buildInfo', ubuntuFilenameKeys);
}

const rhelFilenameKeys = ['linux_rpm_filename', 'rhel_tar_filename'] as const;
export type RHELBuildInfo = CommonBuildInfo &
Record<typeof rhelFilenameKeys[number], string>;

export function assertBuildInfoIsRHEL(
buildInfo: unknown
): asserts buildInfo is RHELBuildInfo {
assertObjectHasKeys(buildInfo, 'buildInfo', commonKeys);
assertObjectHasKeys(buildInfo, 'buildInfo', rhelFilenameKeys);
}

export type PackageDetails = {
kind: PackageKind;
filename: string;
} & (
| {
kind: 'windows_setup' | 'windows_msi' | 'windows_zip';
buildInfo: WindowsBuildInfo;
}
| {
kind: 'osx_dmg' | 'osx_zip';
buildInfo: OSXBuildInfo;
}
| {
kind: 'linux_deb' | 'linux_tar';
buildInfo: UbuntuBuildInfo;
}
| {
kind: 'linux_rpm' | 'rhel_tar';
buildInfo: RHELBuildInfo;
}
);

/**
* Extracts the filename of the packaged app from the build info, specific to a kind of package.
*/
export function getPackageDetails(
kind: PackageKind,
buildInfo: unknown
): PackageDetails {
if (
kind === 'windows_setup' ||
kind === 'windows_msi' ||
kind === 'windows_zip'
) {
assertBuildInfoIsWindows(buildInfo);
return { kind, buildInfo, filename: buildInfo[`${kind}_filename`] };
} else if (kind === 'osx_dmg' || kind === 'osx_zip') {
assertBuildInfoIsOSX(buildInfo);
return { kind, buildInfo, filename: buildInfo[`${kind}_filename`] };
} else if (kind === 'linux_deb' || kind === 'linux_tar') {
assertBuildInfoIsUbuntu(buildInfo);
return { kind, buildInfo, filename: buildInfo[`${kind}_filename`] };
} else if (kind === 'linux_rpm' || kind === 'rhel_tar') {
assertBuildInfoIsRHEL(buildInfo);
return { kind, buildInfo, filename: buildInfo[`${kind}_filename`] };
} else {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
throw new Error(`Unsupported package kind: ${kind}`);
}
}

function readJson<T extends object>(...segments: string[]): T {
const result = JSON.parse(
fs.readFileSync(path.join(...segments), 'utf8')
) as unknown;
assert(typeof result === 'object' && result !== null, 'Expected an object');
return result as T;
}

export function readPackageDetails(
kind: PackageKind,
filePath: string
): PackageDetails {
const result = readJson(filePath);
return getPackageDetails(kind, result);
}

export function writeAndReadPackageDetails(
context: SmokeTestsContext
): PackageDetails {
const compassDir = path.resolve(__dirname, '../../../compass');
const infoArgs = {
format: 'json',
dir: compassDir,
platform: context.platform,
arch: context.arch,
out: path.resolve(context.sandboxPath, 'target.json'),
};
console.log({ infoArgs });

// These are known environment variables that will affect the way
// writeBuildInfo works. Log them as a reminder and for our own sanity
console.log(
'info env vars',
pick(process.env, [
'HADRON_DISTRIBUTION',
'HADRON_APP_VERSION',
'HADRON_PRODUCT',
'HADRON_PRODUCT_NAME',
'HADRON_READONLY',
'HADRON_ISOLATED',
'DEV_VERSION_IDENTIFIER',
'IS_RHEL',
])
);
writeBuildInfo(infoArgs);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Part of me wants to change hadron-build so we can get this info as a variable without an intermediate file, but I've been a bit weary of changing that code because it is used in so many ways and often only at release time. Although I suppose nowadays we release dev too, so it should be safer.

return readPackageDetails(context.package, infoArgs.out);
}
12 changes: 12 additions & 0 deletions packages/compass-e2e-tests/helpers/smoke-test/context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { type PackageKind } from './packages';

export type SmokeTestsContext = {
bucketName?: string;
bucketKeyPrefix?: string;
platform: 'win32' | 'darwin' | 'linux';
arch: 'x64' | 'arm64';
package: PackageKind;
forceDownload?: boolean;
localPackage?: boolean;
sandboxPath: string;
};
32 changes: 32 additions & 0 deletions packages/compass-e2e-tests/helpers/smoke-test/directories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import assert from 'node:assert';
import crypto from 'node:crypto';
import fs from 'node:fs';
import path from 'node:path';

function ensureSandboxesDirectory() {
const sandboxesPath = path.resolve(__dirname, '../../.smoke-sandboxes');
if (!fs.existsSync(sandboxesPath)) {
fs.mkdirSync(sandboxesPath, { recursive: true });
}
return sandboxesPath;
}

export function createSandbox() {
const nonce = crypto.randomBytes(4).toString('hex');
const sandboxPath = path.resolve(ensureSandboxesDirectory(), nonce);
assert.equal(
fs.existsSync(sandboxPath),
false,
`Failed to create sandbox at '${sandboxPath}' - it already exists`
);
fs.mkdirSync(sandboxPath);
return sandboxPath;
}

export function ensureDownloadsDirectory() {
const downloadsPath = path.resolve(__dirname, '../../.smoke-downloads');
if (!fs.existsSync(downloadsPath)) {
fs.mkdirSync(downloadsPath, { recursive: true });
}
return downloadsPath;
}
Loading
Loading