mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Fix: deprecated helm chart filtering (#2158)
* Refactor of excludeDeprecated helm service method Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Pick first helm chart from the list on load Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Removing helm filtering in UI Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Cleaning up Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Cleaning up type definitions Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Adding sorting charts by version Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Adding tests for methods that manipute chart listing Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Cleaning up tests a bit Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com> * Adding semver coercion before comparing versions Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
This commit is contained in:
parent
103467d31b
commit
6876d774a5
108
src/main/helm/__mocks__/helm-chart-manager.ts
Normal file
108
src/main/helm/__mocks__/helm-chart-manager.ts
Normal file
@ -0,0 +1,108 @@
|
||||
import { HelmRepo, HelmRepoManager } from "../helm-repo-manager";
|
||||
|
||||
export class HelmChartManager {
|
||||
private cache: any = {};
|
||||
private repo: HelmRepo;
|
||||
|
||||
constructor(repo: HelmRepo){
|
||||
this.cache = HelmRepoManager.cache;
|
||||
this.repo = repo;
|
||||
}
|
||||
|
||||
public async charts(): Promise<any> {
|
||||
switch (this.repo.name) {
|
||||
case "stable":
|
||||
return Promise.resolve({
|
||||
"apm-server": [
|
||||
{
|
||||
apiVersion: "3.0.0",
|
||||
name: "apm-server",
|
||||
version: "2.1.7",
|
||||
repo: "stable",
|
||||
digest: "test"
|
||||
},
|
||||
{
|
||||
apiVersion: "3.0.0",
|
||||
name: "apm-server",
|
||||
version: "2.1.6",
|
||||
repo: "stable",
|
||||
digest: "test"
|
||||
}
|
||||
],
|
||||
"redis": [
|
||||
{
|
||||
apiVersion: "3.0.0",
|
||||
name: "apm-server",
|
||||
version: "1.0.0",
|
||||
repo: "stable",
|
||||
digest: "test"
|
||||
},
|
||||
{
|
||||
apiVersion: "3.0.0",
|
||||
name: "apm-server",
|
||||
version: "0.0.9",
|
||||
repo: "stable",
|
||||
digest: "test"
|
||||
}
|
||||
]
|
||||
});
|
||||
case "experiment":
|
||||
return Promise.resolve({
|
||||
"fairwind": [
|
||||
{
|
||||
apiVersion: "3.0.0",
|
||||
name: "fairwind",
|
||||
version: "0.0.1",
|
||||
repo: "experiment",
|
||||
digest: "test"
|
||||
},
|
||||
{
|
||||
apiVersion: "3.0.0",
|
||||
name: "fairwind",
|
||||
version: "0.0.2",
|
||||
repo: "experiment",
|
||||
digest: "test",
|
||||
deprecated: true
|
||||
}
|
||||
]
|
||||
});
|
||||
case "bitnami":
|
||||
return Promise.resolve({
|
||||
"hotdog": [
|
||||
{
|
||||
apiVersion: "3.0.0",
|
||||
name: "hotdog",
|
||||
version: "1.0.1",
|
||||
repo: "bitnami",
|
||||
digest: "test"
|
||||
},
|
||||
{
|
||||
apiVersion: "3.0.0",
|
||||
name: "hotdog",
|
||||
version: "1.0.2",
|
||||
repo: "bitnami",
|
||||
digest: "test",
|
||||
}
|
||||
],
|
||||
"pretzel": [
|
||||
{
|
||||
apiVersion: "3.0.0",
|
||||
name: "pretzel",
|
||||
version: "1.0",
|
||||
repo: "bitnami",
|
||||
digest: "test",
|
||||
},
|
||||
{
|
||||
apiVersion: "3.0.0",
|
||||
name: "pretzel",
|
||||
version: "1.0.1",
|
||||
repo: "bitnami",
|
||||
digest: "test"
|
||||
}
|
||||
]
|
||||
});
|
||||
default:
|
||||
return Promise.resolve({});
|
||||
}
|
||||
}
|
||||
}
|
||||
104
src/main/helm/__tests__/helm-service.test.ts
Normal file
104
src/main/helm/__tests__/helm-service.test.ts
Normal file
@ -0,0 +1,104 @@
|
||||
import { helmService } from "../helm-service";
|
||||
import { repoManager } from "../helm-repo-manager";
|
||||
|
||||
jest.spyOn(repoManager, "init").mockImplementation();
|
||||
|
||||
jest.mock("../helm-chart-manager");
|
||||
|
||||
describe("Helm Service tests", () => {
|
||||
test("list charts without deprecated ones", async () => {
|
||||
jest.spyOn(repoManager, "repositories").mockImplementation(async () => {
|
||||
return [
|
||||
{ name: "stable", url: "stableurl" },
|
||||
{ name: "experiment", url: "experimenturl" }
|
||||
];
|
||||
});
|
||||
|
||||
const charts = await helmService.listCharts();
|
||||
|
||||
expect(charts).toEqual({
|
||||
stable: {
|
||||
"apm-server": [
|
||||
{
|
||||
apiVersion: "3.0.0",
|
||||
name: "apm-server",
|
||||
version: "2.1.7",
|
||||
repo: "stable",
|
||||
digest: "test"
|
||||
},
|
||||
{
|
||||
apiVersion: "3.0.0",
|
||||
name: "apm-server",
|
||||
version: "2.1.6",
|
||||
repo: "stable",
|
||||
digest: "test"
|
||||
}
|
||||
],
|
||||
"redis": [
|
||||
{
|
||||
apiVersion: "3.0.0",
|
||||
name: "apm-server",
|
||||
version: "1.0.0",
|
||||
repo: "stable",
|
||||
digest: "test"
|
||||
},
|
||||
{
|
||||
apiVersion: "3.0.0",
|
||||
name: "apm-server",
|
||||
version: "0.0.9",
|
||||
repo: "stable",
|
||||
digest: "test"
|
||||
}
|
||||
]
|
||||
},
|
||||
experiment: {}
|
||||
});
|
||||
});
|
||||
|
||||
test("list charts sorted by version in descending order", async () => {
|
||||
jest.spyOn(repoManager, "repositories").mockImplementation(async () => {
|
||||
return [
|
||||
{ name: "bitnami", url: "bitnamiurl" }
|
||||
];
|
||||
});
|
||||
|
||||
const charts = await helmService.listCharts();
|
||||
|
||||
expect(charts).toEqual({
|
||||
bitnami: {
|
||||
"hotdog": [
|
||||
{
|
||||
apiVersion: "3.0.0",
|
||||
name: "hotdog",
|
||||
version: "1.0.2",
|
||||
repo: "bitnami",
|
||||
digest: "test",
|
||||
},
|
||||
{
|
||||
apiVersion: "3.0.0",
|
||||
name: "hotdog",
|
||||
version: "1.0.1",
|
||||
repo: "bitnami",
|
||||
digest: "test"
|
||||
},
|
||||
],
|
||||
"pretzel": [
|
||||
{
|
||||
apiVersion: "3.0.0",
|
||||
name: "pretzel",
|
||||
version: "1.0.1",
|
||||
repo: "bitnami",
|
||||
digest: "test",
|
||||
},
|
||||
{
|
||||
apiVersion: "3.0.0",
|
||||
name: "pretzel",
|
||||
version: "1.0",
|
||||
repo: "bitnami",
|
||||
digest: "test"
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -4,9 +4,10 @@ import { HelmRepo, HelmRepoManager } from "./helm-repo-manager";
|
||||
import logger from "../logger";
|
||||
import { promiseExec } from "../promise-exec";
|
||||
import { helmCli } from "./helm-cli";
|
||||
import type { RepoHelmChartList } from "../../renderer/api/endpoints/helm-charts.api";
|
||||
|
||||
type CachedYaml = {
|
||||
entries: any; // todo: types
|
||||
entries: RepoHelmChartList
|
||||
};
|
||||
|
||||
export class HelmChartManager {
|
||||
@ -24,15 +25,15 @@ export class HelmChartManager {
|
||||
return charts[name];
|
||||
}
|
||||
|
||||
public async charts(): Promise<any> {
|
||||
public async charts(): Promise<RepoHelmChartList> {
|
||||
try {
|
||||
const cachedYaml = await this.cachedYaml();
|
||||
|
||||
return cachedYaml["entries"];
|
||||
} catch(error) {
|
||||
logger.error(error);
|
||||
logger.error("HELM-CHART-MANAGER]: failed to list charts", { error });
|
||||
|
||||
return [];
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import semver from "semver";
|
||||
import { Cluster } from "../cluster";
|
||||
import logger from "../logger";
|
||||
import { repoManager } from "./helm-repo-manager";
|
||||
import { HelmChartManager } from "./helm-chart-manager";
|
||||
import { releaseManager } from "./helm-release-manager";
|
||||
import { HelmChartList, RepoHelmChartList } from "../../renderer/api/endpoints/helm-charts.api";
|
||||
|
||||
class HelmService {
|
||||
public async installChart(cluster: Cluster, data: { chart: string; values: {}; name: string; namespace: string; version: string }) {
|
||||
@ -10,7 +12,7 @@ class HelmService {
|
||||
}
|
||||
|
||||
public async listCharts() {
|
||||
const charts: any = {};
|
||||
const charts: HelmChartList = {};
|
||||
|
||||
await repoManager.init();
|
||||
const repositories = await repoManager.repositories();
|
||||
@ -18,14 +20,10 @@ class HelmService {
|
||||
for (const repo of repositories) {
|
||||
charts[repo.name] = {};
|
||||
const manager = new HelmChartManager(repo);
|
||||
let entries = await manager.charts();
|
||||
const sortedCharts = this.sortChartsByVersion(await manager.charts());
|
||||
const enabledCharts = this.excludeDeprecatedChartGroups(sortedCharts);
|
||||
|
||||
entries = this.excludeDeprecated(entries);
|
||||
|
||||
for (const key in entries) {
|
||||
entries[key] = entries[key][0];
|
||||
}
|
||||
charts[repo.name] = entries;
|
||||
charts[repo.name] = enabledCharts;
|
||||
}
|
||||
|
||||
return charts;
|
||||
@ -96,20 +94,30 @@ class HelmService {
|
||||
return { message: output };
|
||||
}
|
||||
|
||||
protected excludeDeprecated(entries: any) {
|
||||
for (const key in entries) {
|
||||
entries[key] = entries[key].filter((entry: any) => {
|
||||
if (Array.isArray(entry)) {
|
||||
return entry[0]["deprecated"] != true;
|
||||
}
|
||||
private excludeDeprecatedChartGroups(chartGroups: RepoHelmChartList) {
|
||||
const groups = new Map(Object.entries(chartGroups));
|
||||
|
||||
return entry["deprecated"] != true;
|
||||
for (const [chartName, charts] of groups) {
|
||||
if (charts[0].deprecated) {
|
||||
groups.delete(chartName);
|
||||
}
|
||||
}
|
||||
|
||||
return Object.fromEntries(groups);
|
||||
}
|
||||
|
||||
private sortChartsByVersion(chartGroups: RepoHelmChartList) {
|
||||
for (const key in chartGroups) {
|
||||
chartGroups[key] = chartGroups[key].sort((first, second) => {
|
||||
const firstVersion = semver.coerce(first.version || 0);
|
||||
const secondVersion = semver.coerce(second.version || 0);
|
||||
|
||||
return semver.compare(secondVersion, firstVersion);
|
||||
});
|
||||
}
|
||||
|
||||
return entries;
|
||||
return chartGroups;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const helmService = new HelmService();
|
||||
|
||||
@ -3,11 +3,8 @@ import { apiBase } from "../index";
|
||||
import { stringify } from "querystring";
|
||||
import { autobind } from "../../utils";
|
||||
|
||||
interface IHelmChartList {
|
||||
[repo: string]: {
|
||||
[name: string]: HelmChart;
|
||||
};
|
||||
}
|
||||
export type RepoHelmChartList = Record<string, HelmChart[]>;
|
||||
export type HelmChartList = Record<string, RepoHelmChartList>;
|
||||
|
||||
export interface IHelmChartDetails {
|
||||
readme: string;
|
||||
@ -22,12 +19,12 @@ const endpoint = compile(`/v2/charts/:repo?/:name?`) as (params?: {
|
||||
export const helmChartsApi = {
|
||||
list() {
|
||||
return apiBase
|
||||
.get<IHelmChartList>(endpoint())
|
||||
.get<HelmChartList>(endpoint())
|
||||
.then(data => {
|
||||
return Object
|
||||
.values(data)
|
||||
.reduce((allCharts, repoCharts) => allCharts.concat(Object.values(repoCharts)), [])
|
||||
.map(HelmChart.create);
|
||||
.map(([chart]) => HelmChart.create(chart));
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@ -72,9 +72,6 @@ export class HelmCharts extends Component<Props> {
|
||||
(chart: HelmChart) => chart.getAppVersion(),
|
||||
(chart: HelmChart) => chart.getKeywords(),
|
||||
]}
|
||||
filterItems={[
|
||||
(items: HelmChart[]) => items.filter(item => !item.deprecated)
|
||||
]}
|
||||
customizeHeader={() => (
|
||||
<SearchInputUrl placeholder="Search Helm Charts" />
|
||||
)}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user