Restructure to monorepo (#6907)

* wip: restructure to monorepo

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* refactor create-release-pr to a package

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* build fixes

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* github workflow fixes

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* fix typo

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* add webpack-env types to core

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* fix github workflows

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* refactor/fix integration tests

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* lint fix

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* yarn run dev

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* eslint settings for vscode

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* move templates to right package

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* open-lens build fixes

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* integration test fix

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* fix nx task dependencies

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* use bash shell for unit tests in test workflow

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* fix test:unit for windows

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* fix win-ca webpack error in open-lens

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* fix win-ca webpack error in open-lens

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* fix build:app on windows

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* remove ELECTRON_BUILDER_EXTRA_ARGS

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* sync src/ from master

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* remove Makefile from core

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
Jari Kolehmainen authored and GitHub committed 2023-01-24 10:46:26 -08:00
1 parent 0066ca4ea2
commit 2657df2293
3321 files changed
+28699 -11447

No files matched your search

@@ -0,0 +1,148 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type Config from "conf";
import type { Migrations, Options as ConfOptions } from "conf/dist/source/types";
import type { IEqualsComparer } from "mobx";
import { makeObservable, reaction } from "mobx";
import { disposer, isPromiseLike, toJS } from "../utils";
import { broadcastMessage } from "../ipc";
import isEqual from "lodash/isEqual";
import { kebabCase } from "lodash";
import type { GetConfigurationFileModel } from "../get-configuration-file-model/get-configuration-file-model.injectable";
import type { Logger } from "../logger";
import type { PersistStateToConfig } from "./save-to-file";
import type { GetBasenameOfPath } from "../path/get-basename.injectable";
import type { EnlistMessageChannelListener } from "../utils/channel/enlist-message-channel-listener-injection-token";
export interface BaseStoreParams<T> extends Omit<ConfOptions<T>, "migrations"> {
syncOptions?: {
fireImmediately?: boolean;
equals?: IEqualsComparer<T>;
};
configName: string;
}
export interface IpcChannelPrefixes {
local: string;
remote: string;
}
export interface BaseStoreDependencies {
readonly logger: Logger;
readonly storeMigrationVersion: string;
readonly directoryForUserData: string;
readonly migrations: Migrations<Record<string, unknown>>;
readonly ipcChannelPrefixes: IpcChannelPrefixes;
readonly shouldDisableSyncInListener: boolean;
getConfigurationFileModel: GetConfigurationFileModel;
persistStateToConfig: PersistStateToConfig;
getBasenameOfPath: GetBasenameOfPath;
enlistMessageChannelListener: EnlistMessageChannelListener;
}
/**
* Note: T should only contain base JSON serializable types.
*/
export abstract class BaseStore<T extends object> {
private readonly syncDisposers = disposer();
readonly displayName = kebabCase(this.params.configName).toUpperCase();
protected constructor(
protected readonly dependencies: BaseStoreDependencies,
protected readonly params: BaseStoreParams<T>,
) {
makeObservable(this);
}
/**
* This must be called after the last child's constructor is finished (or just before it finishes)
*/
load() {
this.dependencies.logger.info(`[${this.displayName}]: LOADING ...`);
const config = this.dependencies.getConfigurationFileModel({
projectName: "lens",
projectVersion: this.dependencies.storeMigrationVersion,
cwd: this.cwd(),
...this.params,
migrations: this.dependencies.migrations as Migrations<T>,
});
const res = this.fromStore(config.store);
if (isPromiseLike(res)) {
this.dependencies.logger.error(`${this.displayName} extends BaseStore<T>'s fromStore method returns a Promise or promise-like object. This is an error and must be fixed.`);
}
this.startSyncing(config);
this.dependencies.logger.info(`[${this.displayName}]: LOADED from ${config.path}`);
}
protected cwd() {
return this.dependencies.directoryForUserData;
}
private startSyncing(config: Config<T>) {
const name = this.dependencies.getBasenameOfPath(config.path);
const disableSync = () => this.syncDisposers();
const enableSync = () => {
this.syncDisposers.push(
reaction(
() => toJS(this.toJSON()), // unwrap possible observables and react to everything
model => {
this.dependencies.persistStateToConfig(config, model);
broadcastMessage(`${this.dependencies.ipcChannelPrefixes.remote}:${config.path}`, model);
},
this.params.syncOptions,
),
this.dependencies.enlistMessageChannelListener({
channel: {
id: `${this.dependencies.ipcChannelPrefixes.local}:${config.path}`,
},
handler: (model) => {
this.dependencies.logger.silly(`[${this.displayName}]: syncing ${name}`, { model });
if (this.dependencies.shouldDisableSyncInListener) {
disableSync();
}
// todo: use "resourceVersion" if merge required (to avoid equality checks => better performance)
if (!isEqual(this.toJSON(), model)) {
this.fromStore(model as T);
}
if (this.dependencies.shouldDisableSyncInListener) {
enableSync();
}
},
}),
);
};
enableSync();
}
/**
* fromStore is called internally when a child class syncs with the file
* system.
*
* Note: This function **must** be synchronous.
*
* @param data the parsed information read from the stored JSON file
*/
protected abstract fromStore(data: T): void;
/**
* toJSON is called when syncing the store to the filesystem. It should
* produce a JSON serializable object representation of the current state.
*
* It is recommended that a round trip is valid. Namely, calling
* `this.fromStore(this.toJSON())` shouldn't change the state.
*/
abstract toJSON(): T;
}
@@ -0,0 +1,11 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectionToken } from "@ogre-tools/injectable";
import type { IpcChannelPrefixes } from "./base-store";
export const baseStoreIpcChannelPrefixesInjectionToken = getInjectionToken<IpcChannelPrefixes>({
id: "base-store-ipc-channel-prefix-token",
});
@@ -0,0 +1,10 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectionToken } from "@ogre-tools/injectable";
export const shouldBaseStoreDisableSyncInIpcListenerInjectionToken = getInjectionToken<boolean>({
id: "should-base-store-disable-sync-in-ipc-listener-token",
});
@@ -0,0 +1,46 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { InjectionToken } from "@ogre-tools/injectable";
import { lifecycleEnum, getInjectable } from "@ogre-tools/injectable";
import type Conf from "conf/dist/source";
import type { Migrations } from "conf/dist/source/types";
import loggerInjectable from "../logger.injectable";
import { getOrInsert, iter } from "../utils";
export interface MigrationDeclaration {
version: string;
run(store: Conf<Partial<Record<string, unknown>>>): void;
}
const storeMigrationsInjectable = getInjectable({
id: "store-migrations",
instantiate: (di, token): Migrations<Record<string, unknown>> => {
const logger = di.inject(loggerInjectable);
const declarations = di.injectMany(token);
const migrations = new Map<string, MigrationDeclaration["run"][]>();
for (const decl of declarations) {
getOrInsert(migrations, decl.version, []).push(decl.run);
}
return Object.fromEntries(
iter.map(
migrations,
([v, fns]) => [v, (store) => {
logger.info(`Running ${v} migration for ${store.path}`);
for (const fn of fns) {
fn(store);
}
}],
),
);
},
lifecycle: lifecycleEnum.keyedSingleton({
getInstanceKey: (di, token: InjectionToken<MigrationDeclaration, void>) => token.id,
}),
});
export default storeMigrationsInjectable;
@@ -0,0 +1,12 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectionToken } from "@ogre-tools/injectable";
import type Config from "conf";
export type PersistStateToConfig = <T extends object>(config: Config<T>, state: T) => void;
export const persistStateToConfigInjectionToken = getInjectionToken<PersistStateToConfig>({
id: "persist-state-to-config-token",
});