1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Merge branch 'master' into dependabot/npm_and_yarn/swc/core-1.3.37

This commit is contained in:
Alex Andreev 2023-03-03 11:51:56 +03:00
commit 405b1c16a5
60 changed files with 17339 additions and 1667 deletions

54
.github/workflows/cron-test.yaml vendored Normal file
View File

@ -0,0 +1,54 @@
name: Cron Test
on:
schedule:
- cron: "0 0 * * 1" # Run on the first day over every week
jobs:
test:
name: cron unit tests on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, macos-11, windows-2019]
node-version: [16.x]
steps:
- name: Checkout Release from lens
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Add the current IP address, long hostname and short hostname record to /etc/hosts file
if: runner.os == 'Linux'
run: |
echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts
- name: Using Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: Get npm cache directory path
if: ${{ runner.os != 'Windows' }}
id: npm-cache-dir-path
shell: bash
run: echo "dir=$(npm config get cache)" >> $GITHUB_OUTPUT
- uses: actions/cache@v3
if: ${{ runner.os != 'Windows' }}
id: npm-cache # use this to check for `cache-hit` (`steps.npm-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.npm-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-
- uses: nick-fields/retry@v2
name: Install dependencies
with:
timeout_minutes: 20
max_attempts: 3
retry_on: error
command: npm ci
- run: npm run test:unit
name: Run tests

View File

@ -7,14 +7,80 @@ on:
branches:
- master
jobs:
test:
name: ${{ matrix.type }} tests on ${{ matrix.os }}
integration-test:
name: integration tests on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, macos-11, windows-2019]
type: [unit, smoke]
node-version: [16.x]
steps:
- name: Checkout Release from lens
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Add the current IP address, long hostname and short hostname record to /etc/hosts file
if: runner.os == 'Linux'
run: |
echo -e "$(ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)\t$(hostname -f) $(hostname -s)" | sudo tee -a /etc/hosts
- name: Using Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: Get npm cache directory path
if: ${{ runner.os != 'Windows' }}
id: npm-cache-dir-path
shell: bash
run: echo "dir=$(npm config get cache)" >> $GITHUB_OUTPUT
- uses: actions/cache@v3
if: ${{ runner.os != 'Windows' }}
id: npm-cache # use this to check for `cache-hit` (`steps.npm-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.npm-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-
- uses: nick-fields/retry@v2
name: Install dependencies
with:
timeout_minutes: 20
max_attempts: 3
retry_on: error
command: npm ci
- name: Install integration test dependencies
id: minikube
uses: medyagh/setup-minikube@master
with:
minikube-version: latest
if: ${{ runner.os == 'Linux' }}
- run: xvfb-run --auto-servernum --server-args='-screen 0, 1600x900x24' npm run test:integration
name: Run Linux integration tests
if: ${{ runner.os == 'Linux' }}
- run: npm run test:integration
name: Run macOS integration tests
shell: bash
if: ${{ runner.os == 'macOS' }}
- run: npm run test:integration
name: Run Windows integration tests
if: ${{ runner.os == 'Windows' }}
unit-test:
name: unit tests on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04]
node-version: [16.x]
steps:
- name: Checkout Release from lens
@ -57,24 +123,3 @@ jobs:
- run: npm run test:unit
name: Run tests
if: ${{ matrix.type == 'unit' }}
- name: Install integration test dependencies
id: minikube
uses: medyagh/setup-minikube@master
with:
minikube-version: latest
if: ${{ runner.os == 'Linux' && matrix.type == 'smoke' }}
- run: xvfb-run --auto-servernum --server-args='-screen 0, 1600x900x24' npm run test:integration
name: Run Linux integration tests
if: ${{ runner.os == 'Linux' && matrix.type == 'smoke' }}
- run: npm run test:integration
name: Run macOS integration tests
shell: bash
if: ${{ runner.os == 'macOS' && matrix.type == 'smoke' }}
- run: npm run test:integration
name: Run Windows integration tests
if: ${{ runner.os == 'Windows' && matrix.type == 'smoke' }}

View File

