diff --git a/RELEASE_GUIDE.md b/RELEASE_GUIDE.md index 559385f025..f1f5915727 100644 --- a/RELEASE_GUIDE.md +++ b/RELEASE_GUIDE.md @@ -11,9 +11,12 @@ All releases will be made by creating a PR which bumps the version field in the ## Steps -1. If you are making a minor or major release (or prereleases for one) make sure you are on the `master` branch. +1. If you are making a minor or major release (or prereleases of one) make sure you are on the `master` branch. 1. If you are making a patch release (or a prerelease for one) make sure you are on the `release/v.` branch. -1. Run `yarn create-release-pr `. If you are making a subsequent prerelease release, provide the `--check-commits` flag. -1. If you are checking the commits, type `y` to pick a commit, and `n` to skip it. You will want to skip the commits that were part of previous prerelease releases. +1. Run `npm run create-release-pr`. +1. Pick the PRs that you want to include in this release using the keys listed. 1. Once the PR is created, approved, and then merged the `Release Open Lens` workflow will create a tag and release for you. 1. If you are making a major or minor release, create a `release/v.` branch and push it to `origin` so that future patch releases can be made from it. +1. If you released a major or minor version, create a new patch milestone and move all bug issues to that milestone and all enhancement issues to the next minor milestone. +1. If you released a patch version, create a new patch milestone for the next patch version and move all the issues and PRs (open or closed) that weren't included in the current release to that milestone. +1. Close the milestone related to the release that was just made (if not a prerelease release). diff --git a/lerna.json b/lerna.json index 5395d75a7e..5fceab6364 100644 --- a/lerna.json +++ b/lerna.json @@ -4,7 +4,7 @@ "packages": [ "packages/*" ], - "version": "6.4.1", + "version": "6.4.2", "npmClient": "yarn", "npmClientArgs": [ "--network-timeout=100000" diff --git a/packages/core/package.json b/packages/core/package.json index 6b1b109f41..da5f0de9ae 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -3,7 +3,7 @@ "productName": "", "description": "Lens Desktop Core", "homepage": "https://github.com/lensapp/lens", - "version": "6.4.1", + "version": "6.4.2", "repository": { "type": "git", "url": "git+https://github.com/lensapp/lens.git" diff --git a/packages/core/src/main/cluster-detectors/detect-cluster-metadata.injectable.ts b/packages/core/src/main/cluster-detectors/detect-cluster-metadata.injectable.ts index 3665f74f52..cfc492942f 100644 --- a/packages/core/src/main/cluster-detectors/detect-cluster-metadata.injectable.ts +++ b/packages/core/src/main/cluster-detectors/detect-cluster-metadata.injectable.ts @@ -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), ); diff --git a/packages/core/src/main/cluster-detectors/detect-cluster-metadata.test.ts b/packages/core/src/main/cluster-detectors/detect-cluster-metadata.test.ts new file mode 100644 index 0000000000..387e365227 --- /dev/null +++ b/packages/core/src/main/cluster-detectors/detect-cluster-metadata.test.ts @@ -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"); + }); +}); diff --git a/packages/extension-api/package.json b/packages/extension-api/package.json index 1a4e07fde2..1bdf781fd8 100644 --- a/packages/extension-api/package.json +++ b/packages/extension-api/package.json @@ -2,7 +2,7 @@ "name": "@k8slens/extensions", "productName": "OpenLens extensions", "description": "OpenLens - Open Source Kubernetes IDE: extensions", - "version": "6.4.1", + "version": "6.4.2", "copyright": "© 2022 OpenLens Authors", "license": "MIT", "main": "dist/extension-api.js", @@ -26,7 +26,7 @@ "prepare:dev": "yarn run build" }, "dependencies": { - "@k8slens/core": "^6.4.1" + "@k8slens/core": "^6.4.2" }, "devDependencies": { "@types/node": "^16.18.6", @@ -39,6 +39,7 @@ "style-loader": "^3.3.1", "ts-loader": "^9.4.2", "ts-node": "^10.9.1", + "typed-emitter": "^2.1.0", "typedoc": "0.23.25", "typedoc-plugin-markdown": "^3.13.6", "typescript": "^4.9.5", diff --git a/packages/open-lens/package.json b/packages/open-lens/package.json index 45ce7ba560..46377dad61 100644 --- a/packages/open-lens/package.json +++ b/packages/open-lens/package.json @@ -4,7 +4,7 @@ "productName": "OpenLens", "description": "OpenLens - Open Source IDE for Kubernetes", "homepage": "https://github.com/lensapp/lens", - "version": "6.4.1", + "version": "6.4.2", "repository": { "type": "git", "url": "git+https://github.com/lensapp/lens.git" @@ -192,7 +192,7 @@ } }, "dependencies": { - "@k8slens/core": "^6.4.1", + "@k8slens/core": "^6.4.2", "@k8slens/ensure-binaries": "^6.4.0-beta.16", "@k8slens/generate-tray-icons": "^6.4.0-beta.16", "@ogre-tools/fp": "^12.0.1", diff --git a/packages/release-tool/package.json b/packages/release-tool/package.json index 77d2b9b5e0..3164582d1b 100644 --- a/packages/release-tool/package.json +++ b/packages/release-tool/package.json @@ -1,6 +1,6 @@ { "name": "@k8slens/release-tool", - "version": "6.4.0", + "version": "6.4.2", "description": "Release tool for lens monorepo", "main": "dist/index.mjs", "license": "MIT", diff --git a/packages/release-tool/src/index.ts b/packages/release-tool/src/index.ts index 8c1e465ffd..2632d883f0 100755 --- a/packages/release-tool/src/index.ts +++ b/packages/release-tool/src/index.ts @@ -145,6 +145,14 @@ function formatSemverForMilestone(version: SemVer): string { return `${version.major}.${version.minor}.${version.patch}`; } +function formatVersionForPickingPrs(version: SemVer): string { + if (version.prerelease.length > 0) { + return `${version.major}.${version.minor}.${version.patch}`; + } + + return `${version.major}.${version.minor}.${version.patch+1}`; +} + async function createReleaseBranchAndCommit(prBase: string, version: SemVer, prBody: string): Promise { const prBranch = `release/v${version.format()}`; @@ -182,9 +190,10 @@ function sortExtendedGithubPrData(left: ExtendedGithubPrData, right: ExtendedGit return -1; } -async function getRelevantPRs(milestone: string, previousReleasedVersion: string): Promise { +async function getRelevantPRs(previousReleasedVersion: string): Promise { console.log("retrieving previous 200 PRs..."); + const milestone = formatVersionForPickingPrs(await getCurrentVersionOfSubPackage("core")); const getMergedPrsArgs = [ "gh", "pr", @@ -326,8 +335,7 @@ async function createRelease(): Promise { await bumpPackageVersions(); } - const prMilestone = formatSemverForMilestone(await getCurrentVersionOfSubPackage("core")); - const relevantPrs = await getRelevantPRs(prMilestone, previousReleasedVersion); + const relevantPrs = await getRelevantPRs(previousReleasedVersion); const selectedPrs = await pickRelevantPrs(relevantPrs, isMasterBranch); const prBody = formatChangelog(previousReleasedVersion, selectedPrs);