@certd/pipeline 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/.eslintrc +21 -0
  2. package/.mocharc.json +5 -0
  3. package/.prettierrc +3 -0
  4. package/README.md +16 -0
  5. package/index.ts +1 -0
  6. package/package.json +61 -0
  7. package/src/access/api.ts +18 -0
  8. package/src/access/decorator.ts +39 -0
  9. package/src/access/index.ts +3 -0
  10. package/src/access/registry.ts +4 -0
  11. package/src/context/index.ts +6 -0
  12. package/src/core/context.ts +88 -0
  13. package/src/core/executor.ts +207 -0
  14. package/src/core/index.ts +4 -0
  15. package/src/core/run-history.ts +158 -0
  16. package/src/core/storage.ts +140 -0
  17. package/src/d.ts/fast-crud.ts +115 -0
  18. package/src/d.ts/index.ts +2 -0
  19. package/src/d.ts/pipeline.ts +119 -0
  20. package/src/decorator/common.ts +17 -0
  21. package/src/decorator/index.ts +2 -0
  22. package/src/decorator/utils.ts +42 -0
  23. package/src/index.ts +9 -0
  24. package/src/midway/configuration.ts +52 -0
  25. package/src/midway/index.ts +5 -0
  26. package/src/plugin/api.ts +60 -0
  27. package/src/plugin/decorator.ts +63 -0
  28. package/src/plugin/index.ts +3 -0
  29. package/src/plugin/registry.ts +4 -0
  30. package/src/plugin/test/echo-plugin.ts +31 -0
  31. package/src/registry/index.ts +1 -0
  32. package/src/registry/registry.ts +57 -0
  33. package/src/utils/index.ts +7 -0
  34. package/src/utils/util.log.ts +35 -0
  35. package/src/utils/util.request.ts +58 -0
  36. package/src/utils/util.sleep.ts +7 -0
  37. package/test/cert.fake.test.ts +58 -0
  38. package/test/echo-plugin.ts +30 -0
  39. package/test/index.test.ts +16 -0
  40. package/test/pipeline/access-service-test.ts +10 -0
  41. package/test/pipeline/init.test.ts +15 -0
  42. package/test/pipeline/pipeline.define.ts +66 -0
  43. package/test/pipeline/pipeline.test.ts +18 -0
  44. package/tsconfig.json +20 -0
  45. package/vite.config.js +35 -0
