@vaharoni/devops 1.0.47
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.
- package/README.md +51 -0
- package/dist/app-support/crypto/index.d.ts +15 -0
- package/dist/app-support/crypto/index.d.ts.map +1 -0
- package/dist/app-support/crypto/index.js +30 -0
- package/dist/app-support/crypto/internal-token.d.ts +20 -0
- package/dist/app-support/crypto/internal-token.d.ts.map +1 -0
- package/dist/app-support/crypto/internal-token.js +42 -0
- package/dist/app-support/crypto/internal-token.spec.d.ts +2 -0
- package/dist/app-support/crypto/internal-token.spec.d.ts.map +1 -0
- package/dist/app-support/crypto/internal-token.spec.js +45 -0
- package/dist/app-support/crypto/secret.d.ts +3 -0
- package/dist/app-support/crypto/secret.d.ts.map +1 -0
- package/dist/app-support/crypto/secret.js +12 -0
- package/dist/app-support/crypto/secret.spec.d.ts +2 -0
- package/dist/app-support/crypto/secret.spec.d.ts.map +1 -0
- package/dist/app-support/crypto/secret.spec.js +15 -0
- package/dist/app-support/discovery/dev-discovery-loader.d.ts +2 -0
- package/dist/app-support/discovery/dev-discovery-loader.d.ts.map +1 -0
- package/dist/app-support/discovery/dev-discovery-loader.js +30 -0
- package/dist/app-support/discovery/service-endpoint.d.ts +2 -0
- package/dist/app-support/discovery/service-endpoint.d.ts.map +1 -0
- package/dist/app-support/discovery/service-endpoint.js +10 -0
- package/dist/cli/affected.d.ts +11 -0
- package/dist/cli/affected.d.ts.map +1 -0
- package/dist/cli/affected.js +103 -0
- package/dist/cli/common.d.ts +89 -0
- package/dist/cli/common.d.ts.map +1 -0
- package/dist/cli/common.js +236 -0
- package/dist/cli/common.spec.d.ts +2 -0
- package/dist/cli/common.spec.d.ts.map +1 -0
- package/dist/cli/common.spec.js +64 -0
- package/dist/cli/console.d.ts +11 -0
- package/dist/cli/console.d.ts.map +1 -0
- package/dist/cli/console.js +35 -0
- package/dist/cli/constant.d.ts +11 -0
- package/dist/cli/constant.d.ts.map +1 -0
- package/dist/cli/constant.js +22 -0
- package/dist/cli/db.d.ts +11 -0
- package/dist/cli/db.d.ts.map +1 -0
- package/dist/cli/db.js +119 -0
- package/dist/cli/dml.d.ts +11 -0
- package/dist/cli/dml.d.ts.map +1 -0
- package/dist/cli/dml.js +116 -0
- package/dist/cli/env.d.ts +11 -0
- package/dist/cli/env.d.ts.map +1 -0
- package/dist/cli/env.js +67 -0
- package/dist/cli/exec.d.ts +11 -0
- package/dist/cli/exec.d.ts.map +1 -0
- package/dist/cli/exec.js +50 -0
- package/dist/cli/image.d.ts +11 -0
- package/dist/cli/image.d.ts.map +1 -0
- package/dist/cli/image.js +140 -0
- package/dist/cli/init.d.ts +11 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +66 -0
- package/dist/cli/internal-curl.d.ts +11 -0
- package/dist/cli/internal-curl.d.ts.map +1 -0
- package/dist/cli/internal-curl.js +43 -0
- package/dist/cli/job.d.ts +11 -0
- package/dist/cli/job.d.ts.map +1 -0
- package/dist/cli/job.js +67 -0
- package/dist/cli/jwt.d.ts +11 -0
- package/dist/cli/jwt.d.ts.map +1 -0
- package/dist/cli/jwt.js +27 -0
- package/dist/cli/namespace.d.ts +11 -0
- package/dist/cli/namespace.d.ts.map +1 -0
- package/dist/cli/namespace.js +70 -0
- package/dist/cli/prep-build.d.ts +11 -0
- package/dist/cli/prep-build.d.ts.map +1 -0
- package/dist/cli/prep-build.js +82 -0
- package/dist/cli/prisma.d.ts +11 -0
- package/dist/cli/prisma.d.ts.map +1 -0
- package/dist/cli/prisma.js +25 -0
- package/dist/cli/redis.d.ts +11 -0
- package/dist/cli/redis.d.ts.map +1 -0
- package/dist/cli/redis.js +76 -0
- package/dist/cli/registry.d.ts +11 -0
- package/dist/cli/registry.d.ts.map +1 -0
- package/dist/cli/registry.js +58 -0
- package/dist/cli/run-many.d.ts +11 -0
- package/dist/cli/run-many.d.ts.map +1 -0
- package/dist/cli/run-many.js +50 -0
- package/dist/cli/run.d.ts +11 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +37 -0
- package/dist/cli/template.d.ts +11 -0
- package/dist/cli/template.d.ts.map +1 -0
- package/dist/cli/template.js +123 -0
- package/dist/cli/test.d.ts +11 -0
- package/dist/cli/test.d.ts.map +1 -0
- package/dist/cli/test.js +28 -0
- package/dist/devops.d.ts +3 -0
- package/dist/devops.d.ts.map +1 -0
- package/dist/devops.js +103 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/libs/affected-entities.d.ts +15 -0
- package/dist/libs/affected-entities.d.ts.map +1 -0
- package/dist/libs/affected-entities.js +52 -0
- package/dist/libs/config.d.ts +6 -0
- package/dist/libs/config.d.ts.map +1 -0
- package/dist/libs/config.js +98 -0
- package/dist/libs/dependencies.d.ts +19 -0
- package/dist/libs/dependencies.d.ts.map +1 -0
- package/dist/libs/dependencies.js +62 -0
- package/dist/libs/dependencies.spec.d.ts +2 -0
- package/dist/libs/dependencies.spec.d.ts.map +1 -0
- package/dist/libs/dependencies.spec.js +21 -0
- package/dist/libs/digital-ocean/container-reg.d.ts +6 -0
- package/dist/libs/digital-ocean/container-reg.d.ts.map +1 -0
- package/dist/libs/digital-ocean/container-reg.js +69 -0
- package/dist/libs/discovery/dependencies.d.ts +19 -0
- package/dist/libs/discovery/dependencies.d.ts.map +1 -0
- package/dist/libs/discovery/dependencies.js +62 -0
- package/dist/libs/discovery/dependencies.spec.d.ts +2 -0
- package/dist/libs/discovery/dependencies.spec.d.ts.map +1 -0
- package/dist/libs/discovery/dependencies.spec.js +21 -0
- package/dist/libs/discovery/images.d.ts +5 -0
- package/dist/libs/discovery/images.d.ts.map +1 -0
- package/dist/libs/discovery/images.js +45 -0
- package/dist/libs/discovery/index.d.ts +5 -0
- package/dist/libs/discovery/index.d.ts.map +1 -0
- package/dist/libs/discovery/index.js +55 -0
- package/dist/libs/discovery/package-json-processor.d.ts +3 -0
- package/dist/libs/discovery/package-json-processor.d.ts.map +1 -0
- package/dist/libs/discovery/package-json-processor.js +34 -0
- package/dist/libs/discovery/process-common.d.ts +25 -0
- package/dist/libs/discovery/process-common.d.ts.map +1 -0
- package/dist/libs/discovery/process-common.js +40 -0
- package/dist/libs/discovery/process-package-json.d.ts +3 -0
- package/dist/libs/discovery/process-package-json.d.ts.map +1 -0
- package/dist/libs/discovery/process-package-json.js +34 -0
- package/dist/libs/discovery/process-pyproject-toml.d.ts +3 -0
- package/dist/libs/discovery/process-pyproject-toml.d.ts.map +1 -0
- package/dist/libs/discovery/process-pyproject-toml.js +36 -0
- package/dist/libs/discovery/pyproject-toml-processor.d.ts +3 -0
- package/dist/libs/discovery/pyproject-toml-processor.d.ts.map +1 -0
- package/dist/libs/discovery/pyproject-toml-processor.js +39 -0
- package/dist/libs/git-helpers.d.ts +8 -0
- package/dist/libs/git-helpers.d.ts.map +1 -0
- package/dist/libs/git-helpers.js +20 -0
- package/dist/libs/hetzner/reg-secret.d.ts +3 -0
- package/dist/libs/hetzner/reg-secret.d.ts.map +1 -0
- package/dist/libs/hetzner/reg-secret.js +39 -0
- package/dist/libs/k8s-constants.d.ts +12 -0
- package/dist/libs/k8s-constants.d.ts.map +1 -0
- package/dist/libs/k8s-constants.js +66 -0
- package/dist/libs/k8s-db.d.ts +18 -0
- package/dist/libs/k8s-db.d.ts.map +1 -0
- package/dist/libs/k8s-db.js +73 -0
- package/dist/libs/k8s-generate.d.ts +17 -0
- package/dist/libs/k8s-generate.d.ts.map +1 -0
- package/dist/libs/k8s-generate.js +179 -0
- package/dist/libs/k8s-helpers.d.ts +11 -0
- package/dist/libs/k8s-helpers.d.ts.map +1 -0
- package/dist/libs/k8s-helpers.js +42 -0
- package/dist/libs/k8s-image-config.d.ts +8 -0
- package/dist/libs/k8s-image-config.d.ts.map +1 -0
- package/dist/libs/k8s-image-config.js +113 -0
- package/dist/libs/k8s-job-waiter.d.ts +8 -0
- package/dist/libs/k8s-job-waiter.d.ts.map +1 -0
- package/dist/libs/k8s-job-waiter.js +84 -0
- package/dist/libs/k8s-namespace.d.ts +7 -0
- package/dist/libs/k8s-namespace.d.ts.map +1 -0
- package/dist/libs/k8s-namespace.js +27 -0
- package/dist/libs/k8s-redis.d.ts +6 -0
- package/dist/libs/k8s-redis.d.ts.map +1 -0
- package/dist/libs/k8s-redis.js +31 -0
- package/dist/libs/k8s-secrets-manager.d.ts +5 -0
- package/dist/libs/k8s-secrets-manager.d.ts.map +1 -0
- package/dist/libs/k8s-secrets-manager.js +61 -0
- package/dist/libs/validate-env.d.ts +56 -0
- package/dist/libs/validate-env.d.ts.map +1 -0
- package/dist/libs/validate-env.js +214 -0
- package/dist/libs/validate-env.spec.d.ts +2 -0
- package/dist/libs/validate-env.spec.d.ts.map +1 -0
- package/dist/libs/validate-env.spec.js +168 -0
- package/dist/libs/workspace-discovery.d.ts +2 -0
- package/dist/libs/workspace-discovery.d.ts.map +1 -0
- package/dist/libs/workspace-discovery.js +75 -0
- package/dist/test.d.ts +2 -0
- package/dist/test.d.ts.map +1 -0
- package/dist/test.js +1 -0
- package/dist/types/index.d.ts +925 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +79 -0
- package/package.json +55 -0
- package/src/app-support/crypto/index.ts +31 -0
- package/src/app-support/crypto/internal-token.spec.ts +53 -0
- package/src/app-support/crypto/internal-token.ts +82 -0
- package/src/app-support/crypto/secret.spec.ts +18 -0
- package/src/app-support/crypto/secret.ts +13 -0
- package/src/app-support/discovery/dev-discovery-loader.ts +35 -0
- package/src/app-support/discovery/service-endpoint.ts +12 -0
- package/src/cli/affected.ts +116 -0
- package/src/cli/common.spec.ts +78 -0
- package/src/cli/common.ts +323 -0
- package/src/cli/console.ts +46 -0
- package/src/cli/constant.ts +25 -0
- package/src/cli/db.ts +133 -0
- package/src/cli/dml.ts +126 -0
- package/src/cli/env.ts +87 -0
- package/src/cli/exec.sh +21 -0
- package/src/cli/exec.ts +57 -0
- package/src/cli/image.ts +197 -0
- package/src/cli/init.ts +75 -0
- package/src/cli/internal-curl.ts +48 -0
- package/src/cli/job.ts +80 -0
- package/src/cli/jwt.ts +32 -0
- package/src/cli/namespace.ts +78 -0
- package/src/cli/prep-build.ts +96 -0
- package/src/cli/prisma.ts +33 -0
- package/src/cli/redis.ts +83 -0
- package/src/cli/registry.ts +76 -0
- package/src/cli/run-many.ts +61 -0
- package/src/cli/run.ts +46 -0
- package/src/cli/template.ts +169 -0
- package/src/cli/test.ts +30 -0
- package/src/devops.ts +119 -0
- package/src/index.ts +3 -0
- package/src/libs/affected-entities.ts +71 -0
- package/src/libs/config.ts +117 -0
- package/src/libs/digital-ocean/container-reg.ts +81 -0
- package/src/libs/discovery/dependencies.spec.ts +25 -0
- package/src/libs/discovery/dependencies.ts +73 -0
- package/src/libs/discovery/images.ts +57 -0
- package/src/libs/discovery/index.ts +60 -0
- package/src/libs/discovery/process-common.ts +55 -0
- package/src/libs/discovery/process-package-json.ts +47 -0
- package/src/libs/discovery/process-pyproject-toml.ts +43 -0
- package/src/libs/git-helpers.ts +32 -0
- package/src/libs/hetzner/reg-secret.ts +54 -0
- package/src/libs/k8s-constants.ts +83 -0
- package/src/libs/k8s-db.ts +83 -0
- package/src/libs/k8s-generate.ts +211 -0
- package/src/libs/k8s-helpers.ts +59 -0
- package/src/libs/k8s-image-config.ts +165 -0
- package/src/libs/k8s-job-waiter.ts +124 -0
- package/src/libs/k8s-namespace.ts +41 -0
- package/src/libs/k8s-redis.ts +31 -0
- package/src/libs/k8s-secrets-manager.ts +79 -0
- package/src/libs/validate-env.spec.ts +223 -0
- package/src/libs/validate-env.ts +266 -0
- package/src/target-templates/.devops/config/constants.yaml +17 -0
- package/src/target-templates/.devops/config/images.yaml +88 -0
- package/src/target-templates/.devops/docker-images/common/docker-common.sh +23 -0
- package/src/target-templates/.devops/docker-images/node-services/node-exec.sh +8 -0
- package/src/target-templates/.devops/docker-images/node-services/node-run.sh +8 -0
- package/src/target-templates/.devops/docker-images/node-services.Dockerfile +34 -0
- package/src/target-templates/.devops/docker-images/python-services/python-exec.sh +8 -0
- package/src/target-templates/.devops/docker-images/python-services/python-run.sh +8 -0
- package/src/target-templates/.devops/docker-images/python-services.Dockerfile +29 -0
- package/src/target-templates/.devops/env.example.yaml +23 -0
- package/src/target-templates/.devops/infra/hetzner/abandoned/harbor-values.yaml +30 -0
- package/src/target-templates/.devops/infra/hetzner/abandoned/hcloud-config.yaml +134 -0
- package/src/target-templates/.devops/infra/hetzner/cert-manager.yaml +25 -0
- package/src/target-templates/.devops/infra/hetzner/harbor-cert.yaml +13 -0
- package/src/target-templates/.devops/infra/hetzner/harbor-values.yaml +76 -0
- package/src/target-templates/.devops/infra/hetzner/hcloud-config.yaml +113 -0
- package/src/target-templates/.devops/infra/hetzner/ingress-nginx-annotations.yaml +49 -0
- package/src/target-templates/.devops/infra/hetzner/ingress-nginx-configmap.yaml +8 -0
- package/src/target-templates/.devops/infra/hetzner/retain-storage-class.yaml +8 -0
- package/src/target-templates/.devops/infra/monitoring-ingress.yaml +62 -0
- package/src/target-templates/.devops/infra/stackgres-ui-ingress.yaml +35 -0
- package/src/target-templates/.devops/infra/test.yaml +60 -0
- package/src/target-templates/.devops/manifests/_index.yaml +21 -0
- package/src/target-templates/.devops/manifests/cron-jobs.yaml.hb +55 -0
- package/src/target-templates/.devops/manifests/db-migrate-job.yaml.hb +42 -0
- package/src/target-templates/.devops/manifests/deployment-debug.yaml.hb +44 -0
- package/src/target-templates/.devops/manifests/deployment-process.yaml.hb +47 -0
- package/src/target-templates/.devops/manifests/deployment-web.yaml.hb +53 -0
- package/src/target-templates/.devops/manifests/ingress.yaml.hb +21 -0
- package/src/target-templates/.devops/manifests/prefect.yaml.hb +62 -0
- package/src/target-templates/.devops/manifests/service.yaml.hb +15 -0
- package/src/target-templates/.devops/milvus/production/milvus-values.yaml +2 -0
- package/src/target-templates/.devops/milvus/staging/milvus-values.yaml +2 -0
- package/src/target-templates/.devops/postgres/DailyOperatorRestart.yaml +54 -0
- package/src/target-templates/.devops/postgres/production/cluster/PodDisruptionBudget.yaml +27 -0
- package/src/target-templates/.devops/postgres/production/cluster/SGCluster.yaml +47 -0
- package/src/target-templates/.devops/postgres/production/cluster/StackGres-alerts.yaml +191 -0
- package/src/target-templates/.devops/postgres/production/configurations/06-SGDistributedLogs.yaml +11 -0
- package/src/target-templates/.devops/postgres/production/configurations/07-SGObjectStorage.yaml +18 -0
- package/src/target-templates/.devops/postgres/production/configurations/08-SGScript.yaml +12 -0
- package/src/target-templates/.devops/postgres/staging/cluster/SGCluster.yaml +42 -0
- package/src/target-templates/.devops/postgres/staging/configurations/07-SGObjectStorage.yaml +18 -0
- package/src/target-templates/.devops/postgres/staging/configurations/08-SGScript.yaml +12 -0
- package/src/target-templates/.devops/prefect/production/prefect-values.yaml +14 -0
- package/src/target-templates/.devops/prefect/staging/prefect-values.yaml +14 -0
- package/src/target-templates/.devops/redis/production/redis-values.yaml +20 -0
- package/src/target-templates/.devops/redis/staging/redis-values.yaml +8 -0
- package/src/target-templates/.envrc +5 -0
- package/src/target-templates/.github/actions/build-image@v1/action.yaml +86 -0
- package/src/target-templates/.github/actions/connect-to-digital-ocean@v1/action.yaml +29 -0
- package/src/target-templates/.github/actions/connect-to-hetzner@v1/action.yaml +31 -0
- package/src/target-templates/.github/actions/connect-to-infra@v1/action.yaml +46 -0
- package/src/target-templates/.github/actions/db-migrate@v1/action.yaml +23 -0
- package/src/target-templates/.github/actions/deploy-image@v1/action.yaml +33 -0
- package/src/target-templates/.github/actions/setup-prereq@v1/action.yaml +29 -0
- package/src/target-templates/.github/workflows/k8s-build.yaml +84 -0
- package/src/target-templates/applications/example-data-pipeline/pyproject.toml +14 -0
- package/src/target-templates/applications/example-data-pipeline/src/example_data_pipeline/main.py +38 -0
- package/src/target-templates/applications/example-node/index.ts +30 -0
- package/src/target-templates/applications/example-node/package.json +26 -0
- package/src/target-templates/applications/example-node/tsconfig.json +3 -0
- package/src/target-templates/applications/example-python/pyproject.toml +20 -0
- package/src/target-templates/applications/example-python/src/example_python/__init__.py +0 -0
- package/src/target-templates/applications/example-python/src/example_python/main.py +13 -0
- package/src/target-templates/applications/example-python/src/example_python/scripts.py +17 -0
- package/src/target-templates/applications/example-python/tests/__init__.py +0 -0
- package/src/target-templates/applications/jobs/README.md +68 -0
- package/src/target-templates/applications/jobs/index.ts +1 -0
- package/src/target-templates/applications/jobs/package.json +30 -0
- package/src/target-templates/applications/jobs/tsconfig.json +3 -0
- package/src/target-templates/config/.env.development +1 -0
- package/src/target-templates/config/.env.global +4 -0
- package/src/target-templates/config/.env.test +1 -0
- package/src/target-templates/db/db/__init__.py +0 -0
- package/src/target-templates/db/db/db_client_test.py +46 -0
- package/src/target-templates/db/db-client-test.ts +140 -0
- package/src/target-templates/db/db-client.ts +19 -0
- package/src/target-templates/db/env.yaml +4 -0
- package/src/target-templates/db/package.json +17 -0
- package/src/target-templates/db/prisma/schema.prisma +24 -0
- package/src/target-templates/db/prisma-setup-vitest.ts +27 -0
- package/src/target-templates/db/pyproject.toml +14 -0
- package/src/target-templates/db/tsconfig.json +3 -0
- package/src/target-templates/devops +3 -0
- package/src/target-templates/devopspy +3 -0
- package/src/target-templates/dml/package.json +7 -0
- package/src/target-templates/dml/tsconfig.json +3 -0
- package/src/target-templates/libs/example-node-lib/bun.lock +27 -0
- package/src/target-templates/libs/example-node-lib/index.ts +3 -0
- package/src/target-templates/libs/example-node-lib/package.json +12 -0
- package/src/target-templates/libs/example-node-lib/tsconfig.json +3 -0
- package/src/target-templates/libs/example-python-lib/pyproject.toml +11 -0
- package/src/target-templates/libs/example-python-lib/src/example_python_lib/__init__.py +2 -0
- package/src/target-templates/pyproject.toml +19 -0
- package/src/target-templates/tmp/.gitkeep +0 -0
- package/src/target-templates/tsconfig.json +27 -0
- package/src/test.ts +0 -0
- package/src/types/index.ts +173 -0
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,79 @@
|
|
1
|
+
import { z } from "zod";
|
2
|
+
export const SUPPORTED_LANGUAGES = ["python", "node"];
|
3
|
+
// Config files
|
4
|
+
export const constFileSchema = z.object({
|
5
|
+
"project-name": z.string(),
|
6
|
+
"infra": z.enum(["hetzner", "digitalocean"]),
|
7
|
+
"image-versions-to-keep": z.number(),
|
8
|
+
"registry-base-url": z.string(),
|
9
|
+
"registry-name": z.string(),
|
10
|
+
"extra-remote-environments": z.array(z.string()),
|
11
|
+
"extra-local-environments": z.array(z.string()),
|
12
|
+
});
|
13
|
+
const singleTemplateSchema = z.object({
|
14
|
+
"copy-common": z.boolean().optional(),
|
15
|
+
"extra-content": z.array(z.string()).optional(),
|
16
|
+
});
|
17
|
+
const singleImageSchema = z.object({
|
18
|
+
"image-template": z.string(),
|
19
|
+
"language": z.enum(SUPPORTED_LANGUAGES),
|
20
|
+
"domains": z.record(z.string()).optional(),
|
21
|
+
"debug-template": z.string(),
|
22
|
+
"can-db-migrate": z.boolean().optional(),
|
23
|
+
applications: z.array(z.string()),
|
24
|
+
});
|
25
|
+
export const imageFileSchema = z.object({
|
26
|
+
templates: z.record(singleTemplateSchema),
|
27
|
+
images: z.record(singleImageSchema),
|
28
|
+
});
|
29
|
+
const deploymentSchema = z.object({
|
30
|
+
/** The name of the composite template to build in order to support this deployment */
|
31
|
+
template: z.string(),
|
32
|
+
/** The name used by kubernetes objects. If ommitted, the name field from the enclosing context (e.g. package.json) is used. */
|
33
|
+
app_name: z.string().optional(),
|
34
|
+
/** This will be the name of the internal service used for intra-cluster communication */
|
35
|
+
service_name: z.string().optional(),
|
36
|
+
/** For services, the port to expose */
|
37
|
+
port: z.number().optional(),
|
38
|
+
/** This will be the subdomain of the exposed ingress. If not provided, taken from service_name */
|
39
|
+
subdomain: z.string().optional(),
|
40
|
+
/** For cron jobs */
|
41
|
+
cronJobs: z.array(z.object({
|
42
|
+
/** The name of the cron job. Used to identify in k8s. Should be unique among all cron jobs. */
|
43
|
+
name: z.string().optional(),
|
44
|
+
/** The cron schedule */
|
45
|
+
cron: z.string().optional(),
|
46
|
+
/** The curl command to invoke. Must be an array. */
|
47
|
+
curl: z.array(z.string()).optional(),
|
48
|
+
})).optional(),
|
49
|
+
prefectFlows: z.array(z.object({
|
50
|
+
/** The name of the container inside the prefect pod */
|
51
|
+
flow_name: z.string(),
|
52
|
+
/** The path to the file that runs the flow, relative to the project folder. E.g. src/data_pipeline/main.py */
|
53
|
+
script_path: z.string(),
|
54
|
+
})).optional()
|
55
|
+
/** The catchall below allows any other fields that might be in the package.json file */
|
56
|
+
}).catchall(z.any());
|
57
|
+
// ## Workspace Discovery: Languae-specific constructs
|
58
|
+
export const packageFileNodeSchema = z.object({
|
59
|
+
/** This is considered the project name */
|
60
|
+
name: z.string(),
|
61
|
+
/** Scripts exposed by this project. */
|
62
|
+
scripts: z.record(z.string()).optional(),
|
63
|
+
/** The dependencies of the project */
|
64
|
+
dependencies: z.record(z.string()).optional(),
|
65
|
+
/** When a deployment data is available, a k8s deployment is created */
|
66
|
+
deployment: deploymentSchema.optional(),
|
67
|
+
});
|
68
|
+
export const packageFilePythonSchema = z.object({
|
69
|
+
project: z.object({
|
70
|
+
name: z.string(),
|
71
|
+
dependencies: z.string().array().optional(),
|
72
|
+
}),
|
73
|
+
tool: z.object({
|
74
|
+
devops: z.object({
|
75
|
+
deployment: deploymentSchema.optional(),
|
76
|
+
scripts: z.record(z.string()).optional(),
|
77
|
+
}).optional(),
|
78
|
+
}).optional(),
|
79
|
+
});
|
package/package.json
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
{
|
2
|
+
"name": "@vaharoni/devops",
|
3
|
+
"type": "module",
|
4
|
+
"version": "1.0.47",
|
5
|
+
"description": "Devops utility",
|
6
|
+
"main": "./dist/index.js",
|
7
|
+
"types": "./dist/index.d.ts",
|
8
|
+
"files": [
|
9
|
+
"dist/**/*",
|
10
|
+
"src/**/*"
|
11
|
+
],
|
12
|
+
"bin": {
|
13
|
+
"devops": "dist/devops.js"
|
14
|
+
},
|
15
|
+
"scripts": {
|
16
|
+
"build": "tsc",
|
17
|
+
"test": "vitest run"
|
18
|
+
},
|
19
|
+
"repository": {
|
20
|
+
"type": "git",
|
21
|
+
"url": "git+https://github.com/vaharoni/devops.git"
|
22
|
+
},
|
23
|
+
"author": "Amit Aharoni",
|
24
|
+
"license": "MIT",
|
25
|
+
"bugs": {
|
26
|
+
"url": "https://github.com/vaharoni/devops/issues"
|
27
|
+
},
|
28
|
+
"homepage": "https://github.com/vaharoni/devops#readme",
|
29
|
+
"publishConfig": {
|
30
|
+
"access": "public"
|
31
|
+
},
|
32
|
+
"dependencies": {
|
33
|
+
"@dotenvx/dotenvx": "^1.38.3",
|
34
|
+
"@iarna/toml": "^2.2.5",
|
35
|
+
"chalk": "^5.3.0",
|
36
|
+
"concurrently": "^9.1.2",
|
37
|
+
"fs-extra": "11.2.0",
|
38
|
+
"glob": "^11.0.1",
|
39
|
+
"handlebars": "^4.7.8",
|
40
|
+
"lodash": "^4.17.21",
|
41
|
+
"tsx": "^4.19.3",
|
42
|
+
"yaml": "^2.4.2",
|
43
|
+
"zod": "^3.24.2"
|
44
|
+
},
|
45
|
+
"devDependencies": {
|
46
|
+
"@types/bun": "latest",
|
47
|
+
"@types/fs-extra": "^11.0.4",
|
48
|
+
"@types/handlebars": "^4.1.0",
|
49
|
+
"@types/lodash": "^4.17.16",
|
50
|
+
"vitest": "^1.6.0"
|
51
|
+
},
|
52
|
+
"peerDependencies": {
|
53
|
+
"typescript": "^5.8.2"
|
54
|
+
}
|
55
|
+
}
|
@@ -0,0 +1,31 @@
|
|
1
|
+
import { generateInternalAuthToken, parseInternalAuthTokenOrThrow } from "./internal-token";
|
2
|
+
|
3
|
+
/**
|
4
|
+
* A simple token generation/verification class that relies on the subject field of an internal JWT-like token. It can:
|
5
|
+
* - generate a short-lived (60s) token with the given subject
|
6
|
+
* - verify that a token has not expired and bears the given subject
|
7
|
+
*
|
8
|
+
* Relies on the MONOREPO_BASE_SECRET environment variable for signing and verifying the token.
|
9
|
+
*/
|
10
|
+
export class InternalToken {
|
11
|
+
constructor(public subject: string) {}
|
12
|
+
|
13
|
+
generate() {
|
14
|
+
return generateInternalAuthToken({ sub: this.subject });
|
15
|
+
}
|
16
|
+
|
17
|
+
verifyOrThrow(token: string) {
|
18
|
+
const parsedToken = parseInternalAuthTokenOrThrow(token);
|
19
|
+
if (parsedToken.sub !== this.subject) {
|
20
|
+
throw new Error('Invalid token');
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
verifyFromHeaderOrThrow(authorizationHeader?: string | null) {
|
25
|
+
if (!authorizationHeader) {
|
26
|
+
throw new Error('Authorization header not found');
|
27
|
+
}
|
28
|
+
const token = authorizationHeader.replace('Bearer ', '');
|
29
|
+
this.verifyOrThrow(token);
|
30
|
+
}
|
31
|
+
}
|
@@ -0,0 +1,53 @@
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
2
|
+
import { generateInternalAuthToken, parseInternalAuthTokenOrThrow } from './internal-token';
|
3
|
+
|
4
|
+
vi.mock('../../libs/config', () => ({
|
5
|
+
getConst: () => 'test',
|
6
|
+
}));
|
7
|
+
|
8
|
+
describe('generate and verify internal token', () => {
|
9
|
+
beforeEach(() => {
|
10
|
+
process.env.MONOREPO_BASE_SECRET = '1234567890abcdef';
|
11
|
+
})
|
12
|
+
|
13
|
+
it('works for default tokens', () => {
|
14
|
+
const token = generateInternalAuthToken();
|
15
|
+
const parsedPayload = parseInternalAuthTokenOrThrow(token);
|
16
|
+
expect(parsedPayload.iss).toEqual('test-internal');
|
17
|
+
expect(parsedPayload.exp - parsedPayload.iat).toEqual(60);
|
18
|
+
});
|
19
|
+
|
20
|
+
it('works for custom tokens', () => {
|
21
|
+
const payload = { hello: 'world' };
|
22
|
+
const token = generateInternalAuthToken({
|
23
|
+
customClaims: payload,
|
24
|
+
expiresInSeconds: 30,
|
25
|
+
aud: 'aud',
|
26
|
+
sub: 'sub',
|
27
|
+
});
|
28
|
+
const parsedPayload = parseInternalAuthTokenOrThrow<{
|
29
|
+
hello: string;
|
30
|
+
}>(token);
|
31
|
+
expect(parsedPayload.iss).toEqual('test-internal');
|
32
|
+
expect(parsedPayload.exp - parsedPayload.iat).toEqual(30);
|
33
|
+
expect(parsedPayload.hello).toEqual('world');
|
34
|
+
expect(parsedPayload.aud).toEqual('aud');
|
35
|
+
expect(parsedPayload.sub).toEqual('sub');
|
36
|
+
});
|
37
|
+
|
38
|
+
it('throws for expired tokens', () => {
|
39
|
+
const invalidToken = generateInternalAuthToken({
|
40
|
+
expiresInSeconds: -1,
|
41
|
+
});
|
42
|
+
expect(() => parseInternalAuthTokenOrThrow(invalidToken)).toThrowError('Token expired');
|
43
|
+
});
|
44
|
+
|
45
|
+
it('throws for invalid signature', () => {
|
46
|
+
const payload = { hello: 'world' };
|
47
|
+
const token = generateInternalAuthToken({
|
48
|
+
customClaims: payload,
|
49
|
+
});
|
50
|
+
const invalidToken = token.replace(/.$/, 'x');
|
51
|
+
expect(() => parseInternalAuthTokenOrThrow(invalidToken)).toThrowError('Invalid token');
|
52
|
+
});
|
53
|
+
});
|
@@ -0,0 +1,82 @@
|
|
1
|
+
import { getConst } from '../../libs/config';
|
2
|
+
import { sign, verify } from './secret';
|
3
|
+
|
4
|
+
export type InternalTokenClaims<CustomClaims extends object = object> =
|
5
|
+
CustomClaims & {
|
6
|
+
/** The token issuer */
|
7
|
+
iss: string;
|
8
|
+
/** Issued at */
|
9
|
+
iat: number;
|
10
|
+
/** Expires at */
|
11
|
+
exp: number;
|
12
|
+
/** The subject of the token. Should contain a string of the "service account" who bears the token. */
|
13
|
+
sub?: string;
|
14
|
+
/** The audience of the token. Should contain a string of who the token is intended for. */
|
15
|
+
aud?: string;
|
16
|
+
};
|
17
|
+
|
18
|
+
class InternalTokenError extends Error {
|
19
|
+
constructor(message: string) {
|
20
|
+
super(message);
|
21
|
+
this.name = 'InternalTokenError';
|
22
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
function defaultClaims({
|
27
|
+
expiresInSeconds,
|
28
|
+
sub,
|
29
|
+
aud,
|
30
|
+
}: {
|
31
|
+
expiresInSeconds: number;
|
32
|
+
sub?: string;
|
33
|
+
aud?: string;
|
34
|
+
}): InternalTokenClaims {
|
35
|
+
return {
|
36
|
+
iss: `${getConst('project-name')}-internal`,
|
37
|
+
iat: Math.floor(Date.now() / 1000),
|
38
|
+
exp: Math.floor(Date.now() / 1000) + expiresInSeconds,
|
39
|
+
sub,
|
40
|
+
aud,
|
41
|
+
};
|
42
|
+
}
|
43
|
+
|
44
|
+
export function generateInternalAuthToken({
|
45
|
+
customClaims = {},
|
46
|
+
expiresInSeconds = 60,
|
47
|
+
sub,
|
48
|
+
aud,
|
49
|
+
}: {
|
50
|
+
customClaims?: Record<string, string>;
|
51
|
+
expiresInSeconds?: number;
|
52
|
+
sub?: string;
|
53
|
+
aud?: string;
|
54
|
+
} = {}) {
|
55
|
+
const data = {
|
56
|
+
...customClaims,
|
57
|
+
// This should be after the customClaims so that custom claims cannot override the default claims
|
58
|
+
...defaultClaims({ expiresInSeconds, sub, aud }),
|
59
|
+
};
|
60
|
+
const str = JSON.stringify(data);
|
61
|
+
const encodedData = Buffer.from(str).toString('base64');
|
62
|
+
const signature = sign(encodedData);
|
63
|
+
return `${encodedData}.${signature}`;
|
64
|
+
}
|
65
|
+
|
66
|
+
export function parseInternalAuthTokenOrThrow<CustomClaims extends object = object>(
|
67
|
+
token: string,
|
68
|
+
): InternalTokenClaims<CustomClaims> {
|
69
|
+
const [encodedData, signature] = token.split('.');
|
70
|
+
const isSignatureOk = verify(encodedData, signature);
|
71
|
+
if (!isSignatureOk) {
|
72
|
+
throw new InternalTokenError('Invalid token');
|
73
|
+
}
|
74
|
+
const dataStr = Buffer.from(encodedData, 'base64').toString('utf-8');
|
75
|
+
const data: InternalTokenClaims<CustomClaims> = JSON.parse(dataStr);
|
76
|
+
|
77
|
+
if (data.exp < Math.floor(Date.now() / 1000)) {
|
78
|
+
throw new InternalTokenError('Token expired');
|
79
|
+
}
|
80
|
+
|
81
|
+
return data;
|
82
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import { beforeEach, describe, expect, it } from 'vitest';
|
2
|
+
import { sign, verify } from './secret';
|
3
|
+
|
4
|
+
describe('sign and verify', () => {
|
5
|
+
beforeEach(() => {
|
6
|
+
process.env.MONOREPO_BASE_SECRET = '1234567890abcdef';
|
7
|
+
})
|
8
|
+
|
9
|
+
it('verify should return true for correct signature', async () => {
|
10
|
+
const sig = sign('data');
|
11
|
+
expect(verify('data', sig)).toEqual(true);
|
12
|
+
});
|
13
|
+
|
14
|
+
it('verify should return false for correct signature', async () => {
|
15
|
+
const sig = sign('data');
|
16
|
+
expect(verify('data2', sig)).toEqual(false);
|
17
|
+
});
|
18
|
+
});
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import { createHmac } from 'crypto';
|
2
|
+
|
3
|
+
export function sign(data: string) {
|
4
|
+
const keyStr = process.env.MONOREPO_BASE_SECRET;
|
5
|
+
if (!keyStr) throw new Error('Secret not set');
|
6
|
+
const key = Buffer.from(keyStr, 'hex');
|
7
|
+
return createHmac('sha256', key).update(data).digest('hex');
|
8
|
+
}
|
9
|
+
|
10
|
+
export function verify(data: string, signature: string) {
|
11
|
+
const generatedSignature = sign(data);
|
12
|
+
return generatedSignature === signature;
|
13
|
+
}
|
@@ -0,0 +1,35 @@
|
|
1
|
+
import { workspaces } from "../../libs/discovery";
|
2
|
+
|
3
|
+
let _portLookupByServiceName: Record<string, number> | null = null;
|
4
|
+
|
5
|
+
function getPortLookup() {
|
6
|
+
if (_portLookupByServiceName) return _portLookupByServiceName;
|
7
|
+
if (process.env["IS_KUBERNETES"] === "true") {
|
8
|
+
throw new Error(
|
9
|
+
"getPortLookup() should only be used in local development. In production, the service name is sufficient."
|
10
|
+
);
|
11
|
+
}
|
12
|
+
|
13
|
+
_portLookupByServiceName = {};
|
14
|
+
Object.values(workspaces()).forEach((workspace) => {
|
15
|
+
workspace.packageDataEntries.forEach((pkg) => {
|
16
|
+
const serviceName = pkg.deployment?.service_name;
|
17
|
+
const port = pkg.deployment?.port;
|
18
|
+
if (!serviceName || !port) return;
|
19
|
+
const existing = _portLookupByServiceName![serviceName];
|
20
|
+
if (!existing) {
|
21
|
+
_portLookupByServiceName![serviceName] = port;
|
22
|
+
} else if (existing !== port) {
|
23
|
+
console.error(
|
24
|
+
`Service name ${serviceName} has conflicting ports: ${existing} and ${port}`
|
25
|
+
);
|
26
|
+
process.exit(1);
|
27
|
+
}
|
28
|
+
});
|
29
|
+
});
|
30
|
+
return _portLookupByServiceName;
|
31
|
+
}
|
32
|
+
|
33
|
+
export function getPortForServiceName(serviceName: string) {
|
34
|
+
return getPortLookup()[serviceName];
|
35
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import { getPortForServiceName } from "./dev-discovery-loader";
|
2
|
+
|
3
|
+
export function getServiceEndpoint(serviceName: string): string {
|
4
|
+
if (process.env["IS_KUBERNETES"] === "true") {
|
5
|
+
return `http://${serviceName}`;
|
6
|
+
}
|
7
|
+
|
8
|
+
const servicePort = getPortForServiceName(serviceName);
|
9
|
+
if (!servicePort)
|
10
|
+
throw new Error(`Port not found for service ${serviceName}`);
|
11
|
+
return `http://127.0.0.1:${servicePort}`;
|
12
|
+
}
|
@@ -0,0 +1,116 @@
|
|
1
|
+
import {
|
2
|
+
findImagesAffected,
|
3
|
+
findImagesWithAffectedWorkspace,
|
4
|
+
isImageAffected,
|
5
|
+
isWorkspaceAffected,
|
6
|
+
} from "../libs/affected-entities";
|
7
|
+
import { getImageData } from "../libs/config";
|
8
|
+
import { CLICommandParser, printUsageAndExit, StrongParams } from "./common";
|
9
|
+
|
10
|
+
const oneLiner =
|
11
|
+
"Command to check whether an image or a workspace is affected by certain commit(s)";
|
12
|
+
const keyExamples = `
|
13
|
+
$ devops affected list-images
|
14
|
+
$ devops affected workspace db --base <sha1> --head <sha2>
|
15
|
+
$ devops affected image main-node --from-live-version
|
16
|
+
$ devops affected find-migrator --from-live-version
|
17
|
+
`;
|
18
|
+
|
19
|
+
const usage = `
|
20
|
+
${oneLiner}
|
21
|
+
|
22
|
+
GENERAL USAGE
|
23
|
+
List
|
24
|
+
devops affected list-images --base [SHA1] --head [SHA2]
|
25
|
+
devops affected list-images --from-live-version
|
26
|
+
|
27
|
+
These return a list of all images affected by the given commits.
|
28
|
+
|
29
|
+
Checkers
|
30
|
+
devops affected workspace <workspace> --base [SHA1] --head [SHA2]
|
31
|
+
|
32
|
+
devops affected image <image> --base [SHA1] --head [SHA2]
|
33
|
+
devops affected image <image> --from-live-version
|
34
|
+
|
35
|
+
These return "true" or "false".
|
36
|
+
|
37
|
+
Finders
|
38
|
+
devops affected find-migrator --base [SHA1] --head [SHA2]
|
39
|
+
devops affected find-migrator --from-live-version
|
40
|
+
|
41
|
+
When --base and --head are used, it checks whether the db project is affected. If it is, it returns the name of one random
|
42
|
+
affected image.
|
43
|
+
When --from-live-version is used, it iterates on the live version of each image that depends on db, and returns the first image that is
|
44
|
+
affected by a db project change since that commit.
|
45
|
+
|
46
|
+
If the db project is unaffected, returns an empty string.
|
47
|
+
|
48
|
+
Options
|
49
|
+
Which commits are regarded for the affected calculation can be changed using:
|
50
|
+
--base Base of the current branch (HEAD^ by default)
|
51
|
+
--head Latest commit of the current branch (HEAD by default)
|
52
|
+
--from-live-version Use the live version of the image/workspace as the base (see devops image version get)
|
53
|
+
|
54
|
+
If --from-live-version is present, --base and --head are ignored.
|
55
|
+
|
56
|
+
EXAMPLES
|
57
|
+
${keyExamples.trim()}
|
58
|
+
`;
|
59
|
+
|
60
|
+
async function run(cmdObj: CLICommandParser) {
|
61
|
+
const options = cmdObj.parseOptions({
|
62
|
+
params: ["--base", "--head"],
|
63
|
+
booleans: ["--from-live-version"],
|
64
|
+
});
|
65
|
+
if (cmdObj.help || options.args.length < 1) printUsageAndExit(usage);
|
66
|
+
const baseSha = options.options["--base"]?.toString();
|
67
|
+
const headSha = options.options["--head"]?.toString();
|
68
|
+
const fromLiveVersion = Boolean(options.options["--from-live-version"]);
|
69
|
+
const commonOpts = {
|
70
|
+
baseSha,
|
71
|
+
headSha,
|
72
|
+
fromLiveVersion,
|
73
|
+
monorepoEnv: cmdObj.env,
|
74
|
+
};
|
75
|
+
|
76
|
+
const [cmd, imageOrWorkspace] = options.args;
|
77
|
+
const params = new StrongParams(usage, { imageOrWorkspace });
|
78
|
+
|
79
|
+
switch (cmd) {
|
80
|
+
case "list-images": {
|
81
|
+
console.log(findImagesAffected(commonOpts).join("\n"));
|
82
|
+
break;
|
83
|
+
}
|
84
|
+
case "workspace": {
|
85
|
+
// prettier-ignore
|
86
|
+
const affected = isWorkspaceAffected(params.required("imageOrWorkspace"), commonOpts);
|
87
|
+
console.log(affected ? "true" : "false");
|
88
|
+
break;
|
89
|
+
}
|
90
|
+
case "image": {
|
91
|
+
const affected = isImageAffected(
|
92
|
+
params.required("imageOrWorkspace"),
|
93
|
+
commonOpts
|
94
|
+
);
|
95
|
+
console.log(affected ? "true" : "false");
|
96
|
+
break;
|
97
|
+
}
|
98
|
+
case "find-migrator": {
|
99
|
+
const migrator = findImagesWithAffectedWorkspace("db", commonOpts)
|
100
|
+
if (!migrator.length) break;
|
101
|
+
const firstMigrator = migrator.find(imageName => getImageData(imageName)["can-db-migrate"]);
|
102
|
+
if (!firstMigrator) {
|
103
|
+
console.error(`The db project was changed and affects the following images: ${migrator.join(", ")}. However, no image in the list has can-db-migrate=true in .devops/config/images.yaml.`);
|
104
|
+
process.exit(1);
|
105
|
+
}
|
106
|
+
console.log(firstMigrator);
|
107
|
+
break;
|
108
|
+
}
|
109
|
+
default:
|
110
|
+
printUsageAndExit(usage);
|
111
|
+
}
|
112
|
+
}
|
113
|
+
|
114
|
+
export default {
|
115
|
+
affected: { oneLiner, keyExamples, run },
|
116
|
+
};
|
@@ -0,0 +1,78 @@
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
2
|
+
import { CLICommandParser } from './common';
|
3
|
+
|
4
|
+
describe('CLICommandParser', () => {
|
5
|
+
// Extra white space intentional
|
6
|
+
const subject = new CLICommandParser(
|
7
|
+
'run tmp/test.sh --env production --in workspace --flag arg'.split(' '),
|
8
|
+
);
|
9
|
+
|
10
|
+
it('constructor: builds object correctly', () => {
|
11
|
+
expect(subject.command).toEqual('run');
|
12
|
+
expect(subject.env).toEqual('production');
|
13
|
+
expect(subject.args).toEqual([
|
14
|
+
'tmp/test.sh',
|
15
|
+
'--in',
|
16
|
+
'workspace',
|
17
|
+
'--flag',
|
18
|
+
'arg',
|
19
|
+
]);
|
20
|
+
});
|
21
|
+
|
22
|
+
describe('parseOptions', () => {
|
23
|
+
it('detects params and booleans', () => {
|
24
|
+
const res = subject.parseOptions({
|
25
|
+
params: ['--in'],
|
26
|
+
booleans: ['--flag'],
|
27
|
+
});
|
28
|
+
expect(res.args).toEqual(['tmp/test.sh', 'arg']);
|
29
|
+
expect(res.argsStr).toEqual('tmp/test.sh arg');
|
30
|
+
expect(res.options).toEqual({ '--in': 'workspace', '--flag': true });
|
31
|
+
});
|
32
|
+
|
33
|
+
it('leaves intact params that are not in the list', () => {
|
34
|
+
const res = subject.parseOptions();
|
35
|
+
expect(res.args).toEqual([
|
36
|
+
'tmp/test.sh',
|
37
|
+
'--in',
|
38
|
+
'workspace',
|
39
|
+
'--flag',
|
40
|
+
'arg',
|
41
|
+
]);
|
42
|
+
expect(res.argsStr).toEqual('tmp/test.sh --in workspace --flag arg');
|
43
|
+
expect(res.options).toEqual({});
|
44
|
+
});
|
45
|
+
|
46
|
+
it('handles passthrough args when they exist', () => {
|
47
|
+
const altSubject = new CLICommandParser(
|
48
|
+
'run tmp/test.sh --env production --in workspace --flag arg -- p1 p2'.split(
|
49
|
+
' ',
|
50
|
+
),
|
51
|
+
);
|
52
|
+
const res = altSubject.parseOptions({
|
53
|
+
params: ['--in'],
|
54
|
+
booleans: ['--flag'],
|
55
|
+
passthroughArgs: true,
|
56
|
+
});
|
57
|
+
expect(res.args).toEqual(['tmp/test.sh', 'arg']);
|
58
|
+
expect(res.argsStr).toEqual('tmp/test.sh arg');
|
59
|
+
expect(res.options).toEqual({ '--in': 'workspace', '--flag': true });
|
60
|
+
expect(res.passthrough).toEqual(['p1', 'p2']);
|
61
|
+
});
|
62
|
+
|
63
|
+
it('handles passthrough args when they do not exist', () => {
|
64
|
+
const altSubject = new CLICommandParser(
|
65
|
+
'run tmp/test.sh --env production --in workspace --flag arg'.split(' '),
|
66
|
+
);
|
67
|
+
const res = altSubject.parseOptions({
|
68
|
+
params: ['--in'],
|
69
|
+
booleans: ['--flag'],
|
70
|
+
passthroughArgs: true,
|
71
|
+
});
|
72
|
+
expect(res.args).toEqual(['tmp/test.sh', 'arg']);
|
73
|
+
expect(res.argsStr).toEqual('tmp/test.sh arg');
|
74
|
+
expect(res.options).toEqual({ '--in': 'workspace', '--flag': true });
|
75
|
+
expect(res.passthrough).toEqual([]);
|
76
|
+
});
|
77
|
+
});
|
78
|
+
});
|