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,61 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { Composite } from "../get-composite/get-composite";
import { compositeHasDescendant } from "./composite-has-descendant";
import { getCompositeFor } from "../get-composite/get-composite";
describe("composite-has-descendant, given composite with children and grand children", () => {
let composite: Composite<{ id: string; parentId?: string }>;
beforeEach(() => {
const items = [
{ id: "some-root-id", parentId: undefined },
{ id: "some-child-item", parentId: "some-root-id" },
{
id: "some-grand-child-item",
parentId: "some-child-item",
},
];
const getComposite = getCompositeFor<{
id: string;
parentId?: string;
}>({
rootId: "some-root-id",
getId: (x) => x.id,
getParentId: (x) => x.parentId,
});
composite = getComposite(items);
});
it("has a child as descendant", () => {
const actual = compositeHasDescendant<typeof composite["value"]>(
(referenceComposite) => referenceComposite.value.id === "some-child-item",
)(composite);
expect(actual).toBe(true);
});
it("has a grand child as descendant", () => {
const actual = compositeHasDescendant<typeof composite["value"]>(
(referenceComposite) =>
referenceComposite.value.id === "some-grand-child-item",
)(composite);
expect(actual).toBe(true);
});
it("does not have an unrelated descendant", () => {
const actual = compositeHasDescendant<typeof composite["value"]>(
(referenceComposite) =>
referenceComposite.value.id === "some-unknown-item",
)(composite);
expect(actual).toBe(false);
});
});
@@ -0,0 +1,19 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { Composite } from "../get-composite/get-composite";
const compositeHasDescendant = <T>(
predicate: (referenceComposite: Composite<T>) => boolean,
) => {
const _compositeHasDescendant = (composite: Composite<T>): boolean =>
predicate(composite) ||
!!composite.children.find((childComposite) =>
_compositeHasDescendant(childComposite),
);
return _compositeHasDescendant;
};
export { compositeHasDescendant };
@@ -0,0 +1,91 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { Composite } from "../get-composite/get-composite";
import { findComposite } from "./find-composite";
import { getCompositeFor } from "../get-composite/get-composite";
describe("find-composite", () => {
let composite: Composite<{ id: string; parentId?: string }>;
beforeEach(() => {
const getComposite = getCompositeFor<{
id: string;
parentId?: string;
}>({
rootId: "some-root-id",
getId: (x) => x.id,
getParentId: (x) => x.parentId,
});
composite = getComposite([
{ id: "some-root-id" },
{ id: "some-child-id", parentId: "some-root-id" },
{ id: "some-grandchild-id", parentId: "some-child-id" },
{ id: "some-other-grandchild-id", parentId: "some-child-id" },
]);
});
it("when finding root using path, does so", () => {
const actual = findComposite("some-root-id")(composite);
expect(actual.id).toBe("some-root-id");
});
it("when finding child using path, does so", () => {
const actual = findComposite("some-root-id", "some-child-id")(composite);
expect(actual.id).toBe("some-child-id");
});
it("when finding grandchild using path, does so", () => {
const actual = findComposite(
"some-root-id",
"some-child-id",
"some-grandchild-id",
)(composite);
expect(actual.id).toBe("some-grandchild-id");
});
it("when finding with non existing leaf-level path, throws", () => {
expect(() => {
findComposite(
"some-root-id",
"some-child-id",
"some-non-existing-grandchild-id",
)(composite);
}).toThrow(`Tried to find 'some-root-id -> some-child-id -> some-non-existing-grandchild-id' from a composite, but found nothing.
Node 'some-root-id -> some-child-id' had only following children:
some-grandchild-id
some-other-grandchild-id`);
});
it("when finding with non-existing mid-level path, throws", () => {
expect(() => {
findComposite(
"some-root-id",
"some-non-existing-child-id",
"some-non-existing-grandchild-id",
)(composite);
}).toThrow(`Tried to find 'some-root-id -> some-non-existing-child-id -> some-non-existing-grandchild-id' from a composite, but found nothing.
Node 'some-root-id' had only following children:
some-child-id`);
});
it("when finding with non-existing root-level path, throws", () => {
expect(() => {
findComposite(
"some-non-existing-root-id",
"some-non-existing-child-id",
"some-non-existing-grandchild-id",
)(composite);
}).toThrow(`Tried to find 'some-non-existing-root-id -> some-non-existing-child-id -> some-non-existing-grandchild-id' from a composite, but found nothing.
Node 'some-root-id' had only following children:
some-child-id`);
});
});
@@ -0,0 +1,36 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { Composite } from "../get-composite/get-composite";
const _findComposite = <T>(currentLeftIds: string[], currentId: string, currentRightIds: string[], composite: Composite<T>): Composite<T> => {
const [nextId, ...nextRightIds] = currentRightIds;
const nextLeftIds = [...currentLeftIds, currentId];
if (currentRightIds.length === 0 && composite.id === currentId) {
return composite;
}
const foundChildComposite = composite.children.find((child) => child.id === nextId);
if (foundChildComposite) {
return _findComposite(nextLeftIds, nextId, nextRightIds, foundChildComposite);
}
const fullPathString = [...currentLeftIds, currentId, ...currentRightIds].join(" -> ");
throw new Error(`Tried to find '${fullPathString}' from a composite, but found nothing.
Node '${[...currentLeftIds, composite.id].join(" -> ")}' had only following children:
${composite.children.map((child) => child.id).join("\n")}`);
};
export const findComposite =
(...path: string[]) =>
<T>(composite: Composite<T>): Composite<T> => {
const [currentId, ...rightIds] = path;
const leftIds: string[] = [];
return _findComposite(leftIds, currentId, rightIds, composite);
};
@@ -0,0 +1,53 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getCompositeNormalization } from "./get-composite-normalization";
import { getCompositeFor } from "../get-composite/get-composite";
describe("get-composite-normalization", () => {
it("given a composite, flattens it to paths and composites", () => {
const someRootItem = {
id: "some-root-id",
parentId: undefined,
};
const someItem = {
id: "some-id",
parentId: "some-root-id",
};
const someNestedItem = {
id: "some-child-id",
parentId: "some-id",
};
const items = [someRootItem, someItem, someNestedItem];
const getComposite = getCompositeFor<{
id: string;
parentId?: string;
orderNumber?: number;
}>({
rootId: "some-root-id",
getId: (x) => x.id,
getParentId: (x) => x.parentId,
});
const composite = getComposite(items);
const actual = getCompositeNormalization(composite);
expect(actual).toEqual([
[["some-root-id"], expect.objectContaining({ value: someRootItem })],
[["some-root-id", "some-id"], expect.objectContaining({ value: someItem })],
[
["some-root-id", "some-id", "some-child-id"],
expect.objectContaining({ value: someNestedItem }),
],
]);
});
});
@@ -0,0 +1,26 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { Composite } from "../get-composite/get-composite";
export const getCompositeNormalization = <T>(composite: Composite<T>) => {
const _normalizeComposite = <T>(
composite: Composite<T>,
previousPath: string[] = [],
): (readonly [path: string[], composite: Composite<T>])[] => {
const currentPath = [...previousPath, composite.id];
const pathAndCompositeTuple = [currentPath, composite] as const;
return [
pathAndCompositeTuple,
...composite.children.flatMap((child) =>
_normalizeComposite(child, currentPath),
),
];
};
return _normalizeComposite(composite);
};
@@ -0,0 +1,71 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getCompositePaths } from "./get-composite-paths";
import { sortBy } from "lodash/fp";
import { getCompositeFor } from "../get-composite/get-composite";
describe("get-composite-paths", () => {
it("given composite with transformed children, returns paths of transformed children in hierarchical order", () => {
const someRootItem = {
id: "some-root-id",
};
const someChildItem1 = {
id: "some-child-id-1",
parentId: "some-root-id",
orderNumber: 1,
};
const someChildItem2 = {
id: "some-child-id-2",
parentId: "some-root-id",
orderNumber: 2,
};
const someGrandchildItem1 = {
id: "some-grandchild-id-1",
parentId: "some-child-id-1",
orderNumber: 1,
};
const someGrandchildItem2 = {
id: "some-grandchild-id-2",
parentId: "some-child-id-1",
orderNumber: 2,
};
const items = [
someRootItem,
// Note: not in order yet.
someChildItem2,
someChildItem1,
someGrandchildItem2,
someGrandchildItem1,
];
const getComposite = getCompositeFor<{
id: string;
parentId?: string;
orderNumber?: number;
}>({
rootId: "some-root-id",
getId: (x) => x.id,
getParentId: (x) => x.parentId,
transformChildren: children => sortBy(child => child.orderNumber, children),
});
const composite = getComposite(items);
const actual = getCompositePaths(composite);
expect(actual).toEqual([
["some-root-id"],
["some-root-id", "some-child-id-1"],
["some-root-id", "some-child-id-1", "some-grandchild-id-1"],
["some-root-id", "some-child-id-1", "some-grandchild-id-2"],
["some-root-id", "some-child-id-2"],
]);
});
});
@@ -0,0 +1,12 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { pipeline } from "@ogre-tools/fp";
import { map } from "lodash/fp";
import type { Composite } from "../get-composite/get-composite";
import { getCompositeNormalization } from "../get-composite-normalization/get-composite-normalization";
export const getCompositePaths = (
composite: Composite<unknown>,
): string[][] => pipeline(composite, getCompositeNormalization, map(([path]) => path));
@@ -0,0 +1,363 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { Composite } from "./get-composite";
import { getCompositePaths } from "../get-composite-paths/get-composite-paths";
import { sortBy } from "lodash/fp";
import { getCompositeFor } from "./get-composite";
interface SomeItem {
id: string;
parentId?: string;
orderNumber?: number;
}
describe("get-composite", () => {
it("given items and an explicit root id, creates a composite", () => {
const someRootItem = {
id: "some-root-id",
someProperty: "some-root-content",
};
const someIrrelevantRootItem = {
id: "some-irrelevant-root-id",
someProperty: "some-other-root-content",
};
const someItem = {
id: "some-id",
parentId: "some-root-id",
someProperty: "some-content",
};
const someNestedItem = {
id: "some-nested-id",
parentId: "some-id",
someProperty: "some-nested-content",
};
const items = [someRootItem, someIrrelevantRootItem, someItem, someNestedItem];
const getComposite = getCompositeFor<SomeItem>({
rootId: "some-root-id",
getId: (x) => x.id,
getParentId: (x) => x.parentId,
});
const composite = getComposite(items);
expect(composite).toEqual({
id: "some-root-id",
value: someRootItem,
children: [
{
id: "some-id",
parentId: "some-root-id",
value: someItem,
children: [
{
id: "some-nested-id",
parentId: "some-id",
value: someNestedItem,
children: [],
},
],
},
],
});
});
it("given items and implicit root, creates a composite", () => {
const someRootItem = {
id: "some-root-id",
someProperty: "some-root-content",
// Notice: no "parentId" makes this the implicit root.
parentId: undefined,
};
const someItem = {
id: "some-id",
parentId: "some-root-id",
someProperty: "some-content",
};
const someNestedItem = {
id: "some-nested-id",
parentId: "some-id",
someProperty: "some-nested-content",
};
const items = [someRootItem, someItem, someNestedItem];
const getComposite = getCompositeFor<SomeItem>({
// Notice: no root id
// rootId: "some-root-id",
getId: (x) => x.id,
getParentId: (x) => x.parentId,
});
const composite = getComposite(items);
expect(composite).toEqual({
id: "some-root-id",
value: someRootItem,
children: [
{
id: "some-id",
parentId: "some-root-id",
value: someItem,
children: [
{
id: "some-nested-id",
parentId: "some-id",
value: someNestedItem,
children: [],
},
],
},
],
});
});
it("given items and an unspecified root id and multiple items without parent as root, throws", () => {
const someRootItem = {
id: "some-root-id",
// Notice: no "parentId" makes this a root.
parentId: undefined,
};
const someOtherRootItem = {
id: "some-other-root-id",
// Notice: no "parentId" makes also this a root.
parentId: undefined,
};
const items = [someRootItem, someOtherRootItem];
const getComposite = getCompositeFor<SomeItem>({
getId: (x) => x.id,
getParentId: (x) => x.parentId,
});
expect(() => {
getComposite(items);
}).toThrow(
'Tried to get a composite, but multiple roots where encountered: "some-root-id", "some-other-root-id"',
);
});
it("given non-unique ids, throws", () => {
const someItem = {
id: "some-id",
parentId: "irrelevant",
};
const someOtherItem = {
id: "some-id",
parentId: "irrelevant",
};
const items = [someItem, someOtherItem];
const getComposite = getCompositeFor<SomeItem>({
getId: (x) => x.id,
getParentId: (x) => x.parentId,
});
expect(() => {
getComposite(items);
}).toThrow(
'Tried to get a composite but encountered non-unique ids: "some-id"',
);
});
it("given items with missing parent ids, when creating composite without handling for unknown parents, throws", () => {
const someItem = {
id: "some-id",
parentId: undefined,
};
const someItemWithMissingParentId = {
id: "some-other-id",
parentId: "some-missing-id",
};
const items = [someItem, someItemWithMissingParentId];
const getComposite = getCompositeFor<SomeItem>({
getId: (x) => x.id,
getParentId: (x) => x.parentId,
});
expect(() => {
getComposite(items);
}).toThrow(
`Tried to get a composite but encountered missing parent ids: "some-missing-id".
Available parent ids are:
"some-id",
"some-other-id"`,
);
});
describe("given items with missing parents, when creating composite with handling for missing parents", () => {
let composite: Composite<any>;
let handleMissingParentIdMock: jest.Mock;
beforeEach(() => {
const someItem = {
id: "some-root-id",
};
const someItemWithMissingParentId = {
id: "some-orphan-id",
// Note: the item corresponding to this id does not exist,
// making this item have a "missing parent".
parentId: "some-missing-id",
};
const items = [someItem, someItemWithMissingParentId];
handleMissingParentIdMock = jest.fn();
const getComposite = getCompositeFor<SomeItem>({
getId: (x) => x.id,
getParentId: (x) => x.parentId,
handleMissingParentIds: handleMissingParentIdMock,
});
composite = getComposite(items);
});
it("creates composite without the orphan item, and without throwing", () => {
const paths = getCompositePaths(composite);
expect(paths).toEqual([["some-root-id"]]);
});
it("handles the missing parent ids", () => {
expect(handleMissingParentIdMock).toHaveBeenCalledWith({
missingParentIds: ["some-missing-id"],
availableParentIds: ["some-root-id", "some-orphan-id"],
});
});
});
it("given items with same id and parent id, throws", () => {
const someItem = {
id: "some-id",
parentId: "some-id",
};
const someRoot = {
id: "root",
parentId: undefined,
};
const items = [someItem, someRoot];
const getComposite = getCompositeFor<SomeItem>({
getId: (x) => x.id,
getParentId: (x) => x.parentId,
});
expect(() => {
getComposite(items);
}).toThrow(
'Tried to get a composite, but found items with self as parent: "some-id"',
);
});
it("given undefined ids, throws", () => {
const root = {
parentId: undefined,
id: "some-root",
};
const someItem = {
parentId: "some-root",
id: undefined,
};
const someOtherItem = {
parentId: "some-root",
id: undefined,
};
const items = [root, someItem, someOtherItem];
const getComposite = getCompositeFor<any>({
getId: (x) => x.id,
getParentId: (x) => x.parentId,
});
expect(() => {
getComposite(items);
}).toThrow("Tried to get a composite but encountered 2 undefined ids");
});
it("given transformed children, creates a composite with transformed children", () => {
const someRootItem = {
id: "some-root-id",
orderNumber: 1,
};
const someItem1 = {
id: "some-id-1",
parentId: "some-root-id",
orderNumber: 1,
};
const someItem2 = {
id: "some-id-2",
parentId: "some-root-id",
orderNumber: 2,
};
const someChildItem1 = {
id: "some-child-id-1",
parentId: "some-id-1",
orderNumber: 1,
};
const someChildItem2 = {
id: "some-child-id-2",
parentId: "some-id-1",
orderNumber: 2,
};
const items = [
someRootItem,
// Note: not in order yet.
someItem2,
someItem1,
someChildItem2,
someChildItem1,
];
const getComposite = getCompositeFor<SomeItem>({
getId: (x) => x.id,
getParentId: (x) => x.parentId,
transformChildren: (things) =>
sortBy((thing) => thing.orderNumber, things),
});
const composite = getComposite(items);
const orderedPaths = getCompositePaths(composite);
expect(orderedPaths).toEqual([
["some-root-id"],
["some-root-id", "some-id-1"],
["some-root-id", "some-id-1", "some-child-id-1"],
["some-root-id", "some-id-1", "some-child-id-2"],
["some-root-id", "some-id-2"],
]);
});
});
@@ -0,0 +1,147 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { pipeline } from "@ogre-tools/fp";
import {
countBy,
filter,
toPairs,
nth,
map,
uniq,
without,
compact,
identity,
} from "lodash/fp";
export interface Composite<T> {
id: string;
parentId: string | undefined;
value: T;
children: Composite<T>[];
}
interface Configuration<T> {
rootId?: string;
getId: (thing: T) => string;
getParentId: (thing: T) => string | undefined;
transformChildren?: (things: T[]) => T[];
handleMissingParentIds?: (parentIdsForHandling: ParentIdsForHandling) => void;
}
export const getCompositeFor = <T>({
rootId = undefined,
getId,
getParentId,
transformChildren = identity,
handleMissingParentIds = throwMissingParentIds,
}: Configuration<T>) => (source: T[]) => {
const undefinedIds = pipeline(
source,
filter((x) => getId(x) === undefined),
);
if (undefinedIds.length) {
throw new Error(
`Tried to get a composite but encountered ${undefinedIds.length} undefined ids`,
);
}
const selfReferencingIds = pipeline(
source,
filter((x) => getId(x) === getParentId(x)),
map(getId),
);
if (selfReferencingIds.length) {
throw new Error(
`Tried to get a composite, but found items with self as parent: "${selfReferencingIds.join(
'", ',
)}"`,
);
}
const duplicateIds = pipeline(
source,
countBy(getId),
toPairs,
filter(([, count]) => count > 1),
map(nth(0)),
);
if (duplicateIds.length) {
throw new Error(
`Tried to get a composite but encountered non-unique ids: "${duplicateIds
.map((x) => String(x))
.join('", "')}"`,
);
}
const allIds = pipeline(source, map(getId));
const allParentIds = pipeline(source, map(getParentId), uniq, compact);
const missingParentIds = without(allIds, allParentIds);
if (missingParentIds.length) {
handleMissingParentIds({ missingParentIds, availableParentIds: allIds });
}
const toComposite = (thing: T): Composite<T> => {
const thingId = getId(thing);
return {
id: thingId,
parentId: getParentId(thing),
value: thing,
children: pipeline(
source,
filter((childThing) => {
const parentId = getParentId(childThing);
return parentId === thingId;
}),
transformChildren,
map(toComposite),
),
};
};
const isRootId = rootId
? (thing: T) => getId(thing) === rootId
: (thing: T) => getParentId(thing) === undefined;
const roots = source.filter(isRootId);
if (roots.length > 1) {
throw new Error(
`Tried to get a composite, but multiple roots where encountered: "${roots
.map(getId)
.join('", "')}"`,
);
}
return toComposite(roots[0]);
};
interface ParentIdsForHandling {
missingParentIds: string[];
availableParentIds: string[];
}
const throwMissingParentIds = ({
missingParentIds,
availableParentIds,
}: ParentIdsForHandling) => {
throw new Error(
`Tried to get a composite but encountered missing parent ids: "${missingParentIds.join(
'", "',
)}".\n\nAvailable parent ids are:\n"${availableParentIds.join('",\n"')}"`,
);
};
@@ -0,0 +1,16 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
export interface ParentOfChildComposite<Id extends string = string> {
id: Id;
}
export interface ChildOfParentComposite<ParentId extends string = string> {
parentId: ParentId;
}
export type RootComposite<Id extends string = string> =
& { parentId: undefined }
& ParentOfChildComposite<Id>;