@@ -0,0 +1,57 @@
1
+ export type Registrable = {
2
+ name: string;
3
+ title: string;
4
+ desc?: string;
5
+ };
6
+
7
+ export type RegistryItem<T> = {
8
+ define: Registrable;
9
+ target: T;
10
+ };
11
+ export class Registry<T> {
12
+ storage: {
13
+ [key: string]: RegistryItem<T>;
14
+ } = {};
15
+
16
+ register(key: string, value: RegistryItem<T>) {
17
+ if (!key || value == null) {
18
+ return;
19
+ }
20
+ this.storage[key] = value;
21
+ }
22
+
23
+ get(name: string): RegistryItem<T> {
24
+ if (!name) {
25
+ throw new Error("插件名称不能为空");
26
+ }
27
+
28
+ const plugin = this.storage[name];
29
+ if (!plugin) {
30
+ throw new Error(`插件${name}还未注册`);
31
+ }
32
+ return plugin;
33
+ }
34
+
35
+ getStorage() {
36
+ return this.storage;
37
+ }
38
+
39
+ getDefineList() {
40
+ const list = [];
41
+ for (const key in this.storage) {
42
+ const define = this.getDefine(key);
43
+ if (define) {
44
+ list.push({ ...define, key });
45
+ }
46
+ }
47
+ return list;
48
+ }
49
+
50
+ getDefine(key: string) {
51
+ const item = this.storage[key];
52
+ if (!item) {
53
+ return;
54
+ }
55
+ return item.define;
56
+ }
57
+ }
@@ -0,0 +1,7 @@
1
+ import sleep from "./util.sleep";
2
+ import { request } from "./util.request";
3
+ export * from "./util.log";
4
+ export const utils = {
5
+ sleep,
6
+ http: request,
7
+ };
@@ -0,0 +1,35 @@
1
+ import log4js, { LoggingEvent, Logger } from "log4js";
2
+
3
+ const OutputAppender = {
4
+ configure: (config: any, layouts: any, findAppender: any, levels: any) => {
5
+ let layout = layouts.basicLayout;
6
+ if (config.layout) {
7
+ layout = layouts.layout(config.layout.type, config.layout);
8
+ }
9
+ function customAppender(layout: any, timezoneOffset: any) {
10
+ return (loggingEvent: LoggingEvent) => {
11
+ if (loggingEvent.context.outputHandler?.write) {
12
+ const text = `${layout(loggingEvent, timezoneOffset)}\n`;
13
+ loggingEvent.context.outputHandler.write(text);
14
+ }
15
+ };
16
+ }
17
+ return customAppender(layout, config.timezoneOffset);
18
+ },
19
+ };
20
+
21
+ // @ts-ignore
22
+ log4js.configure({
23
+ appenders: { std: { type: "stdout" }, output: { type: OutputAppender } },
24
+ categories: { default: { appenders: ["std"], level: "info" }, pipeline: { appenders: ["std", "output"], level: "info" } },
25
+ });
26
+ export const logger = log4js.getLogger("default");
27
+
28
+ export function buildLogger(write: (text: string) => void) {
29
+ const logger = log4js.getLogger("pipeline");
30
+ logger.addContext("outputHandler", {
31
+ write,
32
+ });
33
+ return logger;
34
+ }
35
+ export type ILogger = Logger;
@@ -0,0 +1,58 @@
1
+ import axios from "axios";
2
+ // @ts-ignore
3
+ import qs from "qs";
4
+ import { logger } from "./util.log";
5
+ /**
6
+ * @description 创建请求实例
7
+ */
8
+ function createService() {
9
+ // 创建一个 axios 实例
10
+ const service = axios.create();
11
+ // 请求拦截
12
+ service.interceptors.request.use(
13
+ (config: any) => {
14
+ if (config.formData) {
15
+ config.data = qs.stringify(config.formData, {
16
+ arrayFormat: "indices",
17
+ allowDots: true,
18
+ }); // 序列化请求参数
19
+ delete config.formData;
20
+ }
21
+ return config;
22
+ },
23
+ (error: Error) => {
24
+ // 发送失败
25
+ logger.error(error);
26
+ return Promise.reject(error);
27
+ }
28
+ );
29
+ // 响应拦截
30
+ service.interceptors.response.use(
31
+ (response: any) => {
32
+ logger.info("http response:", JSON.stringify(response.data));
33
+ return response.data;
34
+ },
35
+ (error: any) => {
36
+ // const status = _.get(error, 'response.status')
37
+ // switch (status) {
38
+ // case 400: error.message = '请求错误'; break
39
+ // case 401: error.message = '未授权,请登录'; break
40
+ // case 403: error.message = '拒绝访问'; break
41
+ // case 404: error.message = `请求地址出错: ${error.response.config.url}`; break
42
+ // case 408: error.message = '请求超时'; break
43
+ // case 500: error.message = '服务器内部错误'; break
44
+ // case 501: error.message = '服务未实现'; break
45
+ // case 502: error.message = '网关错误'; break
46
+ // case 503: error.message = '服务不可用'; break
47
+ // case 504: error.message = '网关超时'; break
48
+ // case 505: error.message = 'HTTP版本不受支持'; break
49
+ // default: break
50
+ // }
51
+ logger.error("请求出错:", error.response.config.url, error);
52
+ return Promise.reject(error);
53
+ }
54
+ );
55
+ return service;
56
+ }
57
+
58
+ export const request = createService();
@@ -0,0 +1,7 @@
1
+ export default function (timeout: number) {
2
+ return new Promise((resolve) => {
3
+ setTimeout(() => {
4
+ resolve({});
5
+ }, timeout);
6
+ });
7
+ }
@@ -0,0 +1,58 @@
1
+ export const fakeCrt = `-----BEGIN CERTIFICATE-----
2
+ MIIFSTCCBDGgAwIBAgITAPoZZk/LhVIyXoic2NnJyxubezANBgkqhkiG9w0BAQsF
3
+ ADAiMSAwHgYDVQQDDBdGYWtlIExFIEludGVybWVkaWF0ZSBYMTAeFw0yMDEyMTQx
4
+ NjA1NTFaFw0yMTAzMTQxNjA1NTFaMBsxGTAXBgNVBAMMECouZG9jbWlycm9yLmNs
5
+ dWIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC75tGrYjly+RpcZehQ
6
+ my1EpaXElT4L60pINKV2YDKnBrcSSo1c6rO7nFh12eC/ju4WwYUep0RVmBDF8xD0
7
+ I1Sd1uuDTQWP0UT1X9yqdXtjvxpUqoCHAzG633f3sJRFul7mDLuC9tRCuae9o7qP
8
+ EZ827XOmjBR35dso9I2GEE4828J3YE3tSKtobZlM+30jozLEcsO0PTyM5mq5PPjP
9
+ VI3fGLcEaBmLZf5ixz4XkcY9IAhyAMYf03cT2wRoYPBaDdXblgCYL6sFtIMbzl3M
10
+ Di94PB8NyoNSsC2nmBdWi54wFOgBvY/4ljsX/q7X3EqlSvcA0/M6/c/J9kJ3eupv
11
+ jV8nAgMBAAGjggJ9MIICeTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYB
12
+ BQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFAkdTjSCV3KD
13
+ x28sf98MrwVfyFYgMB8GA1UdIwQYMBaAFMDMA0a5WCDMXHJw8+EuyyCm9Wg6MHcG
14
+ CCsGAQUFBwEBBGswaTAyBggrBgEFBQcwAYYmaHR0cDovL29jc3Auc3RnLWludC14
15
+ MS5sZXRzZW5jcnlwdC5vcmcwMwYIKwYBBQUHMAKGJ2h0dHA6Ly9jZXJ0LnN0Zy1p
16
+ bnQteDEubGV0c2VuY3J5cHQub3JnLzArBgNVHREEJDAighAqLmRvY21pcnJvci5j
17
+ bHVigg5kb2NtaXJyb3IuY2x1YjBMBgNVHSAERTBDMAgGBmeBDAECATA3BgsrBgEE
18
+ AYLfEwEBATAoMCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxldHNlbmNyeXB0Lm9y
19
+ ZzCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB1ABboacHRlerXw/iXGuPwdgH3jOG2
20
+ nTGoUhi2g38xqBUIAAABdmI3LM4AAAQDAEYwRAIgaiNqXSEq+sxp8eqlJXp/KFdO
21
+ so5mT50MoRsLF8Inu0ACIDP46+ekng7I0BlmyIPmbqFcZgnZFVWLLCdLYijhVyOL
22
+ AHcA3Zk0/KXnJIDJVmh9gTSZCEmySfe1adjHvKs/XMHzbmQAAAF2YjcuxwAABAMA
23
+ SDBGAiEAxpeB8/w4YkHZ62nH20h128VtuTSmYDCnF7EK2fQyeZYCIQDbJlF2wehZ
24
+ sF1BeE7qnYYqCTP0dYIrQ9HWtBa/MbGOKTANBgkqhkiG9w0BAQsFAAOCAQEAL2di
25
+ HKh6XcZtGk0BFxJa51sCZ3MLu9+Zy90kCRD4ooP5x932WxVM25+LBRd+xSzx+TRL
26
+ UVrlKp9GdMYX1JXL4Vf2NwzuFO3snPDe/qizD/3+D6yo8eKJ/LD82t5kLWAD2rto
27
+ YfVSTKwfNIBBJwHUnjviBPJmheHHCKmz8Ct6/6QxFAeta9TAMn0sFeVCQnmAq7HL
28
+ jrunq0tNHR/EKG0ITPLf+6P7MxbmpYNnq918766l0tKsW8oo8ZSGEwKU2LMaSiAa
29
+ hasyl/2gMnYXjtKOjDcnR8oLpbrOg0qpVbynmJin1HP835oHPPAZ1gLsqYTTizNz
30
+ AHxTaXliTVvS83dogw==
31
+ -----END CERTIFICATE-----
32
+ -----BEGIN CERTIFICATE-----
33
+ MIIEqzCCApOgAwIBAgIRAIvhKg5ZRO08VGQx8JdhT+UwDQYJKoZIhvcNAQELBQAw
34
+ GjEYMBYGA1UEAwwPRmFrZSBMRSBSb290IFgxMB4XDTE2MDUyMzIyMDc1OVoXDTM2
35
+ MDUyMzIyMDc1OVowIjEgMB4GA1UEAwwXRmFrZSBMRSBJbnRlcm1lZGlhdGUgWDEw
36
+ ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDtWKySDn7rWZc5ggjz3ZB0
37
+ 8jO4xti3uzINfD5sQ7Lj7hzetUT+wQob+iXSZkhnvx+IvdbXF5/yt8aWPpUKnPym
38
+ oLxsYiI5gQBLxNDzIec0OIaflWqAr29m7J8+NNtApEN8nZFnf3bhehZW7AxmS1m0
39
+ ZnSsdHw0Fw+bgixPg2MQ9k9oefFeqa+7Kqdlz5bbrUYV2volxhDFtnI4Mh8BiWCN
40
+ xDH1Hizq+GKCcHsinDZWurCqder/afJBnQs+SBSL6MVApHt+d35zjBD92fO2Je56
41
+ dhMfzCgOKXeJ340WhW3TjD1zqLZXeaCyUNRnfOmWZV8nEhtHOFbUCU7r/KkjMZO9
42
+ AgMBAAGjgeMwgeAwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAw
43
+ HQYDVR0OBBYEFMDMA0a5WCDMXHJw8+EuyyCm9Wg6MHoGCCsGAQUFBwEBBG4wbDA0
44
+ BggrBgEFBQcwAYYoaHR0cDovL29jc3Auc3RnLXJvb3QteDEubGV0c2VuY3J5cHQu
45
+ b3JnLzA0BggrBgEFBQcwAoYoaHR0cDovL2NlcnQuc3RnLXJvb3QteDEubGV0c2Vu
46
+ Y3J5cHQub3JnLzAfBgNVHSMEGDAWgBTBJnSkikSg5vogKNhcI5pFiBh54DANBgkq
47
+ hkiG9w0BAQsFAAOCAgEABYSu4Il+fI0MYU42OTmEj+1HqQ5DvyAeyCA6sGuZdwjF
48
+ UGeVOv3NnLyfofuUOjEbY5irFCDtnv+0ckukUZN9lz4Q2YjWGUpW4TTu3ieTsaC9
49
+ AFvCSgNHJyWSVtWvB5XDxsqawl1KzHzzwr132bF2rtGtazSqVqK9E07sGHMCf+zp
50
+ DQVDVVGtqZPHwX3KqUtefE621b8RI6VCl4oD30Olf8pjuzG4JKBFRFclzLRjo/h7
51
+ IkkfjZ8wDa7faOjVXx6n+eUQ29cIMCzr8/rNWHS9pYGGQKJiY2xmVC9h12H99Xyf
52
+ zWE9vb5zKP3MVG6neX1hSdo7PEAb9fqRhHkqVsqUvJlIRmvXvVKTwNCP3eCjRCCI
53
+ PTAvjV+4ni786iXwwFYNz8l3PmPLCyQXWGohnJ8iBm+5nk7O2ynaPVW0U2W+pt2w
54
+ SVuvdDM5zGv2f9ltNWUiYZHJ1mmO97jSY/6YfdOUH66iRtQtDkHBRdkNBsMbD+Em
55
+ 2TgBldtHNSJBfB3pm9FblgOcJ0FSWcUDWJ7vO0+NTXlgrRofRT6pVywzxVo6dND0
56
+ WzYlTWeUVsO40xJqhgUQRER9YLOLxJ0O6C8i0xFxAMKOtSdodMB3RIwt7RFQ0uyt
57
+ n5Z5MqkYhlMI3J1tPRTp1nEt9fyGspBOO05gi148Qasp+3N+svqKomoQglNoAxU=
58
+ -----END CERTIFICATE-----`;
@@ -0,0 +1,30 @@
1
+ import { Autowire, ILogger, IsTaskPlugin, ITaskPlugin, TaskInput, TaskOutput } from "../src";
2
+
3
+ @IsTaskPlugin({
4
+ name: "EchoPlugin",
5
+ title: "测试插件【echo】",
6
+ })
7
+ export class EchoPlugin implements ITaskPlugin {
8
+ @TaskInput({
9
+ title: "cert",
10
+ component: {
11
+ name: "pi-output-selector",
12
+ },
13
+ helper: "输出选择",
14
+ })
15
+ cert!: any;
16
+
17
+ @Autowire()
18
+ logger!: ILogger;
19
+
20
+ @TaskOutput({
21
+ title: "cert info",
22
+ })
23
+ certInfo!: any;
24
+
25
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
26
+ async onInstance(): Promise<void> {}
27
+ async execute(): Promise<void> {
28
+ console.log("input :cert", this.cert);
29
+ }
30
+ }
@@ -0,0 +1,16 @@
1
+ import { expect } from "chai";
2
+ import "mocha";
3
+ import { EchoPlugin } from "./echo-plugin";
4
+ describe("task_plugin", function () {
5
+ it("#taskplugin", function () {
6
+ console.log("before new plugin");
7
+ const echoPlugin = new EchoPlugin();
8
+ console.log("before set property", echoPlugin);
9
+ echoPlugin.cert = { test: 1 };
10
+ console.log("before execute");
11
+ // @ts-ignore
12
+ echoPlugin.execute();
13
+ console.log("after execute");
14
+ expect(echoPlugin.cert.test).eq(1);
15
+ });
16
+ });
@@ -0,0 +1,10 @@
1
+ import { IAccess, IAccessService } from "../../src";
2
+ // @ts-ignore
3
+ import { aliyunSecret } from "../user.secret";
4
+ export class AccessServiceTest implements IAccessService {
5
+ async getById(id: any): Promise<IAccess> {
6
+ return {
7
+ ...aliyunSecret,
8
+ } as any;
9
+ }
10
+ }
@@ -0,0 +1,15 @@
1
+ import { ContextFactory } from "../../src/core/context";
2
+ import { FileStorage } from "../../src/core/storage";
3
+ import { AccessServiceTest } from "./access-service-test";
4
+ import { logger } from "../../src/utils/util.log";
5
+
6
+ const contextFactory = new ContextFactory(new FileStorage());
7
+
8
+ const userContext = contextFactory.getContext("user", "test");
9
+ const pipelineContext = contextFactory.getContext("pipeline", "test");
10
+ export const pluginInitProps = {
11
+ accessService: new AccessServiceTest(),
12
+ pipelineContext: pipelineContext,
13
+ userContext: userContext,
14
+ logger: logger,
15
+ };
@@ -0,0 +1,66 @@
1
+ import { ConcurrencyStrategy, NextStrategy, Pipeline, RunStrategy } from "../../src";
2
+
3
+ let idIndex = 0;
4
+ function generateId() {
5
+ idIndex++;
6
+ return idIndex + "";
7
+ }
8
+ export const pipeline: Pipeline = {
9
+ version: 1,
10
+ id: generateId(),
11
+ title: "测试管道",
12
+ userId: 1,
13
+ triggers: [],
14
+ stages: [
15
+ {
16
+ id: generateId(),
17
+ title: "证书申请阶段",
18
+ concurrency: ConcurrencyStrategy.Serial,
19
+ next: NextStrategy.AllSuccess,
20
+ tasks: [
21
+ {
22
+ id: generateId(),
23
+ title: "申请证书任务",
24
+ steps: [
25
+ {
26
+ id: generateId(),
27
+ title: "申请证书",
28
+ type: "CertApply",
29
+ input: {
30
+ domains: ["*.docmirror.cn"],
31
+ email: "xiaojunnuo@qq.com",
32
+ dnsProviderType: "aliyun",
33
+ accessId: "111",
34
+ },
35
+ },
36
+ ],
37
+ },
38
+ ],
39
+ },
40
+ {
41
+ id: generateId(),
42
+ title: "证书部署阶段",
43
+ concurrency: ConcurrencyStrategy.Serial,
44
+ next: NextStrategy.AllSuccess,
45
+ tasks: [
46
+ {
47
+ id: generateId(),
48
+ title: "测试输出参数任务",
49
+ steps: [
50
+ {
51
+ id: generateId(),
52
+ title: "输出参数(echo插件)",
53
+ type: "EchoPlugin",
54
+ input: {
55
+ cert: "cert",
56
+ },
57
+ strategy: {
58
+ runStrategy: RunStrategy.SkipWhenSucceed,
59
+ },
60
+ },
61
+ ],
62
+ },
63
+ ],
64
+ },
65
+ ],
66
+ };
@@ -0,0 +1,18 @@
1
+ //import { expect } from "chai";
2
+ import "mocha";
3
+ import { Executor, RunHistory } from "../../src";
4
+ import { pipeline } from "./pipeline.define";
5
+ import { AccessServiceTest } from "./access-service-test";
6
+ import { FileStorage } from "../../src/core/storage";
7
+ describe("pipeline", function () {
8
+ it("#pipeline", async function () {
9
+ this.timeout(120000);
10
+ async function onChanged(history: RunHistory) {
11
+ console.log("changed:");
12
+ }
13
+
14
+ const executor = new Executor({ userId: "test", pipeline, onChanged, accessService: new AccessServiceTest(), storage: new FileStorage() });
15
+ await executor.run(1, "user");
16
+ // expect(define.name).eq("EchoPlugin");
17
+ });
18
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "useDefineForClassFields": true,
5
+ "module": "commonjs",
6
+ "moduleResolution": "Node",
7
+ "strict": true,
8
+ "jsx": "preserve",
9
+ "sourceMap": true,
10
+ "resolveJsonModule": true,
11
+ "isolatedModules": true,
12
+ "esModuleInterop": true,
13
+ "lib": ["ESNext", "DOM"],
14
+ "skipLibCheck": true,
15
+ "experimentalDecorators": true,
16
+ "emitDecoratorMetadata": true,
17
+ "outDir": "./dist/ts"
18
+ },
19
+ "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue","test/**/*.ts"],
20
+ }
package/vite.config.js ADDED
@@ -0,0 +1,35 @@
1
+ import { defineConfig } from "vite";
2
+ import typescript from "@rollup/plugin-typescript";
3
+ // https://vitejs.dev/config/
4
+ export default defineConfig({
5
+ plugins: [],
6
+ build: {
7
+ lib: {
8
+ entry: "src/index.ts",
9
+ name: "pipeline",
10
+ },
11
+ rollupOptions: {
12
+ plugins: [
13
+ typescript({
14
+ target: "esnext",
15
+ rootDir: "src",
16
+ declaration: true,
17
+ declarationDir: "dist/d",
18
+ exclude: ["./node_modules/**", "./src/**/*.vue"],
19
+ allowSyntheticDefaultImports: true,
20
+ }),
21
+ ],
22
+ external: ["vue", "lodash", "dayjs", "@fast-crud/fast-crud"],
23
+ output: {
24
+ // Provide global variables to use in the UMD build
25
+ // for externalized deps
26
+ globals: {
27
+ vue: "Vue",
28
+ lodash: "_",
29
+ dayjs: "dayjs",
30
+ "@fast-crud/fast-crud": "FastCrud",
31
+ },
32
+ },
33
+ },
34
+ },
35
+ });