@ -1,7 +1,7 @@
{
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
"useWorkspaces": true,
"version": "6.4.0-beta.13",
"version": "6.5.0-alpha.0",
"npmClient": "npm",
"npmClientArgs": [
"--network-timeout=100000"

17483
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -32,6 +32,6 @@
"adr": "^1.4.3",
"cross-env": "^7.0.3",
"lerna": "^6.5.1",
"rimraf": "^4.1.2"
"rimraf": "^4.1.3"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@k8slens/bump-version-for-cron",
"version": "6.4.0-cron.4db172da60",
"version": "6.5.0-alpha.0",
"description": "CLI to bump the version to during a cron daily alpha release",
"license": "MIT",
"scripts": {

View File

@ -3,7 +3,7 @@
"productName": "",
"description": "Lens Desktop Core",
"homepage": "https://github.com/lensapp/lens",
"version": "6.4.0-beta.13",
"version": "6.5.0-alpha.0",
"repository": {
"type": "git",
"url": "git+https://github.com/lensapp/lens.git"
@ -127,7 +127,7 @@
"@astronautlabs/jsonpath": "^1.1.0",
"@hapi/call": "^9.0.1",
"@hapi/subtext": "^7.1.0",
"@k8slens/node-fetch": "^6.4.0-beta.13",
"@k8slens/node-fetch": "^6.5.0-alpha.0",
"@kubernetes/client-node": "^0.18.1",
"@material-ui/styles": "^4.11.5",
"@ogre-tools/fp": "^15.1.1",
@ -329,7 +329,7 @@
"xterm-addon-fit": "^0.5.0"
},
"peerDependencies": {
"@k8slens/application": "^6.4.0-beta.13",
"@k8slens/application": "^6.5.0-alpha.0",
"@types/byline": "^4.2.33",
"@types/chart.js": "^2.9.36",
"@types/color": "^3.0.3",

View File

@ -3,7 +3,7 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { Environments, getEnvironmentSpecificLegacyGlobalDiForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
import { getEnvironmentSpecificLegacyGlobalDiForExtensionApi } from "../../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
import type { CatalogEntityContextMenuContext, CatalogEntityMetadata, CatalogEntityStatus } from "../catalog";
import { CatalogCategory, CatalogEntity, categoryVersion } from "../catalog/catalog-entity";
import productNameInjectable from "../vars/product-name.injectable";
@ -32,7 +32,7 @@ export class WebLink extends CatalogEntity<CatalogEntityMetadata, WebLinkStatus,
onContextMenuOpen(context: CatalogEntityContextMenuContext) {
// NOTE: this is safe because `onContextMenuOpen` is only supposed to be called in the renderer
const di = getEnvironmentSpecificLegacyGlobalDiForExtensionApi(Environments.renderer);
const di = getEnvironmentSpecificLegacyGlobalDiForExtensionApi("renderer");
const productName = di.inject(productNameInjectable);
const weblinkStore = di.inject(weblinkStoreInjectable);

View File

@ -0,0 +1,17 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { DiContainerForInjection } from "@ogre-tools/injectable";
export interface ApplicationConfig {
mode: string;
}
export interface Application {
start: () => Promise<void>;
readonly di: DiContainerForInjection;
}
export type CreateApplication = (config: ApplicationConfig) => Application;

View File

@ -7,7 +7,7 @@ import type { ReadOptions } from "fs-extra";
import fse from "fs-extra";
/**
* NOTE: Add corrisponding a corrisponding override of this injecable in `src/test-utils/override-fs-with-fakes.ts`
* NOTE: Add corresponding override of this injectable in `src/test-utils/override-fs-with-fakes.ts`
*/
const fsInjectable = getInjectable({
id: "fs",

View File

@ -24,6 +24,7 @@ export const applicationInformationFakeInjectable = getInjectable({
welcomeRoute: "/welcome",
copyright: "some-copyright-information",
description: "some-descriptive-text",
dependencies: {},
}),
injectionToken: applicationInformationToken,

View File

@ -0,0 +1,14 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import nodeEnvInjectionToken from "./node-env-injection-token";
const nodeEnvFakeInjectable = getInjectable({
id: "node-env-fake",
instantiate: () => "production",
injectionToken: nodeEnvInjectionToken,
});
export default nodeEnvFakeInjectable;

View File

@ -9,7 +9,7 @@ import {
createContainer,
getInjectable,
} from "@ogre-tools/injectable";
import { Environments, setLegacyGlobalDiForExtensionApi } from "./legacy-global-di-for-extension-api";
import { setLegacyGlobalDiForExtensionApi } from "./legacy-global-di-for-extension-api";
import { asLegacyGlobalObjectForExtensionApiWithModifications } from "./as-legacy-global-object-for-extension-api-with-modifications";
describe("asLegacyGlobalObjectForExtensionApiWithModifications", () => {
@ -25,7 +25,7 @@ describe("asLegacyGlobalObjectForExtensionApiWithModifications", () => {
jest.spyOn(di, "inject");
setLegacyGlobalDiForExtensionApi(di, Environments.renderer);
setLegacyGlobalDiForExtensionApi(di, "renderer");
someInjectable = getInjectable({
id: "some-injectable",

View File

@ -4,17 +4,11 @@
*/
import type { DiContainer } from "@ogre-tools/injectable";
export type Environments = "main" | "renderer";
const legacyGlobalDis = new Map<Environments, DiContainer>();
export enum Environments {
renderer,
main,
}
export const setLegacyGlobalDiForExtensionApi = (
di: DiContainer,
environment: Environments,
) => {
export const setLegacyGlobalDiForExtensionApi = (di: DiContainer, environment: Environments) => {
legacyGlobalDis.set(environment, di);
};

View File

@ -8,8 +8,8 @@ import extensionLoaderInjectable from "../extension-loader/extension-loader.inje
import isCompatibleExtensionInjectable from "./is-compatible-extension/is-compatible-extension.injectable";
import extensionsStoreInjectable from "../extensions-store/extensions-store.injectable";
import extensionInstallationStateStoreInjectable from "../extension-installation-state-store/extension-installation-state-store.injectable";
import installExtensionInjectable from "../extension-installer/install-extension/install-extension.injectable";
import extensionPackageRootDirectoryInjectable from "../extension-installer/extension-package-root-directory/extension-package-root-directory.injectable";
import installExtensionInjectable from "../install-extension/install-extension.injectable";
import extensionPackageRootDirectoryInjectable from "../install-extension/extension-package-root-directory.injectable";
import readJsonFileInjectable from "../../common/fs/read-json-file.injectable";
import loggerInjectable from "../../common/logger.injectable";
import pathExistsInjectable from "../../common/fs/path-exists.injectable";

View File

@ -7,7 +7,7 @@ import type { FSWatcher } from "chokidar";
import { getDiForUnitTesting } from "../../main/getDiForUnitTesting";
import extensionDiscoveryInjectable from "../extension-discovery/extension-discovery.injectable";
import type { ExtensionDiscovery } from "../extension-discovery/extension-discovery";
import installExtensionInjectable from "../extension-installer/install-extension/install-extension.injectable";
import installExtensionInjectable from "../install-extension/install-extension.injectable";
import directoryForUserDataInjectable from "../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
import { delay } from "../../renderer/utils";
import { observable, runInAction, when } from "mobx";

View File

@ -1,21 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import pathToNpmCliInjectable from "../../common/app-paths/path-to-npm-cli.injectable";
import loggerInjectable from "../../common/logger.injectable";
import { ExtensionInstaller } from "./extension-installer";
import extensionPackageRootDirectoryInjectable from "./extension-package-root-directory/extension-package-root-directory.injectable";
const extensionInstallerInjectable = getInjectable({
id: "extension-installer",
instantiate: (di) => new ExtensionInstaller({
extensionPackageRootDirectory: di.inject(extensionPackageRootDirectoryInjectable),
logger: di.inject(loggerInjectable),
pathToNpmCli: di.inject(pathToNpmCliInjectable),
}),
});
export default extensionInstallerInjectable;

View File

@ -1,78 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import AwaitLock from "await-lock";
import child_process from "child_process";
import type { Logger } from "../../common/logger";
const logModule = "[EXTENSION-INSTALLER]";
interface Dependencies {
readonly extensionPackageRootDirectory: string;
readonly logger: Logger;
readonly pathToNpmCli: string;
}
const baseNpmInstallArgs = [
"install",
"--audit=false",
"--fund=false",
// NOTE: we do not omit the `optional` dependencies because that is how we specify the non-bundled extensions
"--omit=dev",
"--omit=peer",
"--prefer-offline",
];
/**
* Installs dependencies for extensions
*/
export class ExtensionInstaller {
private readonly installLock = new AwaitLock();
constructor(private readonly dependencies: Dependencies) {}
/**
* Install single package using npm
*/
installPackage = async (name: string): Promise<void> => {
// Mutual exclusion to install packages in sequence
await this.installLock.acquireAsync();
try {
this.dependencies.logger.info(`${logModule} installing package from ${name} to ${this.dependencies.extensionPackageRootDirectory}`);
await this.npm(...baseNpmInstallArgs, name);
this.dependencies.logger.info(`${logModule} package ${name} installed to ${this.dependencies.extensionPackageRootDirectory}`);
} finally {
this.installLock.release();
}
};
private npm(...args: string[]): Promise<void> {
return new Promise((resolve, reject) => {
const child = child_process.fork(this.dependencies.pathToNpmCli, args, {
cwd: this.dependencies.extensionPackageRootDirectory,
silent: true,
env: {},
});
let stderr = "";
child.stderr?.on("data", data => {
stderr += String(data);
});
child.on("close", (code) => {
if (code !== 0) {
reject(new Error(stderr));
} else {
resolve();
}
});
child.on("error", error => {
reject(error);
});
});
}
}

View File

@ -1,13 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import extensionInstallerInjectable from "../extension-installer.injectable";
const installExtensionInjectable = getInjectable({
id: "install-extension",
instantiate: (di) => di.inject(extensionInstallerInjectable).installPackage,
});
export default installExtensionInjectable;

View File

@ -3,7 +3,7 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
import directoryForUserDataInjectable from "../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
const extensionPackageRootDirectoryInjectable = getInjectable({
id: "extension-package-root-directory",

View File

@ -0,0 +1,111 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { fork } from "child_process";
import AwaitLock from "await-lock";
import pathToNpmCliInjectable from "../../common/app-paths/path-to-npm-cli.injectable";
import extensionPackageRootDirectoryInjectable from "./extension-package-root-directory.injectable";
import prefixedLoggerInjectable from "../../common/logger/prefixed-logger.injectable";
import readJsonFileInjectable from "../../common/fs/read-json-file.injectable";
import joinPathsInjectable from "../../common/path/join-paths.injectable";
import type { PackageJson } from "../common-api";
import writeJsonFileInjectable from "../../common/fs/write-json-file.injectable";
import { once } from "lodash";
import { isErrnoException } from "../../common/utils";
const baseNpmInstallArgs = [
"install",
"--save-optional",
"--audit=false",
"--fund=false",
// NOTE: we do not omit the `optional` dependencies because that is how we specify the non-bundled extensions
"--omit=dev",
"--omit=peer",
"--prefer-offline",
];
export type InstallExtension = (name: string) => Promise<void>;
const installExtensionInjectable = getInjectable({
id: "install-extension",
instantiate: (di): InstallExtension => {
const pathToNpmCli = di.inject(pathToNpmCliInjectable);
const extensionPackageRootDirectory = di.inject(extensionPackageRootDirectoryInjectable);
const readJsonFile = di.inject(readJsonFileInjectable);
const writeJsonFile = di.inject(writeJsonFileInjectable);
const joinPaths = di.inject(joinPathsInjectable);
const logger = di.inject(prefixedLoggerInjectable, "EXTENSION-INSTALLER");
const forkNpm = (...args: string[]) => new Promise<void>((resolve, reject) => {
const child = fork(pathToNpmCli, args, {
cwd: extensionPackageRootDirectory,
silent: true,
env: {},
});
let stderr = "";
child.stderr?.on("data", data => {
stderr += String(data);
});
child.on("close", (code) => {
if (code !== 0) {
reject(new Error(stderr));
} else {
resolve();
}
});
child.on("error", error => {
reject(error);
});
});
const packageJsonPath = joinPaths(extensionPackageRootDirectory, "package.json");
/**
* NOTES:
* - We have to keep the `package.json` because `npm install` removes files from `node_modules`
* if they are no longer in the `package.json`
* - In v6.2.X we saved bundled extensions as `"dependencies"` and external extensions as
* `"optionalDependencies"` at startup. This was done because `"optionalDependencies"` can
* fail to install and that is OK.
* - We continue to maintain this behavior here by only installing new dependencies as
* `"optionalDependencies"`
*/
const fixupPackageJson = once(async () => {
try {
const packageJson = await readJsonFile(packageJsonPath) as PackageJson;
delete packageJson.dependencies;
await writeJsonFile(packageJsonPath, packageJson);
} catch (error) {
if (isErrnoException(error) && error.code === "ENOENT") {
return;
}
throw error;
}
});
const installLock = new AwaitLock();
return async (name) => {
await installLock.acquireAsync();
await fixupPackageJson();
try {
logger.info(`installing package for extension "${name}"`);
await forkNpm(...baseNpmInstallArgs, name);
logger.info(`installed package for extension "${name}"`);
} finally {
installLock.release();
}
};
},
});
export default installExtensionInjectable;

View File

@ -3,16 +3,11 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import {
Environments,
getEnvironmentSpecificLegacyGlobalDiForExtensionApi,
} from "../as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
import { getEnvironmentSpecificLegacyGlobalDiForExtensionApi } from "../as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
import navigateInjectable from "../../main/start-main-application/lens-window/navigate.injectable";
export function navigate(url: string) {
const di = getEnvironmentSpecificLegacyGlobalDiForExtensionApi(Environments.main);
const di = getEnvironmentSpecificLegacyGlobalDiForExtensionApi("main");
const navigate = di.inject(navigateInjectable);
return navigate(url);

View File

@ -2,22 +2,34 @@
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { applicationInformationToken } from "@k8slens/application";
import { getInjectable } from "@ogre-tools/injectable";
import { bundledExtensionInjectionToken } from "../../../../../../common/library";
import { object } from "../../../../../../common/utils";
import buildSemanticVersionInjectable from "../../../../../../common/vars/build-semantic-version.injectable";
const aboutBundledExtensionsInjectable = getInjectable({
id: "about-bundled-extensions",
const specificVersionsInjectable = getInjectable({
id: "specific-versions",
instantiate: (di) => {
const buildSemanticVersion = di.inject(buildSemanticVersionInjectable);
const bundledExtensions = di.injectMany(bundledExtensionInjectionToken);
const applicationInformation = di.inject(applicationInformationToken);
if (buildSemanticVersion.get().prerelease[0] === "latest") {
return [];
}
return bundledExtensions.map(ext => `${ext.manifest.name}: ${ext.manifest.version}`);
const corePackageVersions = object.entries(applicationInformation.dependencies)
.filter(([name]) => name.startsWith("@k8slens/"))
.map(([name, version]) => `${name}: ${version}`);
const bundledExtensionVersions = bundledExtensions
.map(ext => `${ext.manifest.name}: ${ext.manifest.version}`);
return [
...corePackageVersions,
...bundledExtensionVersions,
];
},
});
export default aboutBundledExtensionsInjectable;
export default specificVersionsInjectable;

View File

@ -10,7 +10,7 @@ import productNameInjectable from "../../../../../../common/vars/product-name.in
import buildVersionInjectable from "../../../../../../main/vars/build-version/build-version.injectable";
import extensionApiVersionInjectable from "../../../../../../common/vars/extension-api-version.injectable";
import applicationCopyrightInjectable from "../../../../../../common/vars/application-copyright.injectable";
import aboutBundledExtensionsInjectable from "./about-bundled-extensions.injectable";
import specificVersionsInjectable from "./about-bundled-extensions.injectable";
const showAboutInjectable = getInjectable({
id: "show-about",
@ -23,7 +23,7 @@ const showAboutInjectable = getInjectable({
const appName = di.inject(appNameInjectable);
const productName = di.inject(productNameInjectable);
const applicationCopyright = di.inject(applicationCopyrightInjectable);
const aboutBundledExtensions = di.inject(aboutBundledExtensionsInjectable);
const specificVersions = di.inject(specificVersionsInjectable);
return () => {
const appInfo = [
@ -32,14 +32,26 @@ const showAboutInjectable = getInjectable({
`Electron: ${process.versions.electron}`,
`Chrome: ${process.versions.chrome}`,
`Node: ${process.versions.node}`,
...aboutBundledExtensions,
applicationCopyright,
];
if (specificVersions.length > 0) {
appInfo.push(
"",
"",
...specificVersions,
);
}
showMessagePopup(
`${isWindows ? " ".repeat(2) : ""}${appName}`,
productName,
appInfo.join("\r\n"),
{
textWidth: specificVersions.length > 0
? 300
: undefined,
},
);
};
},

View File

@ -22,7 +22,10 @@ const pickHighestAccuracy = (prev: ClusterDetectionResult, curr: ClusterDetectio
const detectMetadataWithFor = (cluster: Cluster) => async (clusterMetadataDetector: ClusterMetadataDetector) => {
try {
return await clusterMetadataDetector.detect(cluster);
return {
key: clusterMetadataDetector.key,
result: await clusterMetadataDetector.detect(cluster),
};
} catch {
return null;
}
@ -39,7 +42,12 @@ const detectClusterMetadataInjectable = getInjectable({
filter(isDefined),
(arg) => groupBy(arg, "key"),
(arg) => object.entries(arg),
map(([ key, results ]) => [key, reduce(results, pickHighestAccuracy)] as const),
map(([ key, detectionResults ]) => {
const results = detectionResults.map(({ result }) => result as ClusterDetectionResult);
const highestAccuracyResult = reduce(results, pickHighestAccuracy)?.value;
return [key, highestAccuracyResult] as const;
}),
filter(hasDefinedTupleValue),
);

View File

@ -0,0 +1,107 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { AppPaths } from "../../common/app-paths/app-path-injection-token";
import appPathsStateInjectable from "../../common/app-paths/app-paths-state.injectable";
import directoryForKubeConfigsInjectable from "../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable";
import directoryForUserDataInjectable from "../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
import { ClusterMetadataKey } from "../../common/cluster-types";
import type { Cluster } from "../../common/cluster/cluster";
import { createClusterInjectionToken } from "../../common/cluster/create-cluster-injection-token";
import { getDiForUnitTesting } from "../getDiForUnitTesting";
import clusterDistributionDetectorInjectable from "./cluster-distribution-detector.injectable";
import clusterIdDetectorFactoryInjectable from "./cluster-id-detector.injectable";
import clusterLastSeenDetectorInjectable from "./cluster-last-seen-detector.injectable";
import clusterNodeCountDetectorInjectable from "./cluster-nodes-count-detector.injectable";
import type { DetectClusterMetadata } from "./detect-cluster-metadata.injectable";
import detectClusterMetadataInjectable from "./detect-cluster-metadata.injectable";
import requestClusterVersionInjectable from "./request-cluster-version.injectable";
describe("detect-cluster-metadata", () => {
let detectClusterMetadata: DetectClusterMetadata;
let cluster: Cluster;
beforeEach(async () => {
const di = getDiForUnitTesting({ doGeneralOverrides: true });
const lastSeenDetectMock = jest.fn().mockReturnValue(Promise.resolve({ value: "some-time-stamp", accuracy: 100 }));
const nodeCountDetectMock = jest.fn().mockReturnValue(Promise.resolve({ value: 42, accuracy: 100 }));
const clusterIdDetectMock = jest.fn().mockReturnValue(Promise.resolve({ value: "some-cluster-id", accuracy: 100 }));
const distributionDetectMock = jest.fn().mockReturnValue(Promise.resolve({ value: "some-distribution", accuracy: 100 }));
di.override(clusterLastSeenDetectorInjectable, () => {
return {
key: ClusterMetadataKey.LAST_SEEN,
detect: lastSeenDetectMock,
};
});
di.override(requestClusterVersionInjectable, () => () => Promise.resolve("some-cluster-version"));
di.override(clusterNodeCountDetectorInjectable, () => ({
key: ClusterMetadataKey.NODES_COUNT,
detect: nodeCountDetectMock,
}));
di.override(clusterIdDetectorFactoryInjectable, () => ({
key: ClusterMetadataKey.CLUSTER_ID,
detect: clusterIdDetectMock,
}));
di.override(clusterDistributionDetectorInjectable, () => ({
key: ClusterMetadataKey.DISTRIBUTION,
detect: distributionDetectMock,
}));
di.override(directoryForUserDataInjectable, () => "/some-user-store-path");
di.override(directoryForKubeConfigsInjectable, () => "/some-kube-configs");
di.override(appPathsStateInjectable, () => ({
get: () => ({} as AppPaths),
set: () => {},
}));
detectClusterMetadata = di.inject(detectClusterMetadataInjectable);
const createCluster = di.inject(createClusterInjectionToken);
cluster = createCluster({
id: "some-id",
contextName: "some-context",
kubeConfigPath: "minikube-config.yml",
}, {
clusterServerUrl: "foo",
});
});
it("given some cluster, last seen time stamp is added to the metadata", async () => {
const metadata = await detectClusterMetadata(cluster);
expect(metadata.lastSeen).toEqual("some-time-stamp");
});
it("given some cluster, cluster version is added to the metadata", async () => {
const metadata = await detectClusterMetadata(cluster);
expect(metadata.version).toEqual("some-cluster-version");
});
it("given some cluster, id is added to the metadata", async () => {
const metadata = await detectClusterMetadata(cluster);
expect(metadata.id).toEqual("some-cluster-id");
});
it("given some cluster, node count is added to the metadata", async () => {
const metadata = await detectClusterMetadata(cluster);
expect(metadata.nodes).toEqual(42);
});
it("given some cluster, distribution is added to the metadata", async () => {
const metadata = await detectClusterMetadata(cluster);
expect(metadata.distribution).toEqual("some-distribution");
});
});

View File

@ -3,20 +3,17 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { DiContainer } from "@ogre-tools/injectable";
import { getInjectable } from "@ogre-tools/injectable";
import { runInAction } from "mobx";
import type { CreateApplication } from "../common/create-app";
import nodeEnvInjectionToken from "../common/vars/node-env-injection-token";
import { getDi } from "./getDi";
import { registerInjectables } from "./register-injectables";
import startMainApplicationInjectable from "./start-main-application/start-main-application.injectable";
interface AppConfig {
di: DiContainer;
mode: string;
}
export function createApp(conf: AppConfig) {
const { di, mode } = conf;
export const createApplication: CreateApplication = (config) => {
const { mode } = config;
const di = getDi();
runInAction(() => {
di.register(getInjectable({
@ -28,9 +25,8 @@ export function createApp(conf: AppConfig) {
registerInjectables(di);
});
const startMainApplication = di.inject(startMainApplicationInjectable);
return {
start: () => startMainApplication(),
start: di.inject(startMainApplicationInjectable),
di,
};
}
};

View File

@ -5,7 +5,11 @@
import { getInjectable } from "@ogre-tools/injectable";
import electronDialogInjectable from "./electron-dialog.injectable";
export type ShowMessagePopup = (title: string, message: string, detail: string) => void;
export interface ShowMessagePopupOptions {
textWidth?: number;
}
export type ShowMessagePopup = (title: string, message: string, detail: string, options?: ShowMessagePopupOptions) => void;
const showMessagePopupInjectable = getInjectable({
id: "show-message-popup",
@ -13,13 +17,14 @@ const showMessagePopupInjectable = getInjectable({
instantiate: (di): ShowMessagePopup => {
const dialog = di.inject(electronDialogInjectable);
return async (title, message, detail) => {
return async (title, message, detail, options = {}) => {
await dialog.showMessageBox({
title,
message,
detail,
type: "info",
buttons: ["Close"],
...options,
});
};
},

View File

@ -3,5 +3,15 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { createContainer } from "@ogre-tools/injectable";
import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx";
import { setLegacyGlobalDiForExtensionApi } from "../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
export const getDi = () => createContainer("main");
export const getDi = () => {
const environment = "main";
const di = createContainer(environment);
registerMobX(di);
setLegacyGlobalDiForExtensionApi(di, environment);
return di;
};

View File

@ -4,9 +4,8 @@
*/
import { chunk } from "lodash/fp";
import type { DiContainer, Injectable } from "@ogre-tools/injectable";
import { createContainer, isInjectable, getInjectable } from "@ogre-tools/injectable";
import { Environments, setLegacyGlobalDiForExtensionApi } from "../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
import type { DiContainer } from "@ogre-tools/injectable";
import { isInjectable } from "@ogre-tools/injectable";
import spawnInjectable from "./child-process/spawn.injectable";
import initializeExtensionsInjectable from "./start-main-application/runnables/initialize-extensions.injectable";
import setupIpcMainHandlersInjectable from "./electron-app/runnables/setup-ipc-main-handlers/setup-ipc-main-handlers.injectable";
@ -25,46 +24,30 @@ import electronQuitAndInstallUpdateInjectable from "./electron-app/features/elec
import electronUpdaterIsActiveInjectable from "./electron-app/features/electron-updater-is-active.injectable";
import setUpdateOnQuitInjectable from "./electron-app/features/set-update-on-quit.injectable";
import waitUntilBundledExtensionsAreLoadedInjectable from "./start-main-application/lens-window/application-window/wait-until-bundled-extensions-are-loaded.injectable";
import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx";
import electronInjectable from "./utils/resolve-system-proxy/electron.injectable";
import initializeClusterManagerInjectable from "./cluster/initialize-manager.injectable";
import type { GlobalOverride } from "../common/test-utils/get-global-override";
import nodeEnvInjectionToken from "../common/vars/node-env-injection-token";
import { getOverrideFsWithFakes } from "../test-utils/override-fs-with-fakes";
import { applicationInformationFakeInjectable } from "../common/vars/application-information-fake-injectable";
import { getDi } from "./getDi";
export function getDiForUnitTesting(opts: { doGeneralOverrides?: boolean } = {}) {
const {
doGeneralOverrides = false,
} = opts;
const di = createContainer("main");
di.register(getInjectable({
id: "node-env",
instantiate: () => "production",
injectionToken: nodeEnvInjectionToken,
}));
setLegacyGlobalDiForExtensionApi(di, Environments.main);
const di = getDi();
di.preventSideEffects();
const injectables = (
global.injectablePaths.main.paths
runInAction(() => {
const injectables = global.injectablePaths.main.paths
.map(path => require(path))
.flatMap(Object.values)
.filter(isInjectable)
) as Injectable<any, any, any>[];
.filter(isInjectable);
registerMobX(di);
runInAction(() => {
di.register(applicationInformationFakeInjectable);
chunk(100)(injectables).forEach(chunkInjectables => {
di.register(...chunkInjectables);
});
for (const block of chunk(100)(injectables)) {
di.register(...block);
}
});
if (doGeneralOverrides) {

View File

@ -8,7 +8,8 @@ export { afterApplicationIsLoadedInjectionToken } from "./start-main-application
export { beforeApplicationIsLoadingInjectionToken } from "./start-main-application/runnable-tokens/before-application-is-loading-injection-token";
export { beforeElectronIsReadyInjectionToken } from "./start-main-application/runnable-tokens/before-electron-is-ready-injection-token";
export { onLoadOfApplicationInjectionToken } from "./start-main-application/runnable-tokens/on-load-of-application-injection-token";
export { createApp } from "./create-app";
export { createApplication } from "./create-app";
export type { CreateApplication, Application, ApplicationConfig } from "../common/create-app";
export * as Mobx from "mobx";
export * as mainExtensionApi from "../extensions/main-api";
export * as commonExtensionApi from "../extensions/common-api";

View File

@ -4,16 +4,10 @@
*/
import type { DiContainer } from "@ogre-tools/injectable";
import { autoRegister } from "@ogre-tools/injectable-extension-for-auto-registration";
import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx";
import { runInAction } from "mobx";
import { Environments, setLegacyGlobalDiForExtensionApi } from "../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
export function registerInjectables(di: DiContainer) {
setLegacyGlobalDiForExtensionApi(di, Environments.main);
runInAction(() => {
registerMobX(di);
autoRegister({
di,
targetModule: module,
@ -25,6 +19,4 @@ export function registerInjectables(di: DiContainer) {
],
});
});
return di;
}

View File

@ -5,19 +5,16 @@
import "./components/app.scss";
import { bootstrap } from "./bootstrap";
import type { DiContainer } from "@ogre-tools/injectable";
import { getInjectable } from "@ogre-tools/injectable";
import nodeEnvInjectionToken from "../common/vars/node-env-injection-token";
import { runInAction } from "mobx";
import { registerInjectables } from "./register-injectables";
import type { CreateApplication } from "../common/create-app";
import { getDi } from "./getDi";
interface AppConfig {
di: DiContainer;
mode: string;
}
export function createApp(conf: AppConfig) {
const { di, mode } = conf;
export const createApplication: CreateApplication = (config) => {
const { mode } = config;
const di = getDi();
runInAction(() => {
di.register(getInjectable({
@ -25,10 +22,12 @@ export function createApp(conf: AppConfig) {
instantiate: () => mode,
injectionToken: nodeEnvInjectionToken,
}));
registerInjectables(di);
});
return {
start: () => bootstrap(di),
di,
};
}
};

View File

@ -4,5 +4,17 @@
*/
import { createContainer } from "@ogre-tools/injectable";
import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx";
import { registerInjectableReact } from "@ogre-tools/injectable-react";
import { setLegacyGlobalDiForExtensionApi } from "../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
export const getDi = () => createContainer("renderer");
export const getDi = () => {
const environment = "renderer";
const di = createContainer(environment);
registerMobX(di);
registerInjectableReact(di);
setLegacyGlobalDiForExtensionApi(di, environment);
return di;
};

View File

@ -4,9 +4,7 @@
*/
import { noop, chunk } from "lodash/fp";
import type { Injectable } from "@ogre-tools/injectable";
import { createContainer, isInjectable, getInjectable } from "@ogre-tools/injectable";
import { Environments, setLegacyGlobalDiForExtensionApi } from "../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
import { isInjectable } from "@ogre-tools/injectable";
import requestFromChannelInjectable from "./utils/channel/request-from-channel.injectable";
import { getOverrideFsWithFakes } from "../test-utils/override-fs-with-fakes";
import terminalSpawningPoolInjectable from "./components/dock/terminal/terminal-spawning-pool.injectable";
@ -14,47 +12,29 @@ import hostedClusterIdInjectable from "./cluster-frame-context/hosted-cluster-id
import { runInAction } from "mobx";
import requestAnimationFrameInjectable from "./components/animate/request-animation-frame.injectable";
import startTopbarStateSyncInjectable from "./components/layout/top-bar/start-state-sync.injectable";
import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx";
import watchHistoryStateInjectable from "./remote-helpers/watch-history-state.injectable";
import legacyOnChannelListenInjectable from "./ipc/legacy-channel-listen.injectable";
import type { GlobalOverride } from "../common/test-utils/get-global-override";
import nodeEnvInjectionToken from "../common/vars/node-env-injection-token";
import { applicationInformationFakeInjectable } from "../common/vars/application-information-fake-injectable";
import { registerInjectableReact } from "@ogre-tools/injectable-react";
import { getDi } from "./getDi";
export const getDiForUnitTesting = (
opts: { doGeneralOverrides?: boolean } = {},
) => {
const { doGeneralOverrides = false } = opts;
const di = createContainer("renderer");
di.register(getInjectable({
id: "node-env",
instantiate: () => "production",
injectionToken: nodeEnvInjectionToken,
}));
const di = getDi();
di.preventSideEffects();
setLegacyGlobalDiForExtensionApi(di, Environments.renderer);
const injectables = (
global.injectablePaths.renderer.paths
runInAction(() => {
const injectables = global.injectablePaths.renderer.paths
.map(path => require(path))
.flatMap(Object.values)
.filter(isInjectable)
) as Injectable<any, any, any>[];
.filter(isInjectable);
registerMobX(di);
registerInjectableReact(di);
runInAction(() => {
di.register(applicationInformationFakeInjectable);
chunk(100)(injectables).forEach((chunkInjectables) => {
di.register(...chunkInjectables);
});
for (const block of chunk(100)(injectables)) {
di.register(...block);
}
});
if (doGeneralOverrides) {

View File

@ -14,4 +14,5 @@ export * as ReactRouter from "react-router";
export * as ReactRouterDom from "react-router-dom";
export * as rendererExtensionApi from "../extensions/renderer-api";
export * as commonExtensionApi from "../extensions/common-api";
export { createApp } from "./create-app";
export { createApplication } from "./create-app";
export type { CreateApplication, Application, ApplicationConfig } from "../common/create-app";

View File

@ -5,19 +5,10 @@
import type { DiContainer } from "@ogre-tools/injectable";
import { autoRegister } from "@ogre-tools/injectable-extension-for-auto-registration";
import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx";
import { registerInjectableReact } from "@ogre-tools/injectable-react";
import { runInAction } from "mobx";
import { Environments, setLegacyGlobalDiForExtensionApi } from "../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
export function registerInjectables(di: DiContainer) {
setLegacyGlobalDiForExtensionApi(di, Environments.renderer);
registerMobX(di);
registerInjectableReact(di);
runInAction(() => {
autoRegister({
di,
targetModule: module,
@ -29,6 +20,4 @@ export function registerInjectables(di: DiContainer) {
],
});
});
return di;
}

View File

@ -1,6 +1,6 @@
{
"name": "@k8slens/ensure-binaries",
"version": "6.4.0-beta.13",
"version": "6.5.0-alpha.0",
"description": "CLI for downloading configured versions of the bundled versions of CLIs",
"main": "dist/index.js",
"license": "MIT",

View File

@ -2,7 +2,7 @@
"name": "@k8slens/extensions",
"productName": "OpenLens extensions",
"description": "OpenLens - Open Source Kubernetes IDE: extensions",
"version": "6.4.0-beta.13",
"version": "6.5.0-alpha.0",
"copyright": "© 2022 OpenLens Authors",
"license": "MIT",
"main": "dist/extension-api.js",
@ -26,7 +26,7 @@
"prepare:dev": "npm run build"
},
"dependencies": {
"@k8slens/core": "^6.4.0-beta.13"
"@k8slens/core": "^6.5.0-alpha.0"
},
"devDependencies": {
"@types/node": "^16.18.6",

View File

@ -1,6 +1,6 @@
{
"name": "@k8slens/generate-tray-icons",
"version": "6.4.0-beta.13",
"version": "6.5.0-alpha.0",
"description": "CLI generating tray icons for building a lens-like application",
"license": "MIT",
"scripts": {

View File

@ -1,7 +1,7 @@
{
"name": "@k8slens/jest",
"private": false,
"version": "0.0.1",
"version": "6.5.0-alpha.0",
"description": "Jest configuration and scripts for Lens packages.",
"type": "commonjs",
"publishConfig": {

View File

@ -1,7 +1,7 @@
{
"name": "@k8slens/typescript",
"private": false,
"version": "0.0.1",
"version": "6.5.0-alpha.0",
"description": "Typescript configuration for Lens packages.",
"type": "commonjs",
"publishConfig": {

View File

@ -1,7 +1,7 @@
{
"name": "@k8slens/webpack",
"private": false,
"version": "0.0.1",
"version": "6.5.0-alpha.0",
"description": "Webpack configurations and scripts for Lens packages.",
"type": "commonjs",
"publishConfig": {
@ -25,6 +25,7 @@
"dependencies": {
"@types/webpack-env": "^1.18.0",
"css-loader": "^6.7.2",
"fork-ts-checker-webpack-plugin": "^7.3.0",
"mini-css-extract-plugin": "^2.7.0",
"sass-loader": "^13.2.0",
"style-loader": "^3.3.1",

View File

@ -0,0 +1,226 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`get-multi-export-config given maximal package.json, when creating configuration works 1`] = `
Array [
Object {
"entry": Object {
"index": "./index.ts",
},
"externals": Array [
[Function],
[Function],
],
"externalsPresets": Object {
"node": true,
},
"mode": "production",
"module": Object {
"rules": Array [
Object {
"loader": "ts-loader",
"test": /\\\\\\.ts\\(x\\)\\?\\$/,
},
],
},
"name": "./index.ts",
"node": Object {
"__dirname": true,
"__filename": true,
},
"output": Object {
"filename": [Function],
"libraryTarget": "commonjs2",
"path": "/some-working-directory/dist",
},
"performance": Object {
"hints": "error",
"maxEntrypointSize": 100000,
},
"plugins": Array [
ForkTsCheckerWebpackPlugin {
"options": Object {
"typescript": Object {
"configOverwrite": Object {
"compilerOptions": Object {
"declaration": true,
"declarationDir": "/some-working-directory/dist",
},
"include": Array [
"./index.ts",
],
},
"mode": "write-dts",
},
},
},
],
"resolve": Object {
"extensions": Array [
".ts",
".tsx",
],
},
"target": "node",
},
Object {
"entry": Object {
"index": "./some-entrypoint/index.ts",
},
"externals": Array [
[Function],
[Function],
],
"externalsPresets": Object {
"node": true,
},
"mode": "production",
"module": Object {
"rules": Array [
Object {
"loader": "ts-loader",
"test": /\\\\\\.ts\\(x\\)\\?\\$/,
},
],
},
"name": "./some-entrypoint/index.ts",
"node": Object {
"__dirname": true,
"__filename": true,
},
"output": Object {
"filename": [Function],
"libraryTarget": "commonjs2",
"path": "/some-working-directory/dist/some-entrypoint",
},
"performance": Object {
"hints": "error",
"maxEntrypointSize": 100000,
},
"plugins": Array [
ForkTsCheckerWebpackPlugin {
"options": Object {
"typescript": Object {
"configOverwrite": Object {
"compilerOptions": Object {
"declaration": true,
"declarationDir": "/some-working-directory/dist/some-entrypoint",
},
"include": Array [
"./some-entrypoint/index.ts",
],
},
"mode": "write-dts",
},
},
},
],
"resolve": Object {
"extensions": Array [
".ts",
".tsx",
],
},
"target": "node",
},
Object {
"entry": Object {
"index": "./some-other-entrypoint/index.ts",
},
"externals": Array [
[Function],
[Function],
],
"externalsPresets": Object {
"node": true,
},
"mode": "production",
"module": Object {
"rules": Array [
Object {
"loader": "ts-loader",
"test": /\\\\\\.ts\\(x\\)\\?\\$/,
},
Object {
"test": /\\\\\\.s\\?css\\$/,
"use": Array [
Object {
"some": "miniCssExtractPluginLoader",
},
Object {
"loader": "css-loader",
"options": Object {
"modules": Object {
"auto": /\\\\\\.module\\\\\\./i,
"localIdentName": "[name]__[local]--[hash:base64:5]",
"mode": "local",
},
"sourceMap": false,
},
},
Object {
"loader": "sass-loader",
"options": Object {
"sourceMap": false,
},
},
],
},
],
},
"name": "./some-other-entrypoint/index.ts",
"node": Object {
"__dirname": true,
"__filename": true,
},
"output": Object {
"filename": [Function],
"libraryTarget": "commonjs2",
"path": "/some-working-directory/dist/some-other-entrypoint",
},
"performance": Object {
"hints": "error",
"maxEntrypointSize": 100000,
},
"plugins": Array [
ForkTsCheckerWebpackPlugin {
"options": Object {
"typescript": Object {
"configOverwrite": Object {
"compilerOptions": Object {
"declaration": true,
"declarationDir": "/some-working-directory/dist/some-other-entrypoint",
},
"include": Array [
"./some-other-entrypoint/index.ts",
],
},
"mode": "write-dts",
},
},
},
MiniCssExtractPlugin {
"_sortedModulesCache": WeakMap {},
"options": Object {
"chunkFilename": "[name].css",
"experimentalUseImportModule": undefined,
"filename": "[name].css",
"ignoreOrder": false,
"runtime": true,
},
"runtimeOptions": Object {
"attributes": undefined,
"insert": undefined,
"linkType": "text/css",
},
},
],
"resolve": Object {
"extensions": Array [
".ts",
".tsx",
],
},
"target": "node",
},
]
`;

View File

@ -1,5 +1,5 @@
const nodeConfig = require("./node-config");
const reactConfig = require("./react-config");
const getNodeConfig = require("./get-node-config");
const getReactConfigFor = require("./get-react-config");
const path = require("path");
const {
map,
@ -14,7 +14,15 @@ const {
} = require("lodash/fp");
const { pipeline } = require("@ogre-tools/fp");
module.exports = (packageJson, dependencies = { nodeConfig, reactConfig, joinPath: path.join }) => {
module.exports = (
packageJson,
dependencies = {
resolvePath: path.resolve,
workingDirectory: process.cwd(),
getReactConfig: getReactConfigFor()
}
) => {
if (!packageJson.lensMultiExportConfig) {
throw new Error(
`Tried to get multi export config for package "${packageJson.name}" but configuration is missing.`
@ -72,10 +80,13 @@ module.exports = (packageJson, dependencies = { nodeConfig, reactConfig, joinPat
);
}
const toExportSpecificWebpackConfig =
toExportSpecificWebpackConfigFor(dependencies);
return pipeline(
packageJson.lensMultiExportConfig,
toPairs,
map(toExportSpecificWebpackConfigFor(dependencies))
map(toExportSpecificWebpackConfig)
);
};
@ -91,7 +102,11 @@ const toExpectedExport = (externalImportPath) => {
return [
externalImportPath,
{
types: `./${posixJoinForPackageJson("./dist", externalImportPath, "index.d.ts")}`,
types: `./${posixJoinForPackageJson(
"./dist",
externalImportPath,
"index.d.ts"
)}`,
default: entrypointPath,
import: entrypointPath,
@ -103,20 +118,19 @@ const toExpectedExport = (externalImportPath) => {
const toExportSpecificWebpackConfigFor =
(dependencies) =>
([externalImportPath, { buildType, entrypoint }]) => {
const baseConfig =
buildType === "node" ? dependencies.nodeConfig : dependencies.reactConfig;
const outputDirectory = dependencies.resolvePath(
dependencies.workingDirectory,
"dist",
externalImportPath
);
return {
...baseConfig,
name: entrypoint,
entry: {
index: entrypoint,
},
output: {
...baseConfig.output,
path: dependencies.joinPath(baseConfig.output.path, externalImportPath),
},
};
return buildType === "node"
? getNodeConfig({
entrypointFilePath: entrypoint,
outputDirectory,
})
: dependencies.getReactConfig({
entrypointFilePath: entrypoint,
outputDirectory,
});
};

View File

@ -1,10 +1,12 @@
import ForkTsCheckerPlugin from "fork-ts-checker-webpack-plugin";
import getMultiExportConfig from "./get-multi-export-config";
import path from 'path';
import path from "path";
const getReactConfigFor = require("./get-react-config");
const joinPathFake = path.posix.join;
const resolvePathFake = path.posix.resolve;
describe("get-multi-export-config", () => {
let actual;
let configs;
let maximalPackageJson;
beforeEach(() => {
@ -51,43 +53,69 @@ describe("get-multi-export-config", () => {
};
});
it("given maximal package.json, when creating configuration, works", () => {
actual = getMultiExportConfig(maximalPackageJson, {
nodeConfig: nodeConfigStub,
reactConfig: reactConfigStub,
joinPath: joinPathFake,
describe("given maximal package.json, when creating configuration", () => {
beforeEach(() => {
configs = getMultiExportConfig(maximalPackageJson, {
resolvePath: resolvePathFake,
workingDirectory: "/some-working-directory",
getReactConfig: getReactConfigFor({
miniCssExtractPluginLoader: { some: "miniCssExtractPluginLoader" },
}),
});
});
expect(actual).toEqual([
it("works", () => {
expect(configs).toMatchSnapshot();
});
[
{
name: "./index.ts",
stub: "node",
entry: { index: "./index.ts" },
output: { some: "value", path: "/some-build-directory" },
name: "config for node export in default entrypoint",
entrypoint: "./index.ts",
outputDirectory: "/some-working-directory/dist",
},
{
name: "./some-entrypoint/index.ts",
stub: "node",
entry: { index: "./some-entrypoint/index.ts" },
output: {
some: "value",
path: "/some-build-directory/some-entrypoint",
},
name: "config for node export in a non-default entrypoint",
entrypoint: "./some-entrypoint/index.ts",
outputDirectory: "/some-working-directory/dist/some-entrypoint",
},
{
name: "./some-other-entrypoint/index.ts",
stub: "react",
entry: { index: "./some-other-entrypoint/index.ts" },
output: {
some: "other-value",
path: "/some-build-directory/some-other-entrypoint",
},
name: "config for react export in a non-default entrypoint",
entrypoint: "./some-other-entrypoint/index.ts",
outputDirectory: "/some-working-directory/dist/some-other-entrypoint",
},
]);
].forEach((scenario) => {
describe(scenario.name, () => {
let config;
beforeEach(() => {
config = configs.find(({ name }) => name === scenario.entrypoint);
});
it("has correct entrypoint", () => {
expect(config).toHaveProperty("entry.index", scenario.entrypoint);
});
it("has correct output directory", () => {
expect(config).toHaveProperty(
"output.path",
scenario.outputDirectory
);
});
it("has correct declaration directory", () => {
expect(
config.plugins.find(
({ constructor }) => constructor === ForkTsCheckerPlugin
)
).toHaveProperty(
"options.typescript.configOverwrite.compilerOptions.declarationDir",
scenario.outputDirectory
);
});
});
});
});
it("given maximal package.json but path for entrypoint in exports do not match output, when creating configuration, throws", () => {
@ -95,9 +123,9 @@ describe("get-multi-export-config", () => {
expect(() => {
getMultiExportConfig(maximalPackageJson, {
nodeConfig: nodeConfigStub,
reactConfig: reactConfigStub,
joinPath: joinPathFake,
getNodeConfig: () => nodeConfigStub,
getReactConfig: () => reactConfigStub,
joinPath: resolvePathFake,
});
}).toThrow(
'Tried to get multi export config but exports of package.json for "some-name" did not match exactly:'
@ -109,9 +137,9 @@ describe("get-multi-export-config", () => {
expect(() => {
getMultiExportConfig(maximalPackageJson, {
nodeConfig: nodeConfigStub,
reactConfig: reactConfigStub,
joinPath: joinPathFake,
getNodeConfig: () => nodeConfigStub,
getReactConfig: () => reactConfigStub,
joinPath: resolvePathFake,
});
}).toThrow(
'Tried to get multi export config but exports of package.json for "some-name" did not match exactly:'
@ -123,9 +151,9 @@ describe("get-multi-export-config", () => {
expect(() => {
getMultiExportConfig(maximalPackageJson, {
nodeConfig: nodeConfigStub,
reactConfig: reactConfigStub,
joinPath: joinPathFake,
getNodeConfig: () => nodeConfigStub,
getReactConfig: () => reactConfigStub,
joinPath: resolvePathFake,
});
}).toThrow(
'Tried to get multi export config but exports of package.json for "some-name" did not match exactly:'
@ -137,9 +165,9 @@ describe("get-multi-export-config", () => {
expect(() => {
getMultiExportConfig(maximalPackageJson, {
nodeConfig: nodeConfigStub,
reactConfig: reactConfigStub,
joinPath: joinPathFake,
getNodeConfig: () => nodeConfigStub,
getReactConfig: () => reactConfigStub,
joinPath: resolvePathFake,
});
}).toThrow(
'Tried to get multi export config for package "some-name" but configuration is missing.'
@ -151,9 +179,9 @@ describe("get-multi-export-config", () => {
expect(() => {
getMultiExportConfig(maximalPackageJson, {
nodeConfig: nodeConfigStub,
reactConfig: reactConfigStub,
joinPath: joinPathFake,
getNodeConfig: () => nodeConfigStub,
getReactConfig: () => reactConfigStub,
joinPath: resolvePathFake,
});
}).toThrow(
'Tried to get multi export config for package "some-name" but build types "some-invalid" were not any of "node", "react".'
@ -166,9 +194,9 @@ describe("get-multi-export-config", () => {
expect(() => {
getMultiExportConfig(maximalPackageJson, {
nodeConfig: nodeConfigStub,
reactConfig: reactConfigStub,
joinPath: joinPathFake,
getNodeConfig: () => nodeConfigStub,
getReactConfig: () => reactConfigStub,
joinPath: resolvePathFake,
});
}).toThrow(
'Tried to get multi export config for package "some-name" but entrypoint was missing for "./some-entrypoint".'

View File

@ -0,0 +1,78 @@
const ForkTsCheckerPlugin = require("fork-ts-checker-webpack-plugin");
const nodeExternals = require("webpack-node-externals");
const path = require("path");
module.exports = ({ entrypointFilePath, outputDirectory }) => ({
name: entrypointFilePath,
entry: { index: entrypointFilePath },
target: "node",
mode: "production",
performance: {
maxEntrypointSize: 100000,
hints: "error",
},
resolve: {
extensions: [".ts", ".tsx"],
},
plugins: [
new ForkTsCheckerPlugin({
typescript: {
mode: "write-dts",
configOverwrite: {
include: [entrypointFilePath],
compilerOptions: {
declaration: true,
declarationDir: outputDirectory,
},
},
},
}),
],
output: {
path: outputDirectory,
filename: (pathData) =>
pathData.chunk.name === "index"
? "index.js"
: `${pathData.chunk.name}/index.js`,
libraryTarget: "commonjs2",
},
externals: [
nodeExternals({ modulesFromFile: true }),
nodeExternals({
modulesDir: path.resolve(
__dirname,
"..",
"..",
"..",
"..",
"node_modules"
),
}),
],
externalsPresets: { node: true },
node: {
__dirname: true,
__filename: true,
},
module: {
rules: [
{
test: /\.ts(x)?$/,
loader: "ts-loader",
},
],
},
});

View File

@ -0,0 +1,60 @@
const getNodeConfig = require("./get-node-config");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports =
({ miniCssExtractPluginLoader = MiniCssExtractPlugin.loader } = {}) =>
({ entrypointFilePath, outputDirectory }) => {
const nodeConfig = getNodeConfig({
entrypointFilePath,
outputDirectory,
});
return {
...nodeConfig,
plugins: [
...nodeConfig.plugins,
new MiniCssExtractPlugin({
filename: "[name].css",
}),
],
module: {
...nodeConfig.module,
rules: [
...nodeConfig.module.rules,
{
test: /\.s?css$/,
use: [
miniCssExtractPluginLoader,
{
loader: "css-loader",
options: {
sourceMap: false,
modules: {
auto: /\.module\./i, // https://github.com/webpack-contrib/css-loader#auto
mode: "local", // :local(.selector) by default
localIdentName: "[name]__[local]--[hash:base64:5]",
},
},
},
{
loader: "sass-loader",
options: {
sourceMap: false,
},
},
],
},
],
},
};
};

View File

@ -1,68 +1,7 @@
const nodeExternals = require("webpack-node-externals");
const path = require("path");
const getNodeConfig = require("./get-node-config");
const buildDirectory = path.resolve(process.cwd(), "dist");
module.exports = {
entry: { index: "./index.ts" },
target: "node",
mode: "production",
performance: {
maxEntrypointSize: 100000,
hints: "error",
},
resolve: {
extensions: [".ts", ".tsx"],
},
output: {
path: buildDirectory,
filename: (pathData) =>
pathData.chunk.name === "index"
? "index.js"
: `${pathData.chunk.name}/index.js`,
libraryTarget: "commonjs2",
},
externals: [
nodeExternals({ modulesFromFile: true }),
nodeExternals({
modulesDir: path.resolve(
__dirname,
"..",
"..",
"..",
"..",
"node_modules"
),
}),
],
externalsPresets: { node: true },
node: {
__dirname: true,
__filename: true,
},
module: {
rules: [
{
test: /\.ts(x)?$/,
loader: "ts-loader",
options: {
compilerOptions: {
declaration: true,
declarationDir: "./dist",
},
},
},
],
},
};
module.exports = getNodeConfig({
entrypointFilePath: "./index.ts",
outputDirectory: path.resolve(process.cwd(), "dist"),
});

View File

@ -1,44 +1,7 @@
const nodeConfig = require("./node-config");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const path = require("path");
const getReactConfig = require("./get-react-config");
module.exports = {
...nodeConfig,
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css",
}),
],
module: {
...nodeConfig.module,
rules: [
...nodeConfig.module.rules,
{
test: /\.s?css$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
sourceMap: false,
modules: {
auto: /\.module\./i, // https://github.com/webpack-contrib/css-loader#auto
mode: "local", // :local(.selector) by default
localIdentName: "[name]__[local]--[hash:base64:5]",
},
},
},
{
loader: "sass-loader",
options: {
sourceMap: false,
},
},
],
},
],
},
};
module.exports = getReactConfig({
entrypointFilePath: "./index.ts",
outputDirectory: path.resolve(process.cwd(), "dist"),
});

View File

@ -1,6 +1,6 @@
{
"name": "@k8slens/node-fetch",
"version": "6.4.0-beta.13",
"version": "6.5.0-alpha.0",
"description": "Node fetch for Lens",
"license": "MIT",
"private": false,

View File

@ -4,7 +4,7 @@
"productName": "OpenLens",
"description": "OpenLens - Open Source IDE for Kubernetes",
"homepage": "https://github.com/lensapp/lens",
"version": "6.4.0-beta.13",
"version": "6.5.0-alpha.0",
"repository": {
"type": "git",
"url": "git+https://github.com/lensapp/lens.git"
@ -195,10 +195,10 @@
}
},
"dependencies": {
"@k8slens/application": "^6.4.0-beta.13",
"@k8slens/core": "^6.4.0-beta.13",
"@k8slens/ensure-binaries": "^6.4.0-beta.13",
"@k8slens/generate-tray-icons": "^6.4.0-beta.13",
"@k8slens/application": "^6.5.0-alpha.0",
"@k8slens/core": "^6.5.0-alpha.0",
"@k8slens/ensure-binaries": "^6.5.0-alpha.0",
"@k8slens/generate-tray-icons": "^6.5.0-alpha.0",
"@ogre-tools/fp": "^15.1.1",
"@ogre-tools/injectable": "^15.1.1",
"@ogre-tools/injectable-extension-for-auto-registration": "^15.1.1",
@ -208,7 +208,8 @@
"rimraf": "^4.1.2"
},
"devDependencies": {
"@k8slens/node-fetch": "^6.4.0-beta.13",
"@electron/rebuild": "^3.2.10",
"@k8slens/node-fetch": "^6.5.0-alpha.0",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.10",
"@swc/cli": "^0.1.61",
"@swc/core": "^1.3.35",
@ -272,7 +273,6 @@
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.11.1",
"webpack-node-externals": "^3.0.0",
"xterm-addon-fit": "^0.5.0",
"@electron/rebuild": "^3.2.10"
"xterm-addon-fit": "^0.5.0"
}
}

View File

@ -8,12 +8,9 @@ import { applicationInformationToken } from "@k8slens/application";
const applicationInformationInjectable = getInjectable({
id: "application-information",
injectionToken: applicationInformationToken,
instantiate: () => {
const {
version,
config: {
bundledHelmVersion,
bundledKubectlVersion,
@ -22,12 +19,12 @@ const applicationInformationInjectable = getInjectable({
sentryDsn,
welcomeRoute,
},
productName,
build,
copyright,
description,
name,
dependencies,
} = packageJson;
return {
@ -43,9 +40,11 @@ const applicationInformationInjectable = getInjectable({
contentSecurityPolicy,
welcomeRoute,
updatingIsEnabled: (build as any)?.publish?.length > 0,
dependencies,
};
},
causesSideEffects: true,
injectionToken: applicationInformationToken,
});
export default applicationInformationInjectable;

View File

@ -1,18 +1,15 @@
import { createContainer } from "@ogre-tools/injectable";
import { autoRegister } from "@ogre-tools/injectable-extension-for-auto-registration";
import { runInAction } from "mobx";
import { createApp, mainExtensionApi as Main, commonExtensionApi as Common } from "@k8slens/core/main";
import { createApplication, mainExtensionApi as Main, commonExtensionApi as Common } from "@k8slens/core/main";
const di = createContainer("main");
const app = createApp({
di,
const app = createApplication({
mode: process.env.NODE_ENV || "development"
});
runInAction(() => {
try {
autoRegister({
di,
di: app.di,
targetModule: module,
getRequireContexts: () => [
require.context("./", true, CONTEXT_MATCHER_FOR_NON_FEATURES),

View File

@ -1,18 +1,15 @@
import "@k8slens/core/styles";
import { createContainer } from "@ogre-tools/injectable";
import { runInAction } from "mobx";
import { createApp, rendererExtensionApi as Renderer, commonExtensionApi as Common } from "@k8slens/core/renderer";
import { createApplication, rendererExtensionApi as Renderer, commonExtensionApi as Common } from "@k8slens/core/renderer";
import { autoRegister } from "@ogre-tools/injectable-extension-for-auto-registration";
const di = createContainer("renderer");
const app = createApp({
di,
const app = createApplication({
mode: process.env.NODE_ENV || "development"
});
runInAction(() => {
autoRegister({
di,
di: app.di,
targetModule: module,
getRequireContexts: () => [
require.context("./", true, CONTEXT_MATCHER_FOR_NON_FEATURES),

View File

@ -1,6 +1,6 @@
{
"name": "@k8slens/release-tool",
"version": "6.4.0-beta.13",
"version": "6.5.0-alpha.0",
"description": "Release tool for lens monorepo",
"main": "dist/index.mjs",
"license": "MIT",

View File

@ -1,6 +1,6 @@
{
"name": "@k8slens/semver",
"version": "6.4.0-beta.13",
"version": "6.5.0-alpha.0",
"description": "CLI over semver package for picking parts of a version",
"license": "MIT",
"private": true,

View File

@ -1,7 +1,7 @@
{
"name": "@k8slens/application",
"private": false,
"version": "6.4.0-beta.13",
"version": "6.5.0-alpha.0",
"description": "Package for creating Lens applications",
"type": "commonjs",
"files": [

View File

@ -17,6 +17,7 @@ export type ApplicationInformation = {
contentSecurityPolicy: string,
welcomeRoute: string,
updatingIsEnabled: boolean;
dependencies: Partial<Record<string, string>>;
}
export const applicationInformationToken = getInjectionToken<ApplicationInformation>({

View File

@ -1,9 +1,15 @@
{
"name": "@k8slens/feature-core",
"private": false,
"version": "0.0.1",
"version": "6.5.0-alpha.0",
"description": "Code that is common to all Features and those registering them.",
"type": "commonjs",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
},
"files": [
"dist"
],