Skip to content
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Lint
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 'lts/*'
- uses: pnpm/action-setup@v4
- name: Install dependencies
run: pnpm install

- name: Run Lint Check
run: npx nx run-many --target=lint --all --skip-nx-cache
27 changes: 25 additions & 2 deletions apps/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,29 @@
},
"dependencies": {
"express": "^5.1.0",
"winston": "^3.17.0"
"winston": "^3.17.0",
"axios": "^1.13.1",
"rxjs": "^7.8.1",
"supertest": "7.1.4",
"pluralize": "^8.0.0",
"semver": "^7.6.3",
"listr2": "^8.2.1",
"commander": "^13.1.0",
"js-yaml": "^4.1.0",
"lodash": "^4.17.21",
"chalk": "^4.1.2",
"parse-duration": "^1.1.0",
"qs": "^6.12.1",
"dotenv": "^16.4.5",
"zod": "^4.0.10",
"source-map-support": "^0.5.21",
"agentkeepalive": "^4.6.0",
"glob": "^11.0.3",
"signale": "^1.4.0",
"vitest": "3.0.0",
"@nx/webpack": "21.6.4",
"webpack": "5.101.3",
"terser-webpack-plugin": "^5.3.14",
"@api7/adc-sdk": "workspace:*"
}
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

KEEP EOL!

2 changes: 1 addition & 1 deletion apps/cli/src/command/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import parseDuration from 'parse-duration';
import qs from 'qs';

export interface BaseOptions {
verbose: boolean;
verbose: number;
}
export class BaseCommand<
OPTS extends BaseOptions = BaseOptions,
Expand Down
6 changes: 1 addition & 5 deletions apps/cli/src/command/lint.command.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import * as ADCSDK from '@api7/adc-sdk';
import { Listr, ListrTask } from 'listr2';
import pluralize from 'pluralize';
import { ZodError } from 'zod';
import { Listr } from 'listr2';

import { check } from '../linter';
import { LintTask, LoadLocalConfigurationTask } from '../tasks';
import { SignaleRenderer } from '../utils/listr';
import { BaseCommand } from './helper';
Expand Down
45 changes: 33 additions & 12 deletions apps/cli/src/command/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,12 @@ export const toKVConfiguration = (
) {
return [
resourceType,
Object.fromEntries(resources.map((item) => [item.name, item])),
Object.fromEntries(
(Array.isArray(resources) ? resources : []).map((item) => [
item.name,
item,
]),
),
];
} else {
throw new Error(
Expand Down Expand Up @@ -138,29 +143,45 @@ export const mergeConfigurations = (
};

fileContents.forEach((config) => {
config.services && result.services.push(...config.services);
config.ssls && result.ssls.push(...config.ssls);
config.consumers && result.consumers.push(...config.consumers);
config.global_rules &&
if (config.services) {
result.services.push(...config.services);
}
if (config.ssls) {
result.ssls.push(...config.ssls);
}
if (config.consumers) {
result.consumers.push(...config.consumers);
}
if (config.global_rules) {
Object.keys(config.global_rules).forEach((globalRuleName: string) => {
result.global_rules[globalRuleName] =
config.global_rules[globalRuleName];
});
config.plugin_metadata &&
}
if (config.plugin_metadata) {
Object.keys(config.plugin_metadata).forEach(
(pluginMetadataName: string) => {
result.plugin_metadata[pluginMetadataName] =
config.plugin_metadata[pluginMetadataName];
},
);
}

config.routes && result.routes.push(...config.routes);
config.stream_routes && result.stream_routes.push(...config.stream_routes);
/* config.consumer_groups &&
if (config.routes) {
result.routes.push(...config.routes);
}
if (config.stream_routes) {
result.stream_routes.push(...config.stream_routes);
}
/* if (config.consumer_groups) {
result.consumer_groups.push(...config.consumer_groups);
config.plugin_configs &&
}
if (config.plugin_configs) {
result.plugin_configs.push(...config.plugin_configs);
config.upstreams && result.upstreams.push(...config.upstreams); */
}
if (config.upstreams) {
result.upstreams.push(...config.upstreams);
} */
});

return result;
Expand Down Expand Up @@ -332,7 +353,7 @@ export const resortConfiguration = (
];
return [
key,
value.sort((a, b) => {
(Array.isArray(value) ? value : []).sort((a, b) => {
// sort nested resources
if (key === 'services') {
if (a.routes) a.routes.sort((x, y) => x.name.localeCompare(y.name));
Expand Down
1 change: 0 additions & 1 deletion apps/cli/src/linter/specs/consumer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ describe('Consumer Linter', () => {
},
{
name: 'should check consumer credentials (unsupported type)',
//@ts-expect-error for test
input: {
consumers: [
{
Expand Down
2 changes: 1 addition & 1 deletion apps/cli/src/linter/specs/upstream.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ describe('Upstream Linter', () => {
],
},
],
} as ADCSDK.Configuration,
} as unknown as ADCSDK.Configuration,
expect: false,
errors: [
{
Expand Down
1 change: 0 additions & 1 deletion apps/cli/src/tasks/lint.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as ADCSDK from '@api7/adc-sdk';
import { ListrTask } from 'listr2';
import pluralize from 'pluralize';
import { z } from 'zod';

import { check } from '../linter';
Expand Down
16 changes: 10 additions & 6 deletions apps/cli/src/utils/listr.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { LogEntry, LogEntryOptions, Logger } from '@api7/adc-sdk';
import axios, { AxiosResponse } from 'axios';
import {
ListrRenderer,
ListrTaskEventType,
Expand Down Expand Up @@ -64,8 +63,9 @@ export class SignaleRenderer implements ListrRenderer {
if (err) {
this.getScopedLogger().fatal(err);
} else {
this.options.verbose > 0 &&
if (this.options.verbose > 0) {
this.getScopedLogger().star('All is well, see you next time!');
}
}
}

Expand All @@ -84,22 +84,26 @@ export class SignaleRenderer implements ListrRenderer {
if (!task.hasTitle()) return;

if (state === ListrTaskState.STARTED) {
rendererOptions?.verbose > 0 &&
if (rendererOptions?.verbose > 0) {
this.getScopedLogger(rendererOptions).start(task.title);
}
}
if (state === ListrTaskState.COMPLETED) {
rendererOptions?.verbose > 0 &&
if (rendererOptions?.verbose > 0) {
this.getScopedLogger(rendererOptions).success(task.title);
}
}
if (state === ListrTaskState.SKIPPED) {
rendererOptions?.verbose > 0 &&
if (rendererOptions?.verbose > 0) {
this.getScopedLogger(rendererOptions).info(
`${task.title} is skipped${task.message.skip ? `: ${task.message.skip}` : ''}`,
);
}
}
if (state === ListrTaskState.FAILED) {
rendererOptions?.verbose > 0 &&
if (rendererOptions?.verbose > 0) {
this.getScopedLogger(rendererOptions).error(task.title);
}
}
});

Expand Down
5 changes: 3 additions & 2 deletions libs/backend-api7/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
}
},
"devDependencies": {
"@api7/adc-differ": "workspace:*",
"@api7/adc-sdk": "workspace:*",
"@api7/adc-differ": "workspace:*"
"@types/jest": "^30.0.0"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no jest

},
"nx": {
"name": "backend-api7",
Expand All @@ -30,4 +31,4 @@
}
}
}
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

KEEP EOL

14 changes: 9 additions & 5 deletions libs/backend-api7/src/fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,11 @@ export class Fetcher extends ADCSDK.backend.BackendEventSource {
}),
).pipe(
tap((resp) => logger(this.debugLogEvent(resp))),
map((resp) => this.toADC.transformPluginMetadatas(resp?.data?.value)),
map((resp) =>
this.toADC.transformPluginMetadatas(
resp?.data?.value as typing.PluginMetadata,
),
),
tap(() => logger(taskStateEvent('TASK_DONE'))),
);
}
Expand Down Expand Up @@ -278,18 +282,18 @@ export class Fetcher extends ADCSDK.backend.BackendEventSource {
private isSkip(type: ADCSDK.ResourceType): boolean {
const { includeResourceType, excludeResourceType } =
this.opts.backendOpts || {};
if (!isEmpty(includeResourceType) && !includeResourceType.includes(type)) {
if (!isEmpty(includeResourceType) && !includeResourceType?.includes(type)) {
return true;
}
if (!isEmpty(excludeResourceType) && excludeResourceType.includes(type)) {
if (!isEmpty(excludeResourceType) && excludeResourceType?.includes(type)) {
return true;
}
return false;
}

private attachLabelSelector(
params: Record<string, string> = {},
): Record<string, string> {
params: Record<string, string | undefined> = {},
): Record<string, string | undefined> {
const { labelSelector } = this.opts.backendOpts || {};
if (labelSelector)
Object.entries(labelSelector).forEach(([key, value]) => {
Expand Down
68 changes: 37 additions & 31 deletions libs/backend-api7/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@ import semver, { SemVer } from 'semver';
import { Fetcher } from './fetcher';
import { Operator } from './operator';
import { ToADC } from './transformer';
import * as typing from './typing';

export class BackendAPI7 implements ADCSDK.Backend {
private readonly client: AxiosInstance;
private readonly gatewayGroupName: string;
private readonly gatewayGroupName?: string;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a misunderstanding. A undefined/null gatewayGroup is unacceptable for this backend.

Therefore, assuming it is undefined is inherently a logical error. If the gatewayGroup value passed in via opts could be null, it should be asserted there, and an error should be thrown if it is null.

private static logScope = ['API7'];
private readonly subject = new Subject<ADCSDK.BackendEvent>();

private _version?: SemVer;
private gatewayGroupId?: string;
private innerDefaultValue: ADCSDK.DefaultValue;
private innerDefaultValue?: ADCSDK.DefaultValue;

constructor(private readonly opts: ADCSDK.BackendOptions) {
this.client = axios.create({
Expand Down Expand Up @@ -54,8 +55,8 @@ export class BackendAPI7 implements ADCSDK.Backend {

return (this._version =
resp?.data?.value === 'dev'
? semver.coerce('999.999.999')
: semver.coerce(resp?.data?.value) || semver.coerce('0.0.0'));
? semver.coerce('999.999.999')!
: semver.coerce(resp?.data?.value) || semver.coerce('0.0.0')!);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simply create one directly using new Semver(). We can confirm that the provided string is a valid semver.

}

public async defaultValue() {
Expand All @@ -64,16 +65,19 @@ export class BackendAPI7 implements ADCSDK.Backend {
if (items.length < 2) return items[0];
if (!items.some((item) => item.type === 'object')) return {};

const first = items.shift();
if (!first.properties) first.properties = {};
const first = items.shift() || {};
if (!first?.properties) first.properties = {};
return items.reduce((pv, cv) => {
Object.entries(cv?.properties ?? {}).forEach(([key, val]) => {
if (!pv.properties) pv.properties = {};
pv.properties[key] = val;
});
return pv;
}, first);
};
const extractObjectDefault = (obj: JSONSchema4) => {
const extractObjectDefault = (
obj: JSONSchema4,
): Record<string, any> | null => {
if (obj.type !== 'object') return null;
if (!obj.properties) return null;

Expand All @@ -85,7 +89,7 @@ export class BackendAPI7 implements ADCSDK.Backend {

// For array nested object (e.g. service.upstream.nodes)
if (field.type === 'array' && !Array.isArray(field.items)) {
if (field.items.type === 'object')
if (field?.items?.type === 'object')
return [key, [extractObjectDefault(field.items)]];
}

Expand Down Expand Up @@ -117,29 +121,31 @@ export class BackendAPI7 implements ADCSDK.Backend {
const toADC = new ToADC();
return (this.innerDefaultValue = {
core: Object.fromEntries(
Object.entries(resp.data.value).map(
([type, schema]: [ADCSDK.ResourceType, JSONSchema4]) => {
const data =
extractObjectDefault(
schema.allOf ? mergeAllOf(schema.allOf) : schema,
) ?? {};
switch (type) {
case ADCSDK.ResourceType.ROUTE:
return [type, toADC.transformRoute(data)];
case ADCSDK.ResourceType.INTERNAL_STREAM_SERVICE:
case ADCSDK.ResourceType.SERVICE:
return [type, toADC.transformService(data)];
case ADCSDK.ResourceType.SSL:
return [type, toADC.transformSSL(data)];
case ADCSDK.ResourceType.CONSUMER:
return [type, toADC.transformConsumer(data)];
case ADCSDK.ResourceType.UPSTREAM:
return [type, toADC.transformUpstream(data)];
default:
return [type, data];
}
},
),
(
Object.entries(resp.data.value || {}) as Array<
[ADCSDK.ResourceType, JSONSchema4]
>
).map(([type, schema]) => {
const data =
extractObjectDefault(
schema.allOf ? mergeAllOf(schema.allOf) : schema,
) ?? {};
switch (type) {
case ADCSDK.ResourceType.ROUTE:
return [type, toADC.transformRoute(data as typing.Route)];
case ADCSDK.ResourceType.INTERNAL_STREAM_SERVICE:
case ADCSDK.ResourceType.SERVICE:
return [type, toADC.transformService(data as typing.Service)];
case ADCSDK.ResourceType.SSL:
return [type, toADC.transformSSL(data as typing.SSL)];
case ADCSDK.ResourceType.CONSUMER:
return [type, toADC.transformConsumer(data as typing.Consumer)];
case ADCSDK.ResourceType.UPSTREAM:
return [type, toADC.transformUpstream(data as typing.Upstream)];
default:
return [type, data];
}
}),
),
} as ADCSDK.DefaultValue);
}
Expand Down
Loading
Loading