mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Release 6.4.0 (#7250)
* General fixes for release-tool (#7238)
* General fixes for release-tool
Signed-off-by: Sebastian Malton <sebastian@malton.name>
* Revert change to number of PRs retrieved
Signed-off-by: Sebastian Malton <sebastian@malton.name>
---------
Signed-off-by: Sebastian Malton <sebastian@malton.name>
* Throw on errors in kubectlApplyFolder (#7239)
Signed-off-by: Panu Horsmalahti <phorsmalahti@mirantis.com>
* Quick fix for store migration version being wrong (#7243)
Signed-off-by: Sebastian Malton <sebastian@malton.name>
* Revert "Renderer file logging transport (#6795)" (#7245)
Renderer file logging still caused UI freezing (at least on apple silicon macs) when cluster frame was open and main frame was reloaded.
See #544
This reverts commit ac2d0e46ff.
Signed-off-by: Sami Tiilikainen <97873007+samitiilikainen@users.noreply.github.com>
* Fix extension install (#7247)
* Fix extension install
- Remove old bundled extension dependencies
- Make sure external extensions are installed as optional
Signed-off-by: Sebastian Malton <sebastian@malton.name>
* Ignore ENOENT errors
Signed-off-by: Sebastian Malton <sebastian@malton.name>
* Add comment
Signed-off-by: Sebastian Malton <sebastian@malton.name>
---------
Signed-off-by: Sebastian Malton <sebastian@malton.name>
* Release 6.4.0
Signed-off-by: Sebastian Malton <sebastian@malton.name>
* Fix lint
Signed-off-by: Sebastian Malton <sebastian@malton.name>
---------
Signed-off-by: Sebastian Malton <sebastian@malton.name>
Signed-off-by: Panu Horsmalahti <phorsmalahti@mirantis.com>
Signed-off-by: Sami Tiilikainen <97873007+samitiilikainen@users.noreply.github.com>
Co-authored-by: Panu Horsmalahti <phorsmalahti@mirantis.com>
Co-authored-by: Sami Tiilikainen <97873007+samitiilikainen@users.noreply.github.com>
This commit is contained in:
parent
b74cc14b72
commit
5ac90e9178
@ -4,7 +4,7 @@
|
|||||||
"packages": [
|
"packages": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
],
|
],
|
||||||
"version": "6.4.0-beta.17",
|
"version": "6.4.0",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"npmClientArgs": [
|
"npmClientArgs": [
|
||||||
"--network-timeout=100000"
|
"--network-timeout=100000"
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
"productName": "",
|
"productName": "",
|
||||||
"description": "Lens Desktop Core",
|
"description": "Lens Desktop Core",
|
||||||
"homepage": "https://github.com/lensapp/lens",
|
"homepage": "https://github.com/lensapp/lens",
|
||||||
"version": "6.4.0-beta.17",
|
"version": "6.4.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/lensapp/lens.git"
|
"url": "git+https://github.com/lensapp/lens.git"
|
||||||
|
|||||||
@ -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 { DiContainer } from "@ogre-tools/injectable";
|
||||||
|
import kubectlApplyAllInjectable from "../../main/kubectl/kubectl-apply-all.injectable";
|
||||||
|
import { getDiForUnitTesting } from "../../main/getDiForUnitTesting";
|
||||||
|
import type { KubernetesCluster } from "../catalog-entities";
|
||||||
|
import readDirectoryInjectable from "../fs/read-directory.injectable";
|
||||||
|
import readFileInjectable from "../fs/read-file.injectable";
|
||||||
|
import createResourceStackInjectable from "../k8s/create-resource-stack.injectable";
|
||||||
|
import appPathsStateInjectable from "../app-paths/app-paths-state.injectable";
|
||||||
|
import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||||
|
|
||||||
|
describe("create resource stack tests", () => {
|
||||||
|
let di: DiContainer;
|
||||||
|
let cluster: KubernetesCluster;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||||
|
cluster = {
|
||||||
|
getId: () => "test-cluster",
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
di.override(readDirectoryInjectable, () => () => Promise.resolve(["file1"]) as any);
|
||||||
|
di.override(readFileInjectable, () => () => Promise.resolve("filecontents"));
|
||||||
|
di.override(appPathsStateInjectable, () => ({
|
||||||
|
get: () => ({}),
|
||||||
|
}));
|
||||||
|
di.override(directoryForUserDataInjectable, () => "/some-directory-for-user-data");
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("kubectlApplyFolder", () => {
|
||||||
|
it("returns response", async () => {
|
||||||
|
di.override(kubectlApplyAllInjectable, () => () => Promise.resolve({
|
||||||
|
callWasSuccessful: true as const,
|
||||||
|
response: "success",
|
||||||
|
}));
|
||||||
|
|
||||||
|
const createResourceStack = di.inject(createResourceStackInjectable);
|
||||||
|
const resourceStack = createResourceStack(cluster, "test");
|
||||||
|
|
||||||
|
const response = await resourceStack.kubectlApplyFolder("/foo/bar");
|
||||||
|
|
||||||
|
expect(response).toEqual("success");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throws on error", async () => {
|
||||||
|
di.override(kubectlApplyAllInjectable, () => () => Promise.resolve({
|
||||||
|
callWasSuccessful: false as const,
|
||||||
|
error: "No permissions",
|
||||||
|
}));
|
||||||
|
|
||||||
|
const createResourceStack = di.inject(createResourceStackInjectable);
|
||||||
|
const resourceStack = createResourceStack(cluster, "test");
|
||||||
|
|
||||||
|
await expect(() => resourceStack.kubectlApplyFolder("/foo/bar")).rejects.toThrow("No permissions");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -7,7 +7,7 @@ import type { ReadOptions } from "fs-extra";
|
|||||||
import fse 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({
|
const fsInjectable = getInjectable({
|
||||||
id: "fs",
|
id: "fs",
|
||||||
|
|||||||
@ -51,7 +51,7 @@ export class ResourceStack {
|
|||||||
|
|
||||||
this.dependencies.logger.warn(`[RESOURCE-STACK]: failed to apply resources: ${result.error}`);
|
this.dependencies.logger.warn(`[RESOURCE-STACK]: failed to apply resources: ${result.error}`);
|
||||||
|
|
||||||
return "";
|
throw new Error(result.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -3,13 +3,20 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
|
import { createLogger, format } from "winston";
|
||||||
import type { Logger } from "./logger";
|
import type { Logger } from "./logger";
|
||||||
import winstonLoggerInjectable from "./winston-logger.injectable";
|
import { loggerTransportInjectionToken } from "./logger/transports";
|
||||||
|
|
||||||
const loggerInjectable = getInjectable({
|
const loggerInjectable = getInjectable({
|
||||||
id: "logger",
|
id: "logger",
|
||||||
instantiate: (di): Logger => {
|
instantiate: (di): Logger => {
|
||||||
const baseLogger = di.inject(winstonLoggerInjectable);
|
const baseLogger = createLogger({
|
||||||
|
format: format.combine(
|
||||||
|
format.splat(),
|
||||||
|
format.simple(),
|
||||||
|
),
|
||||||
|
transports: di.injectMany(loggerTransportInjectionToken),
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
debug: (message, ...data) => baseLogger.debug(message, ...data),
|
debug: (message, ...data) => baseLogger.debug(message, ...data),
|
||||||
|
|||||||
@ -3,11 +3,10 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
import { getInjectable } from "@ogre-tools/injectable";
|
||||||
import { applicationInformationToken } from "./application-information-token";
|
|
||||||
|
|
||||||
const storeMigrationVersionInjectable = getInjectable({
|
const storeMigrationVersionInjectable = getInjectable({
|
||||||
id: "store-migration-version",
|
id: "store-migration-version",
|
||||||
instantiate: (di) => di.inject(applicationInformationToken).version,
|
instantiate: () => "6.4.0",
|
||||||
});
|
});
|
||||||
|
|
||||||
export default storeMigrationVersionInjectable;
|
export default storeMigrationVersionInjectable;
|
||||||
|
|||||||
@ -1,20 +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 { createLogger, format } from "winston";
|
|
||||||
import { loggerTransportInjectionToken } from "./logger/transports";
|
|
||||||
|
|
||||||
const winstonLoggerInjectable = getInjectable({
|
|
||||||
id: "winston-logger",
|
|
||||||
instantiate: (di) => createLogger({
|
|
||||||
format: format.combine(
|
|
||||||
format.splat(),
|
|
||||||
format.simple(),
|
|
||||||
),
|
|
||||||
transports: di.injectMany(loggerTransportInjectionToken),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
export default winstonLoggerInjectable;
|
|
||||||
@ -8,8 +8,8 @@ import extensionLoaderInjectable from "../extension-loader/extension-loader.inje
|
|||||||
import isCompatibleExtensionInjectable from "./is-compatible-extension/is-compatible-extension.injectable";
|
import isCompatibleExtensionInjectable from "./is-compatible-extension/is-compatible-extension.injectable";
|
||||||
import extensionsStoreInjectable from "../extensions-store/extensions-store.injectable";
|
import extensionsStoreInjectable from "../extensions-store/extensions-store.injectable";
|
||||||
import extensionInstallationStateStoreInjectable from "../extension-installation-state-store/extension-installation-state-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 installExtensionInjectable from "../install-extension/install-extension.injectable";
|
||||||
import extensionPackageRootDirectoryInjectable from "../extension-installer/extension-package-root-directory/extension-package-root-directory.injectable";
|
import extensionPackageRootDirectoryInjectable from "../install-extension/extension-package-root-directory.injectable";
|
||||||
import readJsonFileInjectable from "../../common/fs/read-json-file.injectable";
|
import readJsonFileInjectable from "../../common/fs/read-json-file.injectable";
|
||||||
import loggerInjectable from "../../common/logger.injectable";
|
import loggerInjectable from "../../common/logger.injectable";
|
||||||
import pathExistsInjectable from "../../common/fs/path-exists.injectable";
|
import pathExistsInjectable from "../../common/fs/path-exists.injectable";
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import type { FSWatcher } from "chokidar";
|
|||||||
import { getDiForUnitTesting } from "../../main/getDiForUnitTesting";
|
import { getDiForUnitTesting } from "../../main/getDiForUnitTesting";
|
||||||
import extensionDiscoveryInjectable from "../extension-discovery/extension-discovery.injectable";
|
import extensionDiscoveryInjectable from "../extension-discovery/extension-discovery.injectable";
|
||||||
import type { ExtensionDiscovery } from "../extension-discovery/extension-discovery";
|
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 directoryForUserDataInjectable from "../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||||
import { delay } from "../../renderer/utils";
|
import { delay } from "../../renderer/utils";
|
||||||
import { observable, runInAction, when } from "mobx";
|
import { observable, runInAction, when } from "mobx";
|
||||||
|
|||||||
@ -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;
|
|
||||||
@ -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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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;
|
|
||||||
@ -3,7 +3,7 @@
|
|||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
import { getInjectable } from "@ogre-tools/injectable";
|
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({
|
const extensionPackageRootDirectoryInjectable = getInjectable({
|
||||||
id: "extension-package-root-directory",
|
id: "extension-package-root-directory",
|
||||||
@ -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;
|
||||||
@ -46,9 +46,7 @@ export async function bootstrap(di: DiContainer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await initializeApp(() => {
|
await initializeApp(() => unmountComponentAtNode(rootElem));
|
||||||
unmountComponentAtNode(rootElem);
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`[BOOTSTRAP]: view initialization error: ${error}`, {
|
console.error(`[BOOTSTRAP]: view initialization error: ${error}`, {
|
||||||
origin: location.href,
|
origin: location.href,
|
||||||
|
|||||||
@ -12,7 +12,6 @@ import emitAppEventInjectable from "../../../../common/app-event-bus/emit-event.
|
|||||||
import loadExtensionsInjectable from "../../load-extensions.injectable";
|
import loadExtensionsInjectable from "../../load-extensions.injectable";
|
||||||
import loggerInjectable from "../../../../common/logger.injectable";
|
import loggerInjectable from "../../../../common/logger.injectable";
|
||||||
import showErrorNotificationInjectable from "../../../components/notifications/show-error-notification.injectable";
|
import showErrorNotificationInjectable from "../../../components/notifications/show-error-notification.injectable";
|
||||||
import closeRendererLogFileInjectable from "../../../logger/close-renderer-log-file.injectable";
|
|
||||||
|
|
||||||
const initClusterFrameInjectable = getInjectable({
|
const initClusterFrameInjectable = getInjectable({
|
||||||
id: "init-cluster-frame",
|
id: "init-cluster-frame",
|
||||||
@ -30,7 +29,6 @@ const initClusterFrameInjectable = getInjectable({
|
|||||||
emitAppEvent: di.inject(emitAppEventInjectable),
|
emitAppEvent: di.inject(emitAppEventInjectable),
|
||||||
logger: di.inject(loggerInjectable),
|
logger: di.inject(loggerInjectable),
|
||||||
showErrorNotification: di.inject(showErrorNotificationInjectable),
|
showErrorNotification: di.inject(showErrorNotificationInjectable),
|
||||||
closeFileLogging: di.inject(closeRendererLogFileInjectable),
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||||
*/
|
*/
|
||||||
import { once } from "lodash";
|
|
||||||
import type { Cluster } from "../../../../common/cluster/cluster";
|
import type { Cluster } from "../../../../common/cluster/cluster";
|
||||||
import type { CatalogEntityRegistry } from "../../../api/catalog/entity/registry";
|
import type { CatalogEntityRegistry } from "../../../api/catalog/entity/registry";
|
||||||
import type { ShowNotification } from "../../../components/notifications";
|
import type { ShowNotification } from "../../../components/notifications";
|
||||||
@ -19,7 +18,6 @@ interface Dependencies {
|
|||||||
emitAppEvent: EmitAppEvent;
|
emitAppEvent: EmitAppEvent;
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
showErrorNotification: ShowNotification;
|
showErrorNotification: ShowNotification;
|
||||||
closeFileLogging: () => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const logPrefix = "[CLUSTER-FRAME]:";
|
const logPrefix = "[CLUSTER-FRAME]:";
|
||||||
@ -32,7 +30,6 @@ export const initClusterFrame = ({
|
|||||||
emitAppEvent,
|
emitAppEvent,
|
||||||
logger,
|
logger,
|
||||||
showErrorNotification,
|
showErrorNotification,
|
||||||
closeFileLogging,
|
|
||||||
}: Dependencies) =>
|
}: Dependencies) =>
|
||||||
async (unmountRoot: () => void) => {
|
async (unmountRoot: () => void) => {
|
||||||
// TODO: Make catalogEntityRegistry already initialized when passed as dependency
|
// TODO: Make catalogEntityRegistry already initialized when passed as dependency
|
||||||
@ -76,14 +73,11 @@ export const initClusterFrame = ({
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const onCloseFrame = once(() => {
|
window.onbeforeunload = () => {
|
||||||
logger.info(
|
logger.info(
|
||||||
`${logPrefix} Unload dashboard, clusterId=${(hostedCluster.id)}, frameId=${frameRoutingId}`,
|
`${logPrefix} Unload dashboard, clusterId=${(hostedCluster.id)}, frameId=${frameRoutingId}`,
|
||||||
);
|
);
|
||||||
closeFileLogging();
|
|
||||||
unmountRoot();
|
|
||||||
});
|
|
||||||
|
|
||||||
window.addEventListener("beforeunload", onCloseFrame);
|
unmountRoot();
|
||||||
window.addEventListener("pagehide", onCloseFrame);
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -13,7 +13,6 @@ import loggerInjectable from "../../../common/logger.injectable";
|
|||||||
import { delay } from "../../../common/utils";
|
import { delay } from "../../../common/utils";
|
||||||
import { broadcastMessage } from "../../../common/ipc";
|
import { broadcastMessage } from "../../../common/ipc";
|
||||||
import { bundledExtensionsLoaded } from "../../../common/ipc/extension-handling";
|
import { bundledExtensionsLoaded } from "../../../common/ipc/extension-handling";
|
||||||
import closeRendererLogFileInjectable from "../../logger/close-renderer-log-file.injectable";
|
|
||||||
|
|
||||||
const initRootFrameInjectable = getInjectable({
|
const initRootFrameInjectable = getInjectable({
|
||||||
id: "init-root-frame",
|
id: "init-root-frame",
|
||||||
@ -25,7 +24,6 @@ const initRootFrameInjectable = getInjectable({
|
|||||||
const lensProtocolRouterRenderer = di.inject(lensProtocolRouterRendererInjectable);
|
const lensProtocolRouterRenderer = di.inject(lensProtocolRouterRendererInjectable);
|
||||||
const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable);
|
const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable);
|
||||||
const logger = di.inject(loggerInjectable);
|
const logger = di.inject(loggerInjectable);
|
||||||
const closeRendererLogFile = di.inject(closeRendererLogFileInjectable);
|
|
||||||
|
|
||||||
return async (unmountRoot: () => void) => {
|
return async (unmountRoot: () => void) => {
|
||||||
catalogEntityRegistry.init();
|
catalogEntityRegistry.init();
|
||||||
@ -61,7 +59,7 @@ const initRootFrameInjectable = getInjectable({
|
|||||||
|
|
||||||
window.addEventListener("beforeunload", () => {
|
window.addEventListener("beforeunload", () => {
|
||||||
logger.info("[ROOT-FRAME]: Unload app");
|
logger.info("[ROOT-FRAME]: Unload app");
|
||||||
closeRendererLogFile();
|
|
||||||
unmountRoot();
|
unmountRoot();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,22 +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 winstonLoggerInjectable from "../../common/winston-logger.injectable";
|
|
||||||
import rendererFileLoggerTransportInjectable from "./file-transport.injectable";
|
|
||||||
|
|
||||||
const closeRendererLogFileInjectable = getInjectable({
|
|
||||||
id: "close-renderer-log-file",
|
|
||||||
instantiate: (di) => {
|
|
||||||
const winstonLogger = di.inject(winstonLoggerInjectable);
|
|
||||||
const fileLoggingTransport = di.inject(rendererFileLoggerTransportInjectable);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
fileLoggingTransport.close?.();
|
|
||||||
winstonLogger.remove(fileLoggingTransport);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default closeRendererLogFileInjectable;
|
|
||||||
@ -1,44 +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 { transports } from "winston";
|
|
||||||
import directoryForLogsInjectable from "../../common/app-paths/directory-for-logs.injectable";
|
|
||||||
import { loggerTransportInjectionToken } from "../../common/logger/transports";
|
|
||||||
import windowLocationInjectable from "../../common/k8s-api/window-location.injectable";
|
|
||||||
import currentlyInClusterFrameInjectable from "../routes/currently-in-cluster-frame.injectable";
|
|
||||||
import { getClusterIdFromHost } from "../utils";
|
|
||||||
|
|
||||||
const rendererFileLoggerTransportInjectable = getInjectable({
|
|
||||||
id: "renderer-file-logger-transport",
|
|
||||||
instantiate: (di) => {
|
|
||||||
let frameId: string;
|
|
||||||
|
|
||||||
const currentlyInClusterFrame = di.inject(
|
|
||||||
currentlyInClusterFrameInjectable,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (currentlyInClusterFrame) {
|
|
||||||
const { host } = di.inject(windowLocationInjectable);
|
|
||||||
const clusterId = getClusterIdFromHost(host);
|
|
||||||
|
|
||||||
frameId = clusterId ? `cluster-${clusterId}` : "cluster";
|
|
||||||
} else {
|
|
||||||
frameId = "main";
|
|
||||||
}
|
|
||||||
|
|
||||||
return new transports.File({
|
|
||||||
handleExceptions: false,
|
|
||||||
level: "info",
|
|
||||||
filename: `lens-renderer-${frameId}.log`,
|
|
||||||
dirname: di.inject(directoryForLogsInjectable),
|
|
||||||
maxsize: 1024 * 1024,
|
|
||||||
maxFiles: 2,
|
|
||||||
tailable: true,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
injectionToken: loggerTransportInjectionToken,
|
|
||||||
});
|
|
||||||
|
|
||||||
export default rendererFileLoggerTransportInjectable;
|
|
||||||
@ -2,7 +2,7 @@
|
|||||||
"name": "@k8slens/extensions",
|
"name": "@k8slens/extensions",
|
||||||
"productName": "OpenLens extensions",
|
"productName": "OpenLens extensions",
|
||||||
"description": "OpenLens - Open Source Kubernetes IDE: extensions",
|
"description": "OpenLens - Open Source Kubernetes IDE: extensions",
|
||||||
"version": "6.4.0-beta.17",
|
"version": "6.4.0",
|
||||||
"copyright": "© 2022 OpenLens Authors",
|
"copyright": "© 2022 OpenLens Authors",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "dist/extension-api.js",
|
"main": "dist/extension-api.js",
|
||||||
@ -26,7 +26,7 @@
|
|||||||
"prepare:dev": "yarn run build"
|
"prepare:dev": "yarn run build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@k8slens/core": "^6.4.0-beta.17"
|
"@k8slens/core": "^6.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^16.18.6",
|
"@types/node": "^16.18.6",
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
"productName": "OpenLens",
|
"productName": "OpenLens",
|
||||||
"description": "OpenLens - Open Source IDE for Kubernetes",
|
"description": "OpenLens - Open Source IDE for Kubernetes",
|
||||||
"homepage": "https://github.com/lensapp/lens",
|
"homepage": "https://github.com/lensapp/lens",
|
||||||
"version": "6.4.0-beta.17",
|
"version": "6.4.0",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/lensapp/lens.git"
|
"url": "git+https://github.com/lensapp/lens.git"
|
||||||
@ -192,7 +192,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@k8slens/core": "^6.4.0-beta.17",
|
"@k8slens/core": "^6.4.0",
|
||||||
"@k8slens/ensure-binaries": "^6.4.0-beta.16",
|
"@k8slens/ensure-binaries": "^6.4.0-beta.16",
|
||||||
"@k8slens/generate-tray-icons": "^6.4.0-beta.16",
|
"@k8slens/generate-tray-icons": "^6.4.0-beta.16",
|
||||||
"@ogre-tools/fp": "^12.0.1",
|
"@ogre-tools/fp": "^12.0.1",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@k8slens/release-tool",
|
"name": "@k8slens/release-tool",
|
||||||
"version": "6.4.0-beta.17",
|
"version": "6.4.0",
|
||||||
"description": "Release tool for lens monorepo",
|
"description": "Release tool for lens monorepo",
|
||||||
"main": "dist/index.mjs",
|
"main": "dist/index.mjs",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
import assert from "assert";
|
import assert from "assert";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
import child_process from "child_process";
|
import child_process, { spawn } from "child_process";
|
||||||
import { readFile } from "fs/promises";
|
import { readFile } from "fs/promises";
|
||||||
import inquirer from "inquirer";
|
import inquirer from "inquirer";
|
||||||
import { createInterface, ReadLine } from "readline";
|
import { createInterface, ReadLine } from "readline";
|
||||||
@ -16,9 +16,21 @@ type SemVer = semver.SemVer;
|
|||||||
|
|
||||||
const { SemVer } = semver;
|
const { SemVer } = semver;
|
||||||
const exec = promisify(child_process.exec);
|
const exec = promisify(child_process.exec);
|
||||||
const spawn = promisify(child_process.spawn);
|
|
||||||
const execFile = promisify(child_process.execFile);
|
const execFile = promisify(child_process.execFile);
|
||||||
|
|
||||||
|
async function pipeExecFile(file: string, args: string[], opts?: { stdin: string }) {
|
||||||
|
const p = execFile(file, args);
|
||||||
|
|
||||||
|
p.child.stdout?.pipe(process.stdout);
|
||||||
|
p.child.stderr?.pipe(process.stderr);
|
||||||
|
|
||||||
|
if (opts) {
|
||||||
|
p.child.stdin?.end(opts.stdin);
|
||||||
|
}
|
||||||
|
|
||||||
|
await p;
|
||||||
|
}
|
||||||
|
|
||||||
interface GithubPrData {
|
interface GithubPrData {
|
||||||
author: {
|
author: {
|
||||||
login: string;
|
login: string;
|
||||||
@ -65,9 +77,35 @@ async function fetchAllGitTags(): Promise<string[]> {
|
|||||||
.map(line => line.trim());
|
.map(line => line.trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
async function bumpPackageVersions(): Promise<void> {
|
function bumpPackageVersions() {
|
||||||
await spawn("npm", ["run", "bump-version"], {
|
const bumpPackages = spawn("npm", ["run", "bump-version"], {
|
||||||
stdio: "inherit",
|
stdio: "inherit"
|
||||||
|
});
|
||||||
|
const cleaners: (() => void)[] = [
|
||||||
|
() => bumpPackages.stdout?.unpipe(),
|
||||||
|
() => bumpPackages.stderr?.unpipe(),
|
||||||
|
];
|
||||||
|
const cleanup = () => cleaners.forEach(clean => clean());
|
||||||
|
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
const onExit = (code: number | null) => {
|
||||||
|
cleanup();
|
||||||
|
if (code) {
|
||||||
|
reject(new Error(`"npm run bump-version" failed with code ${code}`));
|
||||||
|
} else {
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const onError = (error: Error) => {
|
||||||
|
cleanup();
|
||||||
|
reject(error);
|
||||||
|
};
|
||||||
|
|
||||||
|
bumpPackages.once("error", onError);
|
||||||
|
cleaners.push(() => bumpPackages.off("error", onError));
|
||||||
|
|
||||||
|
bumpPackages.once("exit", onExit);
|
||||||
|
cleaners.push(() => bumpPackages.off("exit", onExit));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,20 +148,12 @@ function formatSemverForMilestone(version: SemVer): string {
|
|||||||
async function createReleaseBranchAndCommit(prBase: string, version: SemVer, prBody: string): Promise<void> {
|
async function createReleaseBranchAndCommit(prBase: string, version: SemVer, prBody: string): Promise<void> {
|
||||||
const prBranch = `release/v${version.format()}`;
|
const prBranch = `release/v${version.format()}`;
|
||||||
|
|
||||||
await spawn("git", ["checkout", "-b", prBranch], {
|
await pipeExecFile("git", ["checkout", "-b", prBranch]);
|
||||||
stdio: "inherit",
|
await pipeExecFile("git", ["add", "lerna.json", "packages/*/package.json"]);
|
||||||
});
|
await pipeExecFile("git", ["commit", "-sm", `Release ${version.format()}`]);
|
||||||
await spawn("git", ["add", "lerna.json", "packages/*/package.json"], {
|
await pipeExecFile("git", ["push", "--set-upstream", "origin", prBranch]);
|
||||||
stdio: "inherit",
|
|
||||||
});
|
|
||||||
await spawn("git", ["commit", "-sm", `"Release ${version.format()}"`], {
|
|
||||||
stdio: "inherit",
|
|
||||||
});
|
|
||||||
await spawn("git", ["push", "--set-upstream", "origin", prBranch], {
|
|
||||||
stdio: "inherit",
|
|
||||||
});
|
|
||||||
|
|
||||||
await spawn("gh", [
|
await pipeExecFile("gh", [
|
||||||
"pr",
|
"pr",
|
||||||
"create",
|
"create",
|
||||||
"--base", prBase,
|
"--base", prBase,
|
||||||
@ -131,9 +161,9 @@ async function createReleaseBranchAndCommit(prBase: string, version: SemVer, prB
|
|||||||
"--label", "skip-changelog",
|
"--label", "skip-changelog",
|
||||||
"--label", "release",
|
"--label", "release",
|
||||||
"--milestone", formatSemverForMilestone(version),
|
"--milestone", formatSemverForMilestone(version),
|
||||||
"--body-file", prBody,
|
"--body-file", "-",
|
||||||
], {
|
], {
|
||||||
stdio: "inherit"
|
stdin: prBody,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +183,7 @@ function sortExtendedGithubPrData(left: ExtendedGithubPrData, right: ExtendedGit
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getRelevantPRs(milestone: string, previousReleasedVersion: string): Promise<ExtendedGithubPrData[]> {
|
async function getRelevantPRs(milestone: string, previousReleasedVersion: string): Promise<ExtendedGithubPrData[]> {
|
||||||
console.log("retreiving previous 500 PRs...");
|
console.log("retrieving previous 200 PRs...");
|
||||||
|
|
||||||
const getMergedPrsArgs = [
|
const getMergedPrsArgs = [
|
||||||
"gh",
|
"gh",
|
||||||
@ -167,14 +197,14 @@ async function getRelevantPRs(milestone: string, previousReleasedVersion: string
|
|||||||
|
|
||||||
const mergedPrs = JSON.parse((await exec(getMergedPrsArgs.join(" "), { encoding: "utf-8" })).stdout) as GithubPrData[];
|
const mergedPrs = JSON.parse((await exec(getMergedPrsArgs.join(" "), { encoding: "utf-8" })).stdout) as GithubPrData[];
|
||||||
const milestoneRelevantPrs = mergedPrs.filter(pr => pr.milestone?.title === milestone);
|
const milestoneRelevantPrs = mergedPrs.filter(pr => pr.milestone?.title === milestone);
|
||||||
const relaventPrsQuery = await Promise.all(
|
const relevantPrsQuery = await Promise.all(
|
||||||
milestoneRelevantPrs.map(async pr => ({
|
milestoneRelevantPrs.map(async pr => ({
|
||||||
pr,
|
pr,
|
||||||
stdout: (await exec(`git tag v${previousReleasedVersion} --no-contains ${pr.mergeCommit.oid}`)).stdout,
|
stdout: (await exec(`git tag v${previousReleasedVersion} --no-contains ${pr.mergeCommit.oid}`)).stdout,
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
|
|
||||||
return relaventPrsQuery
|
return relevantPrsQuery
|
||||||
.filter(query => query.stdout)
|
.filter(query => query.stdout)
|
||||||
.map(query => query.pr)
|
.map(query => query.pr)
|
||||||
.filter(pr => pr.labels.every(label => label.name !== "skip-changelog"))
|
.filter(pr => pr.labels.every(label => label.name !== "skip-changelog"))
|
||||||
@ -189,40 +219,11 @@ function formatPrEntry(pr: ExtendedGithubPrData) {
|
|||||||
const isEnhancementPr = (pr: ExtendedGithubPrData) => pr.labels.some(label => label.name === "enhancement");
|
const isEnhancementPr = (pr: ExtendedGithubPrData) => pr.labels.some(label => label.name === "enhancement");
|
||||||
const isBugfixPr = (pr: ExtendedGithubPrData) => pr.labels.some(label => label.name === "bug");
|
const isBugfixPr = (pr: ExtendedGithubPrData) => pr.labels.some(label => label.name === "bug");
|
||||||
|
|
||||||
const cherrypickCommitWith = (rl: ReadLine) => async (commit: string) => {
|
const cherryPickCommitWith = (rl: ReadLine) => async (commit: string) => {
|
||||||
try {
|
try {
|
||||||
const cherryPick = child_process.spawn("git", ["cherry-pick", commit]);
|
await pipeExecFile("git", ["cherry-pick", commit]);
|
||||||
|
|
||||||
cherryPick.stdout.pipe(process.stdout);
|
|
||||||
cherryPick.stderr.pipe(process.stderr);
|
|
||||||
|
|
||||||
await new Promise<void>((resolve, reject) => {
|
|
||||||
const cleaners: (() => void)[] = [];
|
|
||||||
const cleanup = () => cleaners.forEach(cleaner => cleaner());
|
|
||||||
|
|
||||||
const onExit = (code: number | null) => {
|
|
||||||
if (code) {
|
|
||||||
reject(new Error(`git cherry-pick failed with exit code ${code}`));
|
|
||||||
cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
cleanup();
|
|
||||||
};
|
|
||||||
|
|
||||||
cherryPick.once("exit", onExit);
|
|
||||||
cleaners.push(() => cherryPick.off("exit", onExit));
|
|
||||||
|
|
||||||
const onError = (error: Error) => {
|
|
||||||
cleanup();
|
|
||||||
reject(error);
|
|
||||||
};
|
|
||||||
|
|
||||||
cherryPick.once("error", onError);
|
|
||||||
cleaners.push(() => cherryPick.off("error", onError));
|
|
||||||
});
|
|
||||||
} catch {
|
} catch {
|
||||||
console.error(chalk.bold("Please resolve conflicts in a seperate terminal and then press enter here..."));
|
console.error(chalk.bold("Please resolve conflicts in a separate terminal and then press enter here..."));
|
||||||
await new Promise<void>(resolve => rl.once("line", () => resolve()));
|
await new Promise<void>(resolve => rl.once("line", () => resolve()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -249,7 +250,7 @@ async function pickWhichPRsToUse(prs: ExtendedGithubPrData[]): Promise<ExtendedG
|
|||||||
function formatChangelog(previousReleasedVersion: string, prs: ExtendedGithubPrData[]): string {
|
function formatChangelog(previousReleasedVersion: string, prs: ExtendedGithubPrData[]): string {
|
||||||
const enhancementPrLines: string[] = [];
|
const enhancementPrLines: string[] = [];
|
||||||
const bugPrLines: string[] = [];
|
const bugPrLines: string[] = [];
|
||||||
const maintenencePrLines: string[] = [];
|
const maintenancePrLines: string[] = [];
|
||||||
|
|
||||||
for (const pr of prs) {
|
for (const pr of prs) {
|
||||||
if (isEnhancementPr(pr)) {
|
if (isEnhancementPr(pr)) {
|
||||||
@ -257,7 +258,7 @@ function formatChangelog(previousReleasedVersion: string, prs: ExtendedGithubPrD
|
|||||||
} else if (isBugfixPr(pr)) {
|
} else if (isBugfixPr(pr)) {
|
||||||
bugPrLines.push(formatPrEntry(pr));
|
bugPrLines.push(formatPrEntry(pr));
|
||||||
} else {
|
} else {
|
||||||
maintenencePrLines.push(formatPrEntry(pr));
|
maintenancePrLines.push(formatPrEntry(pr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,9 +272,9 @@ function formatChangelog(previousReleasedVersion: string, prs: ExtendedGithubPrD
|
|||||||
bugPrLines.push("");
|
bugPrLines.push("");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maintenencePrLines.length > 0) {
|
if (maintenancePrLines.length > 0) {
|
||||||
maintenencePrLines.unshift("## 🧰 Maintenance", "");
|
maintenancePrLines.unshift("## 🧰 Maintenance", "");
|
||||||
maintenencePrLines.push("");
|
maintenancePrLines.push("");
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
@ -281,22 +282,22 @@ function formatChangelog(previousReleasedVersion: string, prs: ExtendedGithubPrD
|
|||||||
"",
|
"",
|
||||||
...enhancementPrLines,
|
...enhancementPrLines,
|
||||||
...bugPrLines,
|
...bugPrLines,
|
||||||
...maintenencePrLines,
|
...maintenancePrLines,
|
||||||
].join("\n");
|
].join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function cherrypickCommits(prs: ExtendedGithubPrData[]): Promise<void> {
|
async function cherryPickCommits(prs: ExtendedGithubPrData[]): Promise<void> {
|
||||||
const rl = createInterface(process.stdin);
|
const rl = createInterface(process.stdin);
|
||||||
const cherrypickCommit = cherrypickCommitWith(rl);
|
const cherryPickCommit = cherryPickCommitWith(rl);
|
||||||
|
|
||||||
for (const pr of prs) {
|
for (const pr of prs) {
|
||||||
await cherrypickCommit(pr.mergeCommit.oid);
|
await cherryPickCommit(pr.mergeCommit.oid);
|
||||||
}
|
}
|
||||||
|
|
||||||
rl.close();
|
rl.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function pickRelaventPrs(prs: ExtendedGithubPrData[], isMasterBranch: boolean): Promise<ExtendedGithubPrData[]> {
|
async function pickRelevantPrs(prs: ExtendedGithubPrData[], isMasterBranch: boolean): Promise<ExtendedGithubPrData[]> {
|
||||||
if (isMasterBranch) {
|
if (isMasterBranch) {
|
||||||
return prs;
|
return prs;
|
||||||
}
|
}
|
||||||
@ -307,7 +308,7 @@ async function pickRelaventPrs(prs: ExtendedGithubPrData[], isMasterBranch: bool
|
|||||||
selectedPrs = await pickWhichPRsToUse(prs);
|
selectedPrs = await pickWhichPRsToUse(prs);
|
||||||
} while (selectedPrs.length === 0 && (console.warn("[WARNING]: must pick at least once commit"), true));
|
} while (selectedPrs.length === 0 && (console.warn("[WARNING]: must pick at least once commit"), true));
|
||||||
|
|
||||||
await cherrypickCommits(selectedPrs);
|
await cherryPickCommits(selectedPrs);
|
||||||
|
|
||||||
return selectedPrs;
|
return selectedPrs;
|
||||||
}
|
}
|
||||||
@ -326,8 +327,8 @@ async function createRelease(): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const prMilestone = formatSemverForMilestone(await getCurrentVersionOfSubPackage("core"));
|
const prMilestone = formatSemverForMilestone(await getCurrentVersionOfSubPackage("core"));
|
||||||
const relaventPrs = await getRelevantPRs(prMilestone, previousReleasedVersion);
|
const relevantPrs = await getRelevantPRs(prMilestone, previousReleasedVersion);
|
||||||
const selectedPrs = await pickRelaventPrs(relaventPrs, isMasterBranch);
|
const selectedPrs = await pickRelevantPrs(relevantPrs, isMasterBranch);
|
||||||
const prBody = formatChangelog(previousReleasedVersion, selectedPrs);
|
const prBody = formatChangelog(previousReleasedVersion, selectedPrs);
|
||||||
|
|
||||||
if (!isMasterBranch) {
|
if (!isMasterBranch) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user