From 32e0293b08e82132779c4054e76de64f5c21127a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Aug 2021 14:33:20 -0400 Subject: [PATCH 01/15] Bump @types/npm from 2.0.31 to 2.0.32 (#3686) Bumps [@types/npm](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/npm) from 2.0.31 to 2.0.32. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/npm) --- updated-dependencies: - dependency-name: "@types/npm" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 21 ++++++++------------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index 1b5aeebdc9..764e5c7b50 100644 --- a/package.json +++ b/package.json @@ -288,7 +288,7 @@ "@types/module-alias": "^2.0.0", "@types/node": "12.20", "@types/node-fetch": "^2.5.12", - "@types/npm": "^2.0.31", + "@types/npm": "^2.0.32", "@types/progress-bar-webpack-plugin": "^2.1.2", "@types/proper-lockfile": "^4.1.1", "@types/randomcolor": "^0.5.6", diff --git a/yarn.lock b/yarn.lock index 3c9a6b7ccb..741e14197b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1717,10 +1717,10 @@ "@types/node" "*" form-data "^3.0.0" -"@types/node@*": - version "14.14.41" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.41.tgz#d0b939d94c1d7bd53d04824af45f1139b8c45615" - integrity sha512-dueRKfaJL4RTtSa7bWeTK1M+VH+Gns73oCgzvYfHZywRCoPSd8EkXBL0mZ9unPTveBn+D9phZBaxuzpwjWkW0g== +"@types/node@*", "@types/node@^14.6.2": + version "14.17.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.17.5.tgz#b59daf6a7ffa461b5648456ca59050ba8e40ed54" + integrity sha512-bjqH2cX/O33jXT/UmReo2pM7DIJREPMnarixbQ57DOOzzFaI6D2+IcwaJQaJpv0M1E9TIhPCYVxrkcityLjlqA== "@types/node@12.20", "@types/node@^12.0.12": version "12.20.21" @@ -1732,20 +1732,15 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.24.tgz#c57511e3a19c4b5e9692bb2995c40a3a52167944" integrity sha512-5SCfvCxV74kzR3uWgTYiGxrd69TbT1I6+cMx1A5kEly/IVveJBimtAMlXiEyVFn5DvUFewQWxOOiJhlxeQwxgA== -"@types/node@^14.6.2": - version "14.17.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.17.5.tgz#b59daf6a7ffa461b5648456ca59050ba8e40ed54" - integrity sha512-bjqH2cX/O33jXT/UmReo2pM7DIJREPMnarixbQ57DOOzzFaI6D2+IcwaJQaJpv0M1E9TIhPCYVxrkcityLjlqA== - "@types/normalize-package-data@^2.4.0": version "2.4.0" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== -"@types/npm@^2.0.31": - version "2.0.31" - resolved "https://registry.yarnpkg.com/@types/npm/-/npm-2.0.31.tgz#aad3aef7e165f2911a052abf548fbcc1bb468577" - integrity sha512-v4JpUx83wVGItleYsnYeZrM8NTLSnYDfTE/iGm4owy6zZPNFNmnsvvrxiYtG3cVHt/XutzTjUBQ9Bh8bnvEkCw== +"@types/npm@^2.0.32": + version "2.0.32" + resolved "https://registry.yarnpkg.com/@types/npm/-/npm-2.0.32.tgz#036682075b9c2116b510fe24b52a5b932e3a99d5" + integrity sha512-9Lg4woNVzJCtac0lET91H65lbO+8YXfk0nmlmoPGhHXMdaVEDloH6zOPIYMy2n39z/aCXXQR0nax66EDekAyIQ== dependencies: "@types/node" "*" From 56bd8cd0b1fd32c7827258b2fc592833797e2ea9 Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Thu, 26 Aug 2021 21:46:46 +0300 Subject: [PATCH 02/15] Support MacOS arm64 build (#3682) Signed-off-by: Jari Kolehmainen Co-authored-by: Jari Kolehmainen Co-authored-by: Sebastian Malton --- .azure-pipelines.yml | 85 ++++++++++++------- Makefile | 3 +- build/download_kubectl.ts | 21 +++-- .../__tests__/app-preferences.tests.ts | 2 +- package.json | 7 +- src/main/lens-binary.ts | 10 +-- 6 files changed, 79 insertions(+), 49 deletions(-) diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index 223f85518d..bf0315ad3e 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -16,8 +16,8 @@ jobs: vmImage: windows-2019 strategy: matrix: - node_12.x: - node_version: 12.x + node_14.x: + node_version: 14.x steps: - powershell: | $CI_BUILD_TAG = git describe --tags @@ -48,12 +48,6 @@ jobs: GH_TOKEN: $(LENS_IDE_GH_TOKEN) displayName: Customize config - - script: make node_modules - displayName: Install dependencies - - - script: make build-npm - displayName: Generate npm package - - script: make build condition: "and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'))" env: @@ -69,8 +63,8 @@ jobs: vmImage: macOS-10.14 strategy: matrix: - node_12.x: - node_version: 12.x + node_14.x: + node_version: 14.x steps: - script: CI_BUILD_TAG=`git describe --tags` && echo "##vso[task.setvariable variable=CI_BUILD_TAG]$CI_BUILD_TAG" condition: "and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'))" @@ -99,15 +93,57 @@ jobs: GH_TOKEN: $(LENS_IDE_GH_TOKEN) displayName: Customize config - - script: make node_modules - displayName: Install dependencies + - script: make build + condition: "and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'))" + env: + APPLEID: $(APPLEID) + APPLEIDPASS: $(APPLEIDPASS) + CSC_LINK: $(CSC_LINK) + CSC_KEY_PASSWORD: $(CSC_KEY_PASSWORD) + AWS_ACCESS_KEY_ID: $(AWS_ACCESS_KEY_ID) + AWS_SECRET_ACCESS_KEY: $(AWS_SECRET_ACCESS_KEY) + BUILD_NUMBER: $(Build.BuildNumber) + displayName: Build - - script: make build-npm - displayName: Generate npm package + - job: macOS-arm64 + pool: + vmImage: macOS-10.14 + strategy: + matrix: + node_14.x: + node_version: 14.x + steps: + - script: CI_BUILD_TAG=`git describe --tags` && echo "##vso[task.setvariable variable=CI_BUILD_TAG]$CI_BUILD_TAG" + condition: "and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'))" + displayName: Set the tag name as an environment variable + + - task: NodeTool@0 + inputs: + versionSpec: $(node_version) + displayName: Install Node.js + + - task: Cache@2 + inputs: + key: 'yarn | "$(Agent.OS)" | yarn.lock' + restoreKeys: | + yarn | "$(Agent.OS)" + path: $(YARN_CACHE_FOLDER) + displayName: Cache Yarn packages + + - bash: | + set -e + git clone "https://${GH_TOKEN}@github.com/lensapp/lens-ide.git" .lens-ide-overlay + rm -rf .lens-ide-overlay/.git + cp -r .lens-ide-overlay/* ./ + jq -s '.[0] * .[1]' package.json package.ide.json > package.custom.json && mv package.custom.json package.json + env: + GH_TOKEN: $(LENS_IDE_GH_TOKEN) + displayName: Customize config - script: make build condition: "and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'))" env: + BINARY_ARCH: arm64 APPLEID: $(APPLEID) APPLEIDPASS: $(APPLEIDPASS) CSC_LINK: $(CSC_LINK) @@ -122,8 +158,8 @@ jobs: vmImage: ubuntu-16.04 strategy: matrix: - node_12.x: - node_version: 12.x + node_14.x: + node_version: 14.x steps: - script: CI_BUILD_TAG=`git describe --tags` && echo "##vso[task.setvariable variable=CI_BUILD_TAG]$CI_BUILD_TAG" condition: "and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'))" @@ -152,23 +188,6 @@ jobs: GH_TOKEN: $(LENS_IDE_GH_TOKEN) displayName: Customize config - - script: make node_modules - displayName: Install dependencies - - - script: make build-npm - displayName: Generate npm package - - - bash: | - sudo chown root:root / - sudo apt-get update && sudo apt-get install -y snapd - sudo snap install snapcraft --classic - echo -n "${SNAP_LOGIN}" | base64 -i -d > snap_login - snapcraft login --with snap_login - condition: "and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'))" - env: - SNAP_LOGIN: $(SNAP_LOGIN) - displayName: Setup snapcraft - - script: make build condition: "and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'))" env: diff --git a/Makefile b/Makefile index 1a8baf0d37..75f6f55fa0 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,7 @@ CMD_ARGS = $(filter-out $@,$(MAKECMDGOALS)) %: @: +BINARY_ARCH ?= x64 NPM_RELEASE_TAG ?= latest EXTENSIONS_DIR = ./extensions extensions = $(foreach dir, $(wildcard $(EXTENSIONS_DIR)/*), ${dir}) @@ -64,7 +65,7 @@ ifeq "$(DETECTED_OS)" "Windows" rm -rf node_modules/win-ca/pem yarn run electron-builder --publish onTag --x64 --ia32 else - yarn run electron-builder --publish onTag + yarn run electron-builder --publish onTag --$(BINARY_ARCH) endif $(extension_node_modules): node_modules diff --git a/build/download_kubectl.ts b/build/download_kubectl.ts index 4400a5f5d0..fefdb6ebb1 100644 --- a/build/download_kubectl.ts +++ b/build/download_kubectl.ts @@ -26,6 +26,7 @@ import requestPromise from "request-promise-native"; import { ensureDir, pathExists } from "fs-extra"; import path from "path"; import { noop } from "lodash"; +import { isLinux, isMac } from "../src/common/vars"; class KubectlDownloader { public kubectlVersion: string; @@ -115,15 +116,21 @@ class KubectlDownloader { }); } } - const downloadVersion = packageInfo.config.bundledKubectlVersion; const baseDir = path.join(__dirname, "..", "binaries", "client"); -const downloads = [ - { platform: "linux", arch: "amd64", target: path.join(baseDir, "linux", "x64", "kubectl") }, - { platform: "darwin", arch: "amd64", target: path.join(baseDir, "darwin", "x64", "kubectl") }, - { platform: "windows", arch: "amd64", target: path.join(baseDir, "windows", "x64", "kubectl.exe") }, - { platform: "windows", arch: "386", target: path.join(baseDir, "windows", "ia32", "kubectl.exe") } -]; +const binaryArch = process.env.BINARY_ARCH || "amd64"; +const binaryTargetArch = binaryArch === "amd64" ? "x64" : "arm64"; + +const downloads = []; + +if (isMac) { + downloads.push({ platform: "darwin", arch: binaryArch, target: path.join(baseDir, "darwin", binaryTargetArch, "kubectl") }); +} else if (isLinux) { + downloads.push({ platform: "linux", arch: binaryArch, target: path.join(baseDir, "linux", binaryTargetArch, "kubectl") }); +} else { + downloads.push({ platform: "windows", arch: "amd64", target: path.join(baseDir, "windows", binaryTargetArch, "kubectl.exe") }); + downloads.push({ platform: "windows", arch: "386", target: path.join(baseDir, "windows", "ia32", "kubectl.exe") }); +} downloads.forEach((dlOpts) => { console.log(dlOpts); diff --git a/integration/__tests__/app-preferences.tests.ts b/integration/__tests__/app-preferences.tests.ts index 4afa8cfd96..fe3817bf0c 100644 --- a/integration/__tests__/app-preferences.tests.ts +++ b/integration/__tests__/app-preferences.tests.ts @@ -63,7 +63,7 @@ describe("preferences page tests", () => { } }, 10*60*1000); - it("ensures helm repos", async () => { + utils.itIf(process.platform !== "win32")("ensures helm repos", async () => { await window.click("[data-testid=kubernetes-tab]"); await window.waitForSelector("[data-testid=repository-name]", { timeout: 100_000, diff --git a/package.json b/package.json index 764e5c7b50..f25adbf843 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "build:win": "yarn run compile && electron-builder --win --dir", "integration": "jest --runInBand --detectOpenHandles --forceExit integration", "dist": "yarn run compile && electron-builder --publish onTag", - "dist:win": "yarn run compile && electron-builder --publish onTag --x64 --ia32", "dist:dir": "yarn run dist --dir -c.compression=store -c.mac.identity=null", "download-bins": "concurrently yarn:download:*", "download:kubectl": "yarn run ts-node build/download_kubectl.ts", @@ -48,7 +47,7 @@ }, "config": { "bundledKubectlVersion": "1.21.2", - "bundledHelmVersion": "3.5.4", + "bundledHelmVersion": "3.6.3", "sentryDsn": "" }, "engines": { @@ -141,6 +140,10 @@ "from": "binaries/client/darwin/x64/kubectl", "to": "./x64/kubectl" }, + { + "from": "binaries/client/darwin/arm64/kubectl", + "to": "./arm64/kubectl" + }, { "from": "binaries/client/helm3/helm3", "to": "./helm3/helm3" diff --git a/src/main/lens-binary.ts b/src/main/lens-binary.ts index d5e9b943a7..2c52b05db5 100644 --- a/src/main/lens-binary.ts +++ b/src/main/lens-binary.ts @@ -60,13 +60,13 @@ export class LensBinary { this.logger = console; let arch = null; - if (process.arch == "x64") { + if (process.env.BINARY_ARCH) { + arch = process.env.BINARY_ARCH; + } else if (process.arch == "x64") { arch = "amd64"; - } - else if (process.arch == "x86" || process.arch == "ia32") { + } else if (process.arch == "x86" || process.arch == "ia32") { arch = "386"; - } - else { + } else { arch = process.arch; } this.arch = arch; From f7dd3de29e88bb4222eb6a6e2902ce46b4d1516d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Aug 2021 14:47:06 -0400 Subject: [PATCH 03/15] Bump postcss-loader from 4.0.3 to 4.3.0 (#3687) Bumps [postcss-loader](https://github.com/webpack-contrib/postcss-loader) from 4.0.3 to 4.3.0. - [Release notes](https://github.com/webpack-contrib/postcss-loader/releases) - [Changelog](https://github.com/webpack-contrib/postcss-loader/blob/v4.3.0/CHANGELOG.md) - [Commits](https://github.com/webpack-contrib/postcss-loader/compare/v4.0.3...v4.3.0) --- updated-dependencies: - dependency-name: postcss-loader dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index f25adbf843..47d8ab915f 100644 --- a/package.json +++ b/package.json @@ -358,7 +358,7 @@ "nodemon": "^2.0.12", "playwright": "^1.14.0", "postcss": "^8.3.6", - "postcss-loader": "4.0.3", + "postcss-loader": "4.3.0", "postinstall-postinstall": "^2.1.0", "progress-bar-webpack-plugin": "^2.1.0", "randomcolor": "^0.6.2", diff --git a/yarn.lock b/yarn.lock index 741e14197b..5adb52ce87 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11292,16 +11292,16 @@ postcss-load-config@^3.0.1, postcss-load-config@^3.1.0: lilconfig "^2.0.3" yaml "^1.10.2" -postcss-loader@4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-4.0.3.tgz#337f51bbdfb02269fb42f7db9fc7f0a93c1b2e3f" - integrity sha512-jHboC/AOnJLPu8/974hODCJ/rNAa2YhhJOclUeuRlAmFpKmEcBY6az8y1ejHyYc2LThzPl8qPRekh2Yz3CiRKA== +postcss-loader@4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-4.3.0.tgz#2c4de9657cd4f07af5ab42bd60a673004da1b8cc" + integrity sha512-M/dSoIiNDOo8Rk0mUqoj4kpGq91gcxCfb9PoyZVdZ76/AuhxylHDYZblNE8o+EQ9AMSASeMFEKxZf5aU6wlx1Q== dependencies: cosmiconfig "^7.0.0" klona "^2.0.4" loader-utils "^2.0.0" - schema-utils "^2.7.1" - semver "^7.3.2" + schema-utils "^3.0.0" + semver "^7.3.4" postcss-modules-extract-imports@^3.0.0: version "3.0.0" @@ -12625,7 +12625,7 @@ schema-utils@^1.0.0: ajv-errors "^1.0.0" ajv-keywords "^3.1.0" -schema-utils@^2.6.1, schema-utils@^2.6.5, schema-utils@^2.7.1: +schema-utils@^2.6.1, schema-utils@^2.6.5: version "2.7.1" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7" integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg== From 6d1e6a2c417fad0cb761d802b0b7579d5323b0de Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Tue, 31 Aug 2021 08:30:02 +0300 Subject: [PATCH 04/15] Test build on macOS/arm64 (#3695) * test build on macos arm64 Signed-off-by: Jari Kolehmainen * fix syntax Signed-off-by: Jari Kolehmainen * fix syntax Signed-off-by: Jari Kolehmainen * clean first Signed-off-by: Jari Kolehmainen * node-gyp 7.1.2 Signed-off-by: Jari Kolehmainen * test Signed-off-by: Jari Kolehmainen * test Signed-off-by: Jari Kolehmainen * cleanup Signed-off-by: Jari Kolehmainen --- .github/workflows/test.yml | 9 ++++++++- package.json | 1 + yarn.lock | 28 ++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3058f28fe0..63d37871cd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,7 +12,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-16.04, macos-10.15, windows-2019] + os: [ubuntu-16.04, macos-11, windows-2019] node-version: [14.x] steps: - name: Checkout Release from lens @@ -86,3 +86,10 @@ jobs: name: Run integration tests shell: bash if: runner.os != 'Linux' + + - run: make build + name: Test build (arm64) + shell: bash + env: + BINARY_ARCH: arm64 + if: runner.os == 'macOS' diff --git a/package.json b/package.json index 47d8ab915f..f016a896b3 100644 --- a/package.json +++ b/package.json @@ -353,6 +353,7 @@ "jest-mock-extended": "^1.0.16", "make-plural": "^6.2.2", "mini-css-extract-plugin": "^1.6.0", + "node-gyp": "7.1.2", "node-loader": "^1.0.3", "node-sass": "^4.14.1", "nodemon": "^2.0.12", diff --git a/yarn.lock b/yarn.lock index 5adb52ce87..c9d81d9a9f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6846,6 +6846,11 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6 resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== +graceful-fs@^4.2.3: + version "4.2.8" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" + integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== + "graceful-readlink@>= 1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" @@ -10001,6 +10006,22 @@ node-forge@^0.8.2: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.8.5.tgz#57906f07614dc72762c84cef442f427c0e1b86ee" integrity sha512-vFMQIWt+J/7FLNyKouZ9TazT74PRV3wgv9UT4cRjC8BffxFbKXkgIWR42URCPSnHm/QDz6BOlb2Q0U4+VQT67Q== +node-gyp@7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-7.1.2.tgz#21a810aebb187120251c3bcec979af1587b188ae" + integrity sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ== + dependencies: + env-paths "^2.2.0" + glob "^7.1.4" + graceful-fs "^4.2.3" + nopt "^5.0.0" + npmlog "^4.1.2" + request "^2.88.2" + rimraf "^3.0.2" + semver "^7.3.2" + tar "^6.0.2" + which "^2.0.2" + node-gyp@^3.8.0: version "3.8.0" resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c" @@ -10156,6 +10177,13 @@ nopt@^4.0.1, nopt@^4.0.3: abbrev "1" osenv "^0.1.4" +nopt@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" + integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== + dependencies: + abbrev "1" + nopt@~1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" From d78c65d7e1023dd4988a1066b9a987617ae428fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 31 Aug 2021 10:35:45 +0300 Subject: [PATCH 05/15] Bump esbuild from 0.12.12 to 0.12.24 (#3694) Bumps [esbuild](https://github.com/evanw/esbuild) from 0.12.12 to 0.12.24. - [Release notes](https://github.com/evanw/esbuild/releases) - [Changelog](https://github.com/evanw/esbuild/blob/master/CHANGELOG.md) - [Commits](https://github.com/evanw/esbuild/compare/v0.12.12...v0.12.24) --- updated-dependencies: - dependency-name: esbuild dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f016a896b3..1650689e4f 100644 --- a/package.json +++ b/package.json @@ -333,7 +333,7 @@ "electron": "^12.0.17", "electron-builder": "^22.10.5", "electron-notarize": "^0.3.0", - "esbuild": "^0.12.12", + "esbuild": "^0.12.24", "esbuild-loader": "^2.13.1", "eslint": "^7.7.0", "eslint-plugin-header": "^3.1.1", diff --git a/yarn.lock b/yarn.lock index c9d81d9a9f..92d33c4162 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5495,10 +5495,10 @@ esbuild@^0.11.19: resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.11.23.tgz#c42534f632e165120671d64db67883634333b4b8" integrity sha512-iaiZZ9vUF5wJV8ob1tl+5aJTrwDczlvGP0JoMmnpC2B0ppiMCu8n8gmy5ZTGl5bcG081XBVn+U+jP+mPFm5T5Q== -esbuild@^0.12.12: - version "0.12.12" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.12.12.tgz#2c3815c508e20f771cf6b2ffb03aa7349e651657" - integrity sha512-fdB/8HRg9u95Zi4/qV+osrfzpvLzubFKUr8SkZf/kUKImLiX61Y7qBzV14FCKphFk7YoXWY85nbPGkI6pq+Zeg== +esbuild@^0.12.24: + version "0.12.24" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.12.24.tgz#21966fad25a80f368ed308101e88102bce0dc68f" + integrity sha512-C0ibY+HsXzYB6L/pLWEiWjMpghKsIc58Q5yumARwBQsHl9DXPakW+5NI/Y9w4YXiz0PEP6XTGTT/OV4Nnsmb4A== escalade@^3.1.1: version "3.1.1" From 9d6bed8786d3db09d47c5f100b1ee6cd2cd065ac Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Tue, 31 Aug 2021 11:00:27 +0300 Subject: [PATCH 06/15] Build and release amd64 & arm64 together (macOS) (#3700) * build and release amd64 & arm64 together Signed-off-by: Jari Kolehmainen * fixes Signed-off-by: Jari Kolehmainen --- .azure-pipelines.yml | 52 +++----------------------------------- .github/workflows/test.yml | 16 +++++++----- Makefile | 6 ++--- build/download_helm.ts | 16 ++++++++++-- build/download_kubectl.ts | 10 ++++---- package.json | 14 ++++------ src/main/helm/helm-cli.ts | 2 +- 7 files changed, 39 insertions(+), 77 deletions(-) diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index bf0315ad3e..3e1b43f875 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -56,11 +56,12 @@ jobs: AWS_ACCESS_KEY_ID: $(AWS_ACCESS_KEY_ID) AWS_SECRET_ACCESS_KEY: $(AWS_SECRET_ACCESS_KEY) BUILD_NUMBER: $(Build.BuildNumber) + ELECTRON_BUILDER_EXTRA_ARGS: "--x64 --ia32" displayName: Build - job: macOS pool: - vmImage: macOS-10.14 + vmImage: macOS-11 strategy: matrix: node_14.x: @@ -103,54 +104,7 @@ jobs: AWS_ACCESS_KEY_ID: $(AWS_ACCESS_KEY_ID) AWS_SECRET_ACCESS_KEY: $(AWS_SECRET_ACCESS_KEY) BUILD_NUMBER: $(Build.BuildNumber) - displayName: Build - - - job: macOS-arm64 - pool: - vmImage: macOS-10.14 - strategy: - matrix: - node_14.x: - node_version: 14.x - steps: - - script: CI_BUILD_TAG=`git describe --tags` && echo "##vso[task.setvariable variable=CI_BUILD_TAG]$CI_BUILD_TAG" - condition: "and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'))" - displayName: Set the tag name as an environment variable - - - task: NodeTool@0 - inputs: - versionSpec: $(node_version) - displayName: Install Node.js - - - task: Cache@2 - inputs: - key: 'yarn | "$(Agent.OS)" | yarn.lock' - restoreKeys: | - yarn | "$(Agent.OS)" - path: $(YARN_CACHE_FOLDER) - displayName: Cache Yarn packages - - - bash: | - set -e - git clone "https://${GH_TOKEN}@github.com/lensapp/lens-ide.git" .lens-ide-overlay - rm -rf .lens-ide-overlay/.git - cp -r .lens-ide-overlay/* ./ - jq -s '.[0] * .[1]' package.json package.ide.json > package.custom.json && mv package.custom.json package.json - env: - GH_TOKEN: $(LENS_IDE_GH_TOKEN) - displayName: Customize config - - - script: make build - condition: "and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/'))" - env: - BINARY_ARCH: arm64 - APPLEID: $(APPLEID) - APPLEIDPASS: $(APPLEIDPASS) - CSC_LINK: $(CSC_LINK) - CSC_KEY_PASSWORD: $(CSC_KEY_PASSWORD) - AWS_ACCESS_KEY_ID: $(AWS_ACCESS_KEY_ID) - AWS_SECRET_ACCESS_KEY: $(AWS_SECRET_ACCESS_KEY) - BUILD_NUMBER: $(Build.BuildNumber) + ELECTRON_BUILDER_EXTRA_ARGS: "--x64 --arm64" displayName: Build - job: Linux diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 63d37871cd..b319c97770 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -83,13 +83,15 @@ jobs: if: runner.os == 'Linux' - run: make integration - name: Run integration tests - shell: bash - if: runner.os != 'Linux' - - - run: make build - name: Test build (arm64) + name: Run macOS integration tests shell: bash env: - BINARY_ARCH: arm64 + ELECTRON_BUILDER_EXTRA_ARGS: "--x64 --arm64" if: runner.os == 'macOS' + + - run: make integration + name: Run Windows integration tests + shell: bash + env: + ELECTRON_BUILDER_EXTRA_ARGS: "--x64 --ia32" + if: runner.os == 'Windows' diff --git a/Makefile b/Makefile index 75f6f55fa0..cf6f988af1 100644 --- a/Makefile +++ b/Makefile @@ -3,8 +3,8 @@ CMD_ARGS = $(filter-out $@,$(MAKECMDGOALS)) %: @: -BINARY_ARCH ?= x64 NPM_RELEASE_TAG ?= latest +ELECTRON_BUILDER_EXTRA_ARGS ?= EXTENSIONS_DIR = ./extensions extensions = $(foreach dir, $(wildcard $(EXTENSIONS_DIR)/*), ${dir}) extension_node_modules = $(foreach dir, $(wildcard $(EXTENSIONS_DIR)/*), ${dir}/node_modules) @@ -63,10 +63,8 @@ build: node_modules binaries/client ifeq "$(DETECTED_OS)" "Windows" # https://github.com/ukoloff/win-ca#clear-pem-folder-on-publish rm -rf node_modules/win-ca/pem - yarn run electron-builder --publish onTag --x64 --ia32 -else - yarn run electron-builder --publish onTag --$(BINARY_ARCH) endif + yarn run electron-builder --publish onTag $(ELECTRON_BUILDER_EXTRA_ARGS) $(extension_node_modules): node_modules cd $(@:/node_modules=) && ../../node_modules/.bin/npm install --no-audit --no-fund diff --git a/build/download_helm.ts b/build/download_helm.ts index 703684066b..6c606d06d5 100644 --- a/build/download_helm.ts +++ b/build/download_helm.ts @@ -18,6 +18,18 @@ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { helmCli } from "../src/main/helm/helm-cli"; +import packageInfo from "../package.json"; +import { isWindows } from "../src/common/vars"; +import { HelmCli } from "../src/main/helm/helm-cli"; +import * as path from "path"; -helmCli.ensureBinary(); +const helmVersion = packageInfo.config.bundledHelmVersion; + +if (!isWindows) { + Promise.all([ + new HelmCli(path.join(process.cwd(), "binaries", "client", "x64"), helmVersion).ensureBinary(), + new HelmCli(path.join(process.cwd(), "binaries", "client", "arm64"), helmVersion).ensureBinary() + ]); +} else { + new HelmCli(path.join(process.cwd(), "binaries", "client", "x64"), helmVersion).ensureBinary(); +} diff --git a/build/download_kubectl.ts b/build/download_kubectl.ts index fefdb6ebb1..e87534d24f 100644 --- a/build/download_kubectl.ts +++ b/build/download_kubectl.ts @@ -118,17 +118,17 @@ class KubectlDownloader { } const downloadVersion = packageInfo.config.bundledKubectlVersion; const baseDir = path.join(__dirname, "..", "binaries", "client"); -const binaryArch = process.env.BINARY_ARCH || "amd64"; -const binaryTargetArch = binaryArch === "amd64" ? "x64" : "arm64"; const downloads = []; if (isMac) { - downloads.push({ platform: "darwin", arch: binaryArch, target: path.join(baseDir, "darwin", binaryTargetArch, "kubectl") }); + downloads.push({ platform: "darwin", arch: "amd64", target: path.join(baseDir, "darwin", "x64", "kubectl") }); + downloads.push({ platform: "darwin", arch: "arm64", target: path.join(baseDir, "darwin", "arm64", "kubectl") }); } else if (isLinux) { - downloads.push({ platform: "linux", arch: binaryArch, target: path.join(baseDir, "linux", binaryTargetArch, "kubectl") }); + downloads.push({ platform: "linux", arch: "amd64", target: path.join(baseDir, "linux", "x64", "kubectl") }); + downloads.push({ platform: "linux", arch: "arm64", target: path.join(baseDir, "linux", "arm64", "kubectl") }); } else { - downloads.push({ platform: "windows", arch: "amd64", target: path.join(baseDir, "windows", binaryTargetArch, "kubectl.exe") }); + downloads.push({ platform: "windows", arch: "amd64", target: path.join(baseDir, "windows", "x64", "kubectl.exe") }); downloads.push({ platform: "windows", arch: "386", target: path.join(baseDir, "windows", "ia32", "kubectl.exe") }); } diff --git a/package.json b/package.json index 1650689e4f..4acccdd50c 100644 --- a/package.json +++ b/package.json @@ -121,8 +121,8 @@ ], "extraResources": [ { - "from": "binaries/client/linux/x64/kubectl", - "to": "./x64/kubectl" + "from": "binaries/client/linux/${arch}/kubectl", + "to": "./${arch}/kubectl" }, { "from": "binaries/client/helm3/helm3", @@ -137,15 +137,11 @@ "entitlementsInherit": "build/entitlements.mac.plist", "extraResources": [ { - "from": "binaries/client/darwin/x64/kubectl", - "to": "./x64/kubectl" + "from": "binaries/client/darwin/${arch}/kubectl", + "to": "./${arch}/kubectl" }, { - "from": "binaries/client/darwin/arm64/kubectl", - "to": "./arm64/kubectl" - }, - { - "from": "binaries/client/helm3/helm3", + "from": "binaries/client/${arch}/helm3/helm3", "to": "./helm3/helm3" } ] diff --git a/src/main/helm/helm-cli.ts b/src/main/helm/helm-cli.ts index 72d4acba29..2ce575ee4e 100644 --- a/src/main/helm/helm-cli.ts +++ b/src/main/helm/helm-cli.ts @@ -58,7 +58,7 @@ const helmVersion = packageInfo.config.bundledHelmVersion; let baseDir = process.resourcesPath; if (!isProduction) { - baseDir = path.join(process.cwd(), "binaries", "client"); + baseDir = path.join(process.cwd(), "binaries", "client", process.arch); } export const helmCli = new HelmCli(baseDir, helmVersion); From 7981e79cbd24826d68bbcae4e2f128891fbf11a0 Mon Sep 17 00:00:00 2001 From: Alex Andreev Date: Tue, 31 Aug 2021 14:44:47 +0300 Subject: [PATCH 07/15] Topbar history buttons (#3696) * HistoryStore initial draft Signed-off-by: Alex Andreev * Adding history icons Signed-off-by: Alex Andreev * Jump history using electron methods Signed-off-by: Alex Andreev * Using 1 topbar component for all views Signed-off-by: Alex Andreev * Add Catalog title to sidebar Signed-off-by: Alex Andreev * Show cluster name in sidebar Signed-off-by: Alex Andreev * Updating topbar tests Signed-off-by: Alex Andreev * Fixing Welcome tests Signed-off-by: Alex Andreev * Removing padding for external topbar items Signed-off-by: Alex Andreev * Fix cluster name prop Signed-off-by: Alex Andreev * Using material icons for history buttons Signed-off-by: Alex Andreev --- src/main/window-manager.ts | 1 + .../+catalog/catalog-menu.module.css | 5 ++ .../components/+catalog/catalog-menu.tsx | 1 + src/renderer/components/+catalog/catalog.tsx | 4 +- .../+welcome/__test__/welcome.test.tsx | 9 +++ src/renderer/components/+welcome/welcome.tsx | 4 +- src/renderer/components/app.tsx | 5 +- .../cluster-manager/catalog-topbar.tsx | 41 ----------- .../cluster-manager/cluster-topbar.tsx | 61 ---------------- .../cluster-manager/cluster-view.tsx | 4 +- .../layout/__tests__/topbar.test.tsx | 70 +++++++++++++++++-- src/renderer/components/layout/sidebar.scss | 8 +++ src/renderer/components/layout/sidebar.tsx | 5 ++ .../components/layout/topbar.module.css | 7 +- src/renderer/components/layout/topbar.tsx | 54 ++++++++++++-- .../history-updater.ts} | 16 +++-- 16 files changed, 163 insertions(+), 132 deletions(-) delete mode 100644 src/renderer/components/cluster-manager/catalog-topbar.tsx delete mode 100644 src/renderer/components/cluster-manager/cluster-topbar.tsx rename src/renderer/{components/cluster-manager/welcome-topbar.tsx => remote-helpers/history-updater.ts} (70%) diff --git a/src/main/window-manager.ts b/src/main/window-manager.ts index 6adba1a987..0822ed331a 100644 --- a/src/main/window-manager.ts +++ b/src/main/window-manager.ts @@ -244,6 +244,7 @@ export class WindowManager extends Singleton { this.sendToView({ channel: IpcRendererNavigationEvents.RELOAD_PAGE, frameInfo }); } else { webContents.getFocusedWebContents()?.reload(); + webContents.getFocusedWebContents()?.clearHistory(); } } diff --git a/src/renderer/components/+catalog/catalog-menu.module.css b/src/renderer/components/+catalog/catalog-menu.module.css index c72dd5bb53..84584e089d 100644 --- a/src/renderer/components/+catalog/catalog-menu.module.css +++ b/src/renderer/components/+catalog/catalog-menu.module.css @@ -27,4 +27,9 @@ @apply uppercase font-bold; color: var(--textColorAccent); font-size: small; +} + +.catalog { + @apply p-5 font-bold text-2xl; + color: var(--textColorAccent); } \ No newline at end of file diff --git a/src/renderer/components/+catalog/catalog-menu.tsx b/src/renderer/components/+catalog/catalog-menu.tsx index 78052cbd9d..0e3d54094e 100644 --- a/src/renderer/components/+catalog/catalog-menu.tsx +++ b/src/renderer/components/+catalog/catalog-menu.tsx @@ -58,6 +58,7 @@ export function CatalogMenu(props: Props) { // Overwrite Material UI styles with injectFirst https://material-ui.com/guides/interoperability/#controlling-priority-4
+
Catalog
} diff --git a/src/renderer/components/+catalog/catalog.tsx b/src/renderer/components/+catalog/catalog.tsx index 4256170649..658c91273f 100644 --- a/src/renderer/components/+catalog/catalog.tsx +++ b/src/renderer/components/+catalog/catalog.tsx @@ -43,7 +43,7 @@ import { catalogURL, CatalogViewRouteParam } from "../../../common/routes"; import { CatalogMenu } from "./catalog-menu"; import { HotbarIcon } from "../hotbar/hotbar-icon"; import { RenderDelay } from "../render-delay/render-delay"; -import { CatalogTopbar } from "../cluster-manager/catalog-topbar"; +import { TopBar } from "../layout/topbar"; export const previousActiveTab = createAppStorage("catalog-previous-active-tab", ""); @@ -247,7 +247,7 @@ export class Catalog extends React.Component { return ( <> - +
{ this.renderList() } diff --git a/src/renderer/components/+welcome/__test__/welcome.test.tsx b/src/renderer/components/+welcome/__test__/welcome.test.tsx index 6eab098d05..d2eda315c4 100644 --- a/src/renderer/components/+welcome/__test__/welcome.test.tsx +++ b/src/renderer/components/+welcome/__test__/welcome.test.tsx @@ -26,6 +26,15 @@ import { Welcome } from "../welcome"; import { TopBarRegistry, WelcomeMenuRegistry, WelcomeBannerRegistry } from "../../../../extensions/registries"; import { defaultWidth } from "../welcome"; +jest.mock( + "electron", + () => ({ + ipcRenderer: { + on: jest.fn(), + }, + }) +); + describe("", () => { beforeEach(() => { TopBarRegistry.createInstance(); diff --git a/src/renderer/components/+welcome/welcome.tsx b/src/renderer/components/+welcome/welcome.tsx index d2ec4fea8c..a4cff08369 100644 --- a/src/renderer/components/+welcome/welcome.tsx +++ b/src/renderer/components/+welcome/welcome.tsx @@ -26,8 +26,8 @@ import Carousel from "react-material-ui-carousel"; import { Icon } from "../icon"; import { productName, slackUrl } from "../../../common/vars"; import { WelcomeMenuRegistry } from "../../../extensions/registries"; -import { WelcomeTopbar } from "../cluster-manager/welcome-topbar"; import { WelcomeBannerRegistry } from "../../../extensions/registries"; +import { TopBar } from "../layout/topbar"; export const defaultWidth = 320; @@ -49,7 +49,7 @@ export class Welcome extends React.Component { return ( <> - +
{welcomeBanner.length > 0 ? ( diff --git a/src/renderer/components/app.tsx b/src/renderer/components/app.tsx index 46e285969a..3f8dbf7d8b 100755 --- a/src/renderer/components/app.tsx +++ b/src/renderer/components/app.tsx @@ -72,6 +72,7 @@ import { catalogEntityRegistry } from "../api/catalog-entity-registry"; import { getHostedClusterId } from "../utils"; import { ClusterStore } from "../../common/cluster-store"; import type { ClusterId } from "../../common/cluster-types"; +import { watchHistoryState } from "../remote-helpers/history-updater"; @observer export class App extends React.Component { @@ -128,7 +129,9 @@ export class App extends React.Component { disposeOnUnmount(this, [ kubeWatchApi.subscribeStores([podsStore, nodesStore, eventStore, namespaceStore], { preload: true, - }) + }), + + watchHistoryState() ]); } diff --git a/src/renderer/components/cluster-manager/catalog-topbar.tsx b/src/renderer/components/cluster-manager/catalog-topbar.tsx deleted file mode 100644 index 7e70834ae3..0000000000 --- a/src/renderer/components/cluster-manager/catalog-topbar.tsx +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (c) 2021 OpenLens Authors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -import React from "react"; -import { welcomeURL } from "../../../common/routes"; -import { navigate } from "../../navigation"; -import { Icon } from "../icon"; -import { TopBar } from "../layout/topbar"; - -export function CatalogTopbar() { - return ( - -
- navigate(welcomeURL())} - tooltip="Close Catalog" - /> -
-
- ); -} diff --git a/src/renderer/components/cluster-manager/cluster-topbar.tsx b/src/renderer/components/cluster-manager/cluster-topbar.tsx deleted file mode 100644 index 20a6120ba1..0000000000 --- a/src/renderer/components/cluster-manager/cluster-topbar.tsx +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Copyright (c) 2021 OpenLens Authors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -import { observer } from "mobx-react"; -import React from "react"; - -import { previousActiveTab } from "../+catalog"; -import { ClusterStore } from "../../../common/cluster-store"; -import { catalogURL } from "../../../common/routes"; -import { navigate } from "../../navigation"; -import { Icon } from "../icon"; -import { TopBar } from "../layout/topbar"; - -import type { RouteComponentProps } from "react-router"; -import type { ClusterViewRouteParams } from "../../../common/routes"; -import type { Cluster } from "../../../main/cluster"; -import { TooltipPosition } from "../tooltip"; - -interface Props extends RouteComponentProps { -} - -export const ClusterTopbar = observer((props: Props) => { - const getCluster = (): Cluster | undefined => { - return ClusterStore.getInstance().getById(props.match.params.clusterId); - }; - - return ( - -
- { - navigate(`${catalogURL()}/${previousActiveTab.get()}`); - }} - tooltip={{ - preferredPositions: TooltipPosition.BOTTOM_RIGHT, - children: "Back to Catalog" - }} - /> -
-
- ); -}); diff --git a/src/renderer/components/cluster-manager/cluster-view.tsx b/src/renderer/components/cluster-manager/cluster-view.tsx index 3d0fea8e55..1c8a9435fc 100644 --- a/src/renderer/components/cluster-manager/cluster-view.tsx +++ b/src/renderer/components/cluster-manager/cluster-view.tsx @@ -34,7 +34,7 @@ import { catalogEntityRegistry } from "../../api/catalog-entity-registry"; import { navigate } from "../../navigation"; import { catalogURL, ClusterViewRouteParams } from "../../../common/routes"; import { previousActiveTab } from "../+catalog"; -import { ClusterTopbar } from "./cluster-topbar"; +import { TopBar } from "../layout/topbar"; interface Props extends RouteComponentProps { } @@ -105,7 +105,7 @@ export class ClusterView extends React.Component { render() { return (
- + {this.renderStatus()}
); diff --git a/src/renderer/components/layout/__tests__/topbar.test.tsx b/src/renderer/components/layout/__tests__/topbar.test.tsx index a8e69ed302..499a52bc66 100644 --- a/src/renderer/components/layout/__tests__/topbar.test.tsx +++ b/src/renderer/components/layout/__tests__/topbar.test.tsx @@ -20,11 +20,46 @@ */ import React from "react"; -import { render } from "@testing-library/react"; +import { render, fireEvent } from "@testing-library/react"; import "@testing-library/jest-dom/extend-expect"; import { TopBar } from "../topbar"; import { TopBarRegistry } from "../../../../extensions/registries"; +jest.mock( + "electron", + () => ({ + ipcRenderer: { + on: jest.fn( + (channel: string, listener: (event: any, ...args: any[]) => void) => { + if (channel === "history:can-go-back") { + listener({}, true); + } + + if (channel === "history:can-go-forward") { + listener({}, true); + } + } + ), + }, + }) +); + +const goBack = jest.fn(); +const goForward = jest.fn(); + +jest.mock("@electron/remote", () => { + return { + webContents: { + getFocusedWebContents: () => { + return { + goBack, + goForward + }; + } + } + }; +}); + describe("", () => { beforeEach(() => { TopBarRegistry.createInstance(); @@ -35,15 +70,38 @@ describe("", () => { }); it("renders w/o errors", () => { - const { container } = render(); + const { container } = render(); expect(container).toBeInstanceOf(HTMLElement); }); - it("renders title", async () => { - const { getByTestId } = render(); + it("renders history arrows", async () => { + const { getByTestId } = render(); - expect(await getByTestId("topbarLabel")).toHaveTextContent("topbar"); + expect(await getByTestId("history-back")).toBeInTheDocument(); + expect(await getByTestId("history-forward")).toBeInTheDocument(); + }); + + it("enables arrow by ipc event", async () => { + const { getByTestId } = render(); + + expect(await getByTestId("history-back")).not.toHaveClass("disabled"); + expect(await getByTestId("history-forward")).not.toHaveClass("disabled"); + }); + + it("triggers browser history back and forward", async () => { + const { getByTestId } = render(); + + const prevButton = await getByTestId("history-back"); + const nextButton = await getByTestId("history-forward"); + + fireEvent.click(prevButton); + + expect(goBack).toBeCalled(); + + fireEvent.click(nextButton); + + expect(goForward).toBeCalled(); }); it("renders items", async () => { @@ -58,7 +116,7 @@ describe("", () => { } ]); - const { getByTestId } = render(); + const { getByTestId } = render(); expect(await getByTestId(testId)).toHaveTextContent(text); }); diff --git a/src/renderer/components/layout/sidebar.scss b/src/renderer/components/layout/sidebar.scss index f0d777fadd..18ac932f69 100644 --- a/src/renderer/components/layout/sidebar.scss +++ b/src/renderer/components/layout/sidebar.scss @@ -45,4 +45,12 @@ padding: $padding; text-align: center; } + + .cluster-name { + padding: 1.25rem; + font-weight: bold; + font-size: 1.5rem; + word-break: break-all; + color: var(--textColorAccent); + } } diff --git a/src/renderer/components/layout/sidebar.tsx b/src/renderer/components/layout/sidebar.tsx index 44e57e9202..adfac26add 100644 --- a/src/renderer/components/layout/sidebar.tsx +++ b/src/renderer/components/layout/sidebar.tsx @@ -40,6 +40,8 @@ import { SidebarItem } from "./sidebar-item"; import { Apps } from "../+apps"; import * as routes from "../../../common/routes"; import { Config } from "../+config"; +import { ClusterStore } from "../../../common/cluster-store"; +import { App } from "../app"; interface Props { className?: string; @@ -181,6 +183,9 @@ export class Sidebar extends React.Component { return (
+
+ {ClusterStore.getInstance().getById(App.clusterId)?.name} +
{ - label: React.ReactNode; } -export const TopBar = observer(({ label, children, ...rest }: Props) => { +const prevEnabled = observable.box(false); +const nextEnabled = observable.box(false); + +ipcRendererOn("history:can-go-back", (event, state: boolean) => { + prevEnabled.set(state); +}); + +ipcRendererOn("history:can-go-forward", (event, state: boolean) => { + nextEnabled.set(state); +}); + +export const TopBar = observer(({ children, ...rest }: Props) => { const renderRegisteredItems = () => { const items = TopBarRegistry.getInstance().getItems(); @@ -37,7 +52,7 @@ export const TopBar = observer(({ label, children, ...rest }: Props) => { } return ( -
+
{items.map((registration, index) => { if (!registration?.components?.Item) { return null; @@ -53,9 +68,38 @@ export const TopBar = observer(({ label, children, ...rest }: Props) => { ); }; + const goBack = () => { + webContents.getFocusedWebContents()?.goBack(); + }; + + const goForward = () => { + webContents.getFocusedWebContents()?.goForward(); + }; + + useEffect(() => { + const disposer = watchHistoryState(); + + return () => disposer(); + }, []); + return (
-
{label}
+
+ + +
{renderRegisteredItems()} {children} diff --git a/src/renderer/components/cluster-manager/welcome-topbar.tsx b/src/renderer/remote-helpers/history-updater.ts similarity index 70% rename from src/renderer/components/cluster-manager/welcome-topbar.tsx rename to src/renderer/remote-helpers/history-updater.ts index c528326c7a..3a8c9bfc04 100644 --- a/src/renderer/components/cluster-manager/welcome-topbar.tsx +++ b/src/renderer/remote-helpers/history-updater.ts @@ -19,12 +19,14 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import React from "react"; -import { TopBar } from "../layout/topbar"; +import { webContents } from "@electron/remote"; +import { reaction } from "mobx"; +import { broadcastMessage } from "../../common/ipc"; +import { navigation } from "../navigation"; -export function WelcomeTopbar() { - return ( - - - ); +export function watchHistoryState() { + return reaction(() => navigation.location, () => { + broadcastMessage("history:can-go-back", webContents.getFocusedWebContents()?.canGoBack()); + broadcastMessage("history:can-go-forward", webContents.getFocusedWebContents()?.canGoForward()); + }); } From 6fdb2f0b58a0f6f1453393372da32d1912fe1d7a Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 31 Aug 2021 09:00:56 -0400 Subject: [PATCH 08/15] Support filtering catalog entities (#3647) * Support filtering catalog entities - This allows extensions and OpenLens to restrict which of the entities the sources have provied are "visible" to the rest of Lens Signed-off-by: Sebastian Malton * Fix lint Signed-off-by: Sebastian Malton * switch to filtering only for catalog view Signed-off-by: Sebastian Malton * Fix test Signed-off-by: Panu Horsmalahti * Add test to iter reduce Signed-off-by: Panu Horsmalahti Co-authored-by: Panu Horsmalahti --- src/common/utils/__tests__/iter.test.ts | 34 ++++++++++ src/common/utils/iter.ts | 19 ++++++ src/extensions/lens-renderer-extension.ts | 17 ++++- src/main/catalog/catalog-entity-registry.ts | 20 +++--- .../__tests__/catalog-entity-registry.test.ts | 67 ++++++++++++++++++- src/renderer/api/catalog-entity-registry.ts | 56 +++++++++++++--- .../+catalog/catalog-entity.store.tsx | 4 +- .../components/hotbar/hotbar-menu.tsx | 2 +- 8 files changed, 192 insertions(+), 27 deletions(-) create mode 100644 src/common/utils/__tests__/iter.test.ts diff --git a/src/common/utils/__tests__/iter.test.ts b/src/common/utils/__tests__/iter.test.ts new file mode 100644 index 0000000000..fd4677df0d --- /dev/null +++ b/src/common/utils/__tests__/iter.test.ts @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import { reduce } from "../iter"; + +describe("iter", () => { + describe("reduce", () => { + it("can reduce a value", () => { + expect(reduce([1, 2, 3], (acc: number[], current: number) => [current, ...acc], [0])).toEqual([3, 2, 1, 0]); + }); + + it("can reduce an empty iterable", () => { + expect(reduce([], (acc: number[], current: number) => [acc[0] + current], [])).toEqual([]); + }); + }); +}); diff --git a/src/common/utils/iter.ts b/src/common/utils/iter.ts index 59fce41829..65b0937726 100644 --- a/src/common/utils/iter.ts +++ b/src/common/utils/iter.ts @@ -156,3 +156,22 @@ export function find(src: Iterable, match: (i: T) => any): T | undefined { return void 0; } + +/** + * Iterate over `src` calling `reducer` with the previous produced value and the current + * yielded value until `src` is exausted. Then return the final value. + * @param src The value to iterate over + * @param reducer A function for producing the next item from an accumilation and the current item + * @param initial The initial value for the iteration + */ +export function reduce(src: Iterable, reducer: (acc: Iterable, cur: T) => Iterable, initial: Iterable): Iterable; + +export function reduce(src: Iterable, reducer: (acc: R, cur: T) => R, initial: R): R { + let acc = initial; + + for (const item of src) { + acc = reducer(acc, item); + } + + return acc; +} diff --git a/src/extensions/lens-renderer-extension.ts b/src/extensions/lens-renderer-extension.ts index 0ae8a44323..b56ffb3d7e 100644 --- a/src/extensions/lens-renderer-extension.ts +++ b/src/extensions/lens-renderer-extension.ts @@ -21,9 +21,11 @@ import type * as registries from "./registries"; import type { Cluster } from "../main/cluster"; -import { LensExtension } from "./lens-extension"; +import { Disposers, LensExtension } from "./lens-extension"; import { getExtensionPageUrl } from "./registries/page-registry"; import type { CatalogEntity } from "../common/catalog"; +import type { Disposer } from "../common/utils"; +import { catalogEntityRegistry, EntityFilter } from "../renderer/api/catalog-entity-registry"; export class LensRendererExtension extends LensExtension { globalPages: registries.PageRegistration[] = []; @@ -59,4 +61,17 @@ export class LensRendererExtension extends LensExtension { async isEnabledForCluster(cluster: Cluster): Promise { return (void cluster) || true; } + + /** + * Add a filtering function for the catalog. This will be removed if the extension is disabled. + * @param fn The function which should return a truthy value for those entities which should be kepted + * @returns A function to clean up the filter + */ + addCatalogFilter(fn: EntityFilter): Disposer { + const dispose = catalogEntityRegistry.addCatalogFilter(fn); + + this[Disposers].push(dispose); + + return dispose; + } } diff --git a/src/main/catalog/catalog-entity-registry.ts b/src/main/catalog/catalog-entity-registry.ts index f2188132eb..e9e441ae2b 100644 --- a/src/main/catalog/catalog-entity-registry.ts +++ b/src/main/catalog/catalog-entity-registry.ts @@ -43,24 +43,20 @@ export class CatalogEntityRegistry { } @computed get items(): CatalogEntity[] { - const allItems = Array.from(iter.flatMap(this.sources.values(), source => source.get())); - - return allItems.filter((entity) => this.categoryRegistry.getCategoryForEntity(entity) !== undefined); + return Array.from( + iter.filter( + iter.flatMap(this.sources.values(), source => source.get()), + entity => this.categoryRegistry.getCategoryForEntity(entity) + ) + ); } getById(id: string): T | undefined { - const item = this.items.find((entity) => entity.metadata.uid === id); - - if (item) return item as T; - - - return undefined; + return this.items.find((entity) => entity.metadata.uid === id) as T | undefined; } getItemsForApiKind(apiVersion: string, kind: string): T[] { - const items = this.items.filter((item) => item.apiVersion === apiVersion && item.kind === kind); - - return items as T[]; + return this.items.filter((item) => item.apiVersion === apiVersion && item.kind === kind) as T[]; } getItemsByEntityClass({ apiVersion, kind }: CatalogEntityKindData): T[] { diff --git a/src/renderer/api/__tests__/catalog-entity-registry.test.ts b/src/renderer/api/__tests__/catalog-entity-registry.test.ts index 4c3bcb48c3..527cb4d328 100644 --- a/src/renderer/api/__tests__/catalog-entity-registry.test.ts +++ b/src/renderer/api/__tests__/catalog-entity-registry.test.ts @@ -23,7 +23,8 @@ import { CatalogEntityRegistry } from "../catalog-entity-registry"; import "../../../common/catalog-entities"; import { catalogCategoryRegistry } from "../../../common/catalog/catalog-category-registry"; import { CatalogCategory, CatalogEntityData, CatalogEntityKindData } from "../catalog-entity"; -import { WebLink } from "../../../common/catalog-entities"; +import { KubernetesCluster, WebLink } from "../../../common/catalog-entities"; +import { observable } from "mobx"; class TestCatalogEntityRegistry extends CatalogEntityRegistry { replaceItems(items: Array) { @@ -51,6 +52,49 @@ class FooBarCategory extends CatalogCategory { } }; } +const entity = new WebLink({ + metadata: { + uid: "test", + name: "test-link", + source: "test", + labels: {} + }, + spec: { + url: "https://k8slens.dev" + }, + status: { + phase: "available" + } +}); +const entity2 = new WebLink({ + metadata: { + uid: "test2", + name: "test-link", + source: "test", + labels: {} + }, + spec: { + url: "https://k8slens.dev" + }, + status: { + phase: "available" + } +}); +const entitykc = new KubernetesCluster({ + metadata: { + uid: "test3", + name: "test-link", + source: "test", + labels: {} + }, + spec: { + kubeconfigPath: "", + kubeconfigContext: "", + }, + status: { + phase: "connected" + } +}); describe("CatalogEntityRegistry", () => { describe("updateItems", () => { @@ -250,4 +294,25 @@ describe("CatalogEntityRegistry", () => { catalogCategoryRegistry.add(new FooBarCategory()); expect(catalog.items.length).toBe(1); }); + + it("does not return items that are filtered out", () => { + const source = observable.array([entity, entity2, entitykc]); + const catalog = new TestCatalogEntityRegistry(catalogCategoryRegistry); + + catalog.replaceItems(source); + + expect(catalog.items.length).toBe(3); + expect(catalog.filteredItems.length).toBe(3); + + const d = catalog.addCatalogFilter(entity => entity.kind === KubernetesCluster.kind); + + expect(catalog.items.length).toBe(3); + expect(catalog.filteredItems.length).toBe(1); + + // Remove filter + d(); + + expect(catalog.items.length).toBe(3); + expect(catalog.filteredItems.length).toBe(3); + }); }); diff --git a/src/renderer/api/catalog-entity-registry.ts b/src/renderer/api/catalog-entity-registry.ts index a067b520d7..7b09ff273b 100644 --- a/src/renderer/api/catalog-entity-registry.ts +++ b/src/renderer/api/catalog-entity-registry.ts @@ -25,10 +25,17 @@ import { CatalogCategory, CatalogEntity, CatalogEntityData, catalogCategoryRegis import "../../common/catalog-entities"; import type { Cluster } from "../../main/cluster"; import { ClusterStore } from "../../common/cluster-store"; +import { Disposer, iter } from "../utils"; +import { once } from "lodash"; + +export type EntityFilter = (entity: CatalogEntity) => any; export class CatalogEntityRegistry { @observable.ref activeEntity: CatalogEntity; protected _entities = observable.map([], { deep: true }); + protected filters = observable.set([], { + deep: false, + }); /** * Buffer for keeping entities that don't yet have CatalogCategory synced @@ -95,27 +102,56 @@ export class CatalogEntityRegistry { return Array.from(this._entities.values()); } - @computed get entities(): Map { - this.processRawEntities(); + @computed get filteredItems() { + return Array.from( + iter.reduce( + this.filters, + iter.filter, + this.items, + ) + ); + } - return this._entities; + @computed get entities(): Map { + return new Map( + this.items.map(entity => [entity.getId(), entity]) + ); + } + + @computed get filteredEntities(): Map { + return new Map( + this.filteredItems.map(entity => [entity.getId(), entity]) + ); } getById(id: string) { return this.entities.get(id) as T; } - getItemsForApiKind(apiVersion: string, kind: string): T[] { - const items = this.items.filter((item) => item.apiVersion === apiVersion && item.kind === kind); + getItemsForApiKind(apiVersion: string, kind: string, { filtered = false } = {}): T[] { + const byApiKind = (item: CatalogEntity) => item.apiVersion === apiVersion && item.kind === kind; + const entities = filtered ? this.filteredItems : this.items; - return items as T[]; + return entities.filter(byApiKind) as T[]; } - getItemsForCategory(category: CatalogCategory): T[] { - const supportedVersions = category.spec.versions.map((v) => `${category.spec.group}/${v.name}`); - const items = this.items.filter((item) => supportedVersions.includes(item.apiVersion) && item.kind === category.spec.names.kind); + getItemsForCategory(category: CatalogCategory, { filtered = false } = {}): T[] { + const supportedVersions = new Set(category.spec.versions.map((v) => `${category.spec.group}/${v.name}`)); + const byApiVersionKind = (item: CatalogEntity) => supportedVersions.has(item.apiVersion) && item.kind === category.spec.names.kind; + const entities = filtered ? this.filteredItems : this.items; - return items as T[]; + return entities.filter(byApiVersionKind) as T[]; + } + + /** + * Add a new filter to the set of item filters + * @param fn The function that should return a truthy value if that entity should be sent currently "active" + * @returns A function to remove that filter + */ + addCatalogFilter(fn: EntityFilter): Disposer { + this.filters.add(fn); + + return once(() => void this.filters.delete(fn)); } } diff --git a/src/renderer/components/+catalog/catalog-entity.store.tsx b/src/renderer/components/+catalog/catalog-entity.store.tsx index c5bb96e5f2..05f317b7b1 100644 --- a/src/renderer/components/+catalog/catalog-entity.store.tsx +++ b/src/renderer/components/+catalog/catalog-entity.store.tsx @@ -129,10 +129,10 @@ export class CatalogEntityStore extends ItemStore new CatalogEntityItem(entity)); + return catalogEntityRegistry.filteredItems.map(entity => new CatalogEntityItem(entity)); } - return catalogEntityRegistry.getItemsForCategory(this.activeCategory).map(entity => new CatalogEntityItem(entity)); + return catalogEntityRegistry.getItemsForCategory(this.activeCategory, { filtered: true }).map(entity => new CatalogEntityItem(entity)); } @computed get selectedItem() { diff --git a/src/renderer/components/hotbar/hotbar-menu.tsx b/src/renderer/components/hotbar/hotbar-menu.tsx index 5df1f48049..cc2c1903c0 100644 --- a/src/renderer/components/hotbar/hotbar-menu.tsx +++ b/src/renderer/components/hotbar/hotbar-menu.tsx @@ -52,7 +52,7 @@ export class HotbarMenu extends React.Component { return null; } - return item ? catalogEntityRegistry.items.find((entity) => entity.metadata.uid === item.entity.uid) : null; + return catalogEntityRegistry.getById(item?.entity.uid) ?? null; } onDragEnd(result: DropResult) { From 36b64f73bcfa5cddd47808b1d235fc630c83ea81 Mon Sep 17 00:00:00 2001 From: Lauri Nevala Date: Wed, 1 Sep 2021 12:44:13 +0300 Subject: [PATCH 09/15] Ignore clusters without kubeconfigPath on kubeconfig sync migration (#3707) Signed-off-by: Lauri Nevala --- src/migrations/user-store/5.0.3-beta.1.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/migrations/user-store/5.0.3-beta.1.ts b/src/migrations/user-store/5.0.3-beta.1.ts index 728cf6a395..05a1767f08 100644 --- a/src/migrations/user-store/5.0.3-beta.1.ts +++ b/src/migrations/user-store/5.0.3-beta.1.ts @@ -40,6 +40,9 @@ export default { syncPaths.add(path.join(os.homedir(), ".kube")); for (const cluster of clusters) { + if (!cluster.kubeConfigPath) { + continue; + } const dirOfKubeconfig = path.dirname(cluster.kubeConfigPath); if (dirOfKubeconfig === storedKubeConfigFolder()) { From d132a4c7e72a31a566882359789669ddff4417eb Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 1 Sep 2021 05:49:00 -0400 Subject: [PATCH 10/15] Fix node shell secret pulling (#3668) - On some KE errors are thrown if trying to get a secret with an empty name, instead of just ignoring the entry - Clean up the node shell settings Signed-off-by: Sebastian Malton --- src/main/cluster.ts | 6 +- src/main/shell-session/node-shell-session.ts | 15 ++-- .../components/cluster-node-shell-setting.tsx | 81 +++++++++---------- 3 files changed, 50 insertions(+), 52 deletions(-) diff --git a/src/main/cluster.ts b/src/main/cluster.ts index 319f2d23df..0dbf32e440 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -706,10 +706,10 @@ export class Cluster implements ClusterModel, ClusterState { } get nodeShellImage(): string { - return this.preferences.nodeShellImage || initialNodeShellImage; + return this.preferences?.nodeShellImage || initialNodeShellImage; } - get imagePullSecret(): string { - return this.preferences.imagePullSecret || ""; + get imagePullSecret(): string | undefined { + return this.preferences?.imagePullSecret; } } diff --git a/src/main/shell-session/node-shell-session.ts b/src/main/shell-session/node-shell-session.ts index aa8c14ba9b..5f36e1d2f0 100644 --- a/src/main/shell-session/node-shell-session.ts +++ b/src/main/shell-session/node-shell-session.ts @@ -25,6 +25,7 @@ import * as k8s from "@kubernetes/client-node"; import type { KubeConfig } from "@kubernetes/client-node"; import type { Cluster } from "../cluster"; import { ShellOpenError, ShellSession } from "./shell-session"; +import { get } from "lodash"; export class NodeShellSession extends ShellSession { ShellType = "node-shell"; @@ -49,7 +50,7 @@ export class NodeShellSession extends ShellSession { await this.waitForRunningPod(); } catch (error) { this.deleteNodeShellPod(); - this.sendResponse("Error occurred. "); + this.sendResponse(`Error occurred: ${get(error, "response.body.message", error?.toString() || "unknown error")}`); throw new ShellOpenError("failed to create node pod", error); } @@ -57,10 +58,16 @@ export class NodeShellSession extends ShellSession { const args = ["exec", "-i", "-t", "-n", "kube-system", this.podId, "--", "sh", "-c", "((clear && bash) || (clear && ash) || (clear && sh))"]; const env = await this.getCachedShellEnv(); - super.open(shell, args, env); + await super.open(shell, args, env); } protected createNodeShellPod() { + const imagePullSecrets = this.cluster.imagePullSecret + ? [{ + name: this.cluster.imagePullSecret, + }] + : undefined; + return this .kc .makeApiClient(k8s.CoreV1Api) @@ -88,9 +95,7 @@ export class NodeShellSession extends ShellSession { command: ["nsenter"], args: ["-t", "1", "-m", "-u", "-i", "-n", "sleep", "14000"] }], - imagePullSecrets: [{ - name: this.cluster.imagePullSecret, - }] + imagePullSecrets, } }); } diff --git a/src/renderer/components/cluster-settings/components/cluster-node-shell-setting.tsx b/src/renderer/components/cluster-settings/components/cluster-node-shell-setting.tsx index 1fb101a15c..58c86f1f89 100644 --- a/src/renderer/components/cluster-settings/components/cluster-node-shell-setting.tsx +++ b/src/renderer/components/cluster-settings/components/cluster-node-shell-setting.tsx @@ -20,11 +20,11 @@ */ import type { Cluster } from "../../../../main/cluster"; -import { autorun, makeObservable, observable } from "mobx"; +import { makeObservable, observable } from "mobx"; import { SubTitle } from "../../layout/sub-title"; import React from "react"; import { Input } from "../../input/input"; -import { disposeOnUnmount, observer } from "mobx-react"; +import { observer } from "mobx-react"; import { Icon } from "../../icon/icon"; import { initialNodeShellImage } from "../../../../common/cluster-types"; @@ -34,59 +34,42 @@ interface Props { @observer export class ClusterNodeShellSetting extends React.Component { - @observable nodeShellImage = ""; - @observable imagePullSecret = ""; + @observable nodeShellImage = this.props.cluster.preferences?.nodeShellImage || ""; + @observable imagePullSecret = this.props.cluster.preferences?.imagePullSecret || ""; constructor(props: Props) { super(props); makeObservable(this); } - componentDidMount() { - disposeOnUnmount(this, - autorun(() => { - this.nodeShellImage = this.props.cluster.nodeShellImage; - this.imagePullSecret = this.props.cluster.imagePullSecret; - }) - ); + componentWillUnmount() { + this.props.cluster.preferences ??= {}; + this.props.cluster.preferences.nodeShellImage = this.nodeShellImage || undefined; + this.props.cluster.preferences.imagePullSecret = this.imagePullSecret || undefined; } - onImageChange = (value: string) => { - this.nodeShellImage = value; - }; - - onSecretChange = (value: string) => { - this.imagePullSecret = value; - }; - - saveImage = () => { - this.props.cluster.preferences.nodeShellImage = this.nodeShellImage; - }; - - saveSecret = () => { - this.props.cluster.preferences.imagePullSecret = this.imagePullSecret; - }; - - resetImage = () => { - this.nodeShellImage = initialNodeShellImage; //revert to default - }; - - clearSecret = () => { - this.imagePullSecret = ""; - }; - render() { - return ( <>
} + onChange={value => this.nodeShellImage = value} + iconRight={ + this.nodeShellImage + ? ( + this.nodeShellImage = ""} + tooltip="Reset" + /> + ) + : undefined + } /> Node shell image. Used for creating node shell pod. @@ -95,15 +78,25 @@ export class ClusterNodeShellSetting extends React.Component {
} + onChange={value => this.imagePullSecret = value} + iconRight={ + this.imagePullSecret + ? ( + this.imagePullSecret = ""} + tooltip="Clear" + /> + ) + : undefined + } /> - Name of a pre-existing secret (optional). Used for pulling image from a private registry. + Name of a pre-existing secret. An optional setting. Used for pulling image from a private registry.
From 1f7cdcdb0109b254b1e3546407f8917038556924 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 12:49:35 +0300 Subject: [PATCH 11/15] Bump dompurify from 2.0.17 to 2.3.1 (#3661) Bumps [dompurify](https://github.com/cure53/DOMPurify) from 2.0.17 to 2.3.1. - [Release notes](https://github.com/cure53/DOMPurify/releases) - [Commits](https://github.com/cure53/DOMPurify/compare/2.0.17...2.3.1) --- updated-dependencies: - dependency-name: dompurify dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 4acccdd50c..7a2aeead37 100644 --- a/package.json +++ b/package.json @@ -325,7 +325,7 @@ "concurrently": "^5.2.0", "css-loader": "^5.2.6", "deepdash": "^5.3.5", - "dompurify": "^2.0.17", + "dompurify": "^2.3.1", "electron": "^12.0.17", "electron-builder": "^22.10.5", "electron-notarize": "^0.3.0", diff --git a/yarn.lock b/yarn.lock index 92d33c4162..8c2d69e208 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5060,10 +5060,10 @@ domhandler@^2.3.0: dependencies: domelementtype "1" -dompurify@^2.0.17: - version "2.0.17" - resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.0.17.tgz#505ffa126a580603df4007e034bdc9b6b738668e" - integrity sha512-nNwwJfW55r8akD8MSFz6k75bzyT2y6JEa1O3JrZFBf+Y5R9JXXU4OsRl0B9hKoPgHTw2b7ER5yJ5Md97MMUJPg== +dompurify@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.1.tgz#a47059ca21fd1212d3c8f71fdea6943b8bfbdf6a" + integrity sha512-xGWt+NHAQS+4tpgbOAI08yxW0Pr256Gu/FNE2frZVTbgrBUn8M7tz7/ktS/LZ2MHeGqz6topj0/xY+y8R5FBFw== domutils@1.5.1: version "1.5.1" From 584d45c5e0477f0d9b823cd381a83e6b14eac3e3 Mon Sep 17 00:00:00 2001 From: Lauri Nevala Date: Wed, 1 Sep 2021 12:50:11 +0300 Subject: [PATCH 12/15] Allow to configure default namespace used in terminal (#3706) * Allow to configure default namespace used in terminal Signed-off-by: Lauri Nevala * Fix lint issues Signed-off-by: Lauri Nevala --- src/common/cluster-types.ts | 1 + src/main/cluster.ts | 27 ++++++++ src/main/kubeconfig-manager.ts | 11 +++- .../components/cluster-home-dir-setting.tsx | 63 ++++++++++++++----- 4 files changed, 86 insertions(+), 16 deletions(-) diff --git a/src/common/cluster-types.ts b/src/common/cluster-types.ts index 705110b895..cdd498a419 100644 --- a/src/common/cluster-types.ts +++ b/src/common/cluster-types.ts @@ -95,6 +95,7 @@ export interface ClusterPreferences extends ClusterPrometheusPreferences { hiddenMetrics?: string[]; nodeShellImage?: string; imagePullSecret?: string; + defaultNamespace?: string; } /** diff --git a/src/main/cluster.ts b/src/main/cluster.ts index 0dbf32e440..c3673e8a91 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -216,6 +216,18 @@ export class Cluster implements ClusterModel, ClusterState { return toJS({ prometheus, prometheusProvider }); } + /** + * defaultNamespace preference + * + * @computed + * @internal + */ + @computed get defaultNamespace(): string { + const { defaultNamespace } = this.preferences; + + return defaultNamespace; + } + constructor(model: ClusterModel) { makeObservable(this); this.id = model.id; @@ -298,10 +310,25 @@ export class Cluster implements ClusterModel, ClusterState { clearInterval(refreshTimer); clearInterval(refreshMetadataTimer); }, + reaction(() => this.defaultNamespace, () => this.recreateProxyKubeconfig()), ); } } + /** + * @internal + */ + async recreateProxyKubeconfig() { + logger.info("Recreate proxy kubeconfig"); + + try { + this.kubeconfigManager.clear(); + } catch { + // do nothing + } + this.getProxyKubeconfig(); + } + /** * internal */ diff --git a/src/main/kubeconfig-manager.ts b/src/main/kubeconfig-manager.ts index ab53118f60..c9b101d59f 100644 --- a/src/main/kubeconfig-manager.ts +++ b/src/main/kubeconfig-manager.ts @@ -56,6 +56,15 @@ export class KubeconfigManager { return this.tempFile; } + async clear() { + if (!this.tempFile) { + return; + } + + logger.info(`Deleting temporary kubeconfig: ${this.tempFile}`); + await fs.unlink(this.tempFile); + } + async unlink() { if (!this.tempFile) { return; @@ -106,7 +115,7 @@ export class KubeconfigManager { user: "proxy", name: contextName, cluster: contextName, - namespace: kubeConfig.getContextObject(contextName).namespace, + namespace: cluster.defaultNamespace || kubeConfig.getContextObject(contextName).namespace, } ] }; diff --git a/src/renderer/components/cluster-settings/components/cluster-home-dir-setting.tsx b/src/renderer/components/cluster-settings/components/cluster-home-dir-setting.tsx index 55abaf5dc6..550c5d9568 100644 --- a/src/renderer/components/cluster-settings/components/cluster-home-dir-setting.tsx +++ b/src/renderer/components/cluster-settings/components/cluster-home-dir-setting.tsx @@ -33,43 +33,76 @@ interface Props { @observer export class ClusterHomeDirSetting extends React.Component { @observable directory = ""; + @observable defaultNamespace = ""; constructor(props: Props) { super(props); makeObservable(this); } - componentDidMount() { + async componentDidMount() { + const kubeconfig = await this.props.cluster.getKubeconfig(); + + const defaultNamespace = this.props.cluster.preferences?.defaultNamespace || kubeconfig.getContextObject(this.props.cluster.contextName).namespace; + disposeOnUnmount(this, autorun(() => { this.directory = this.props.cluster.preferences.terminalCWD || ""; + this.defaultNamespace = defaultNamespace || ""; }) ); } - save = () => { + saveCWD = () => { this.props.cluster.preferences.terminalCWD = this.directory; }; - onChange = (value: string) => { + onChangeTerminalCWD = (value: string) => { this.directory = value; }; + saveDefaultNamespace = () => { + if (this.defaultNamespace) { + this.props.cluster.preferences.defaultNamespace = this.defaultNamespace; + } else { + this.props.cluster.preferences.defaultNamespace = undefined; + } + }; + + onChangeDefaultNamespace = (value: string) => { + this.defaultNamespace = value; + }; + render() { return ( <> - - - - An explicit start path where the terminal will be launched,{" "} - this is used as the current working directory (cwd) for the shell process. - +
+ + + + An explicit start path where the terminal will be launched,{" "} + this is used as the current working directory (cwd) for the shell process. + +
+
+ + + + Default namespace used for kubectl. + +
); } From 41fcd73c69894734d3195bccacd1d749b11f9cc9 Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Wed, 1 Sep 2021 13:15:38 +0300 Subject: [PATCH 13/15] expose logger to extensions (#3708) Signed-off-by: Jari Kolehmainen --- src/extensions/common-api/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/extensions/common-api/index.ts b/src/extensions/common-api/index.ts index c0688dae25..9fdf3a837b 100644 --- a/src/extensions/common-api/index.ts +++ b/src/extensions/common-api/index.ts @@ -26,6 +26,7 @@ import * as Store from "./stores"; import * as Util from "./utils"; import * as Catalog from "./catalog"; import * as Types from "./types"; +import logger from "../../common/logger"; export { App, @@ -34,4 +35,5 @@ export { Store, Types, Util, + logger }; From 776a15e54e42eb696c5e20efa1e811b68b4cbf28 Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Wed, 1 Sep 2021 13:15:58 +0300 Subject: [PATCH 14/15] fix bundling of helm on linux/windows (#3705) Signed-off-by: Jari Kolehmainen --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 7a2aeead37..fa32645865 100644 --- a/package.json +++ b/package.json @@ -125,7 +125,7 @@ "to": "./${arch}/kubectl" }, { - "from": "binaries/client/helm3/helm3", + "from": "binaries/client/${arch}/helm3/helm3", "to": "./helm3/helm3" } ] @@ -160,7 +160,7 @@ "to": "./ia32/kubectl.exe" }, { - "from": "binaries/client/helm3/helm3.exe", + "from": "binaries/client/x64/helm3/helm3.exe", "to": "./helm3/helm3.exe" } ] From edee99a031135ccdde043adfe87fdcbde99a436f Mon Sep 17 00:00:00 2001 From: Jim Ehrismann <40840436+jim-docker@users.noreply.github.com> Date: Wed, 1 Sep 2021 07:58:43 -0400 Subject: [PATCH 15/15] release v5.2.0-beta.3 (#3691) * release v5.2.0-beta.3 Signed-off-by: Jim Ehrismann * '-' is an invalid character for azure job name Signed-off-by: Jim Ehrismann * use newer vmImage for mac azure job so mac arm64 build works Signed-off-by: Jim Ehrismann * use newerer vmImage for mac azure job so mac arm64 build works Signed-off-by: Jim Ehrismann * fix merge conflict while cherry-picking commit 9d6bed8786 Signed-off-by: Jim Ehrismann Build and release amd64 & arm64 together (macOS) (#3700) * build and release amd64 & arm64 together Signed-off-by: Jari Kolehmainen * fixes Signed-off-by: Jari Kolehmainen Co-authored-by: Jari Kolehmainen --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fa32645865..181b7f3753 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "productName": "OpenLens", "description": "OpenLens - Open Source IDE for Kubernetes", "homepage": "https://github.com/lensapp/lens", - "version": "5.2.0-beta.2", + "version": "5.2.0-beta.3", "main": "static/build/main.js", "copyright": "© 2021 OpenLens Authors", "license": "MIT",