@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.
Files changed (342) hide show
  1. package/README.md +51 -0
  2. package/dist/app-support/crypto/index.d.ts +15 -0
  3. package/dist/app-support/crypto/index.d.ts.map +1 -0
  4. package/dist/app-support/crypto/index.js +30 -0
  5. package/dist/app-support/crypto/internal-token.d.ts +20 -0
  6. package/dist/app-support/crypto/internal-token.d.ts.map +1 -0
  7. package/dist/app-support/crypto/internal-token.js +42 -0
  8. package/dist/app-support/crypto/internal-token.spec.d.ts +2 -0
  9. package/dist/app-support/crypto/internal-token.spec.d.ts.map +1 -0
  10. package/dist/app-support/crypto/internal-token.spec.js +45 -0
  11. package/dist/app-support/crypto/secret.d.ts +3 -0
  12. package/dist/app-support/crypto/secret.d.ts.map +1 -0
  13. package/dist/app-support/crypto/secret.js +12 -0
  14. package/dist/app-support/crypto/secret.spec.d.ts +2 -0
  15. package/dist/app-support/crypto/secret.spec.d.ts.map +1 -0
  16. package/dist/app-support/crypto/secret.spec.js +15 -0
  17. package/dist/app-support/discovery/dev-discovery-loader.d.ts +2 -0
  18. package/dist/app-support/discovery/dev-discovery-loader.d.ts.map +1 -0
  19. package/dist/app-support/discovery/dev-discovery-loader.js +30 -0
  20. package/dist/app-support/discovery/service-endpoint.d.ts +2 -0
  21. package/dist/app-support/discovery/service-endpoint.d.ts.map +1 -0
  22. package/dist/app-support/discovery/service-endpoint.js +10 -0
  23. package/dist/cli/affected.d.ts +11 -0
  24. package/dist/cli/affected.d.ts.map +1 -0
  25. package/dist/cli/affected.js +103 -0
  26. package/dist/cli/common.d.ts +89 -0
  27. package/dist/cli/common.d.ts.map +1 -0
  28. package/dist/cli/common.js +236 -0
  29. package/dist/cli/common.spec.d.ts +2 -0
  30. package/dist/cli/common.spec.d.ts.map +1 -0
  31. package/dist/cli/common.spec.js +64 -0
  32. package/dist/cli/console.d.ts +11 -0
  33. package/dist/cli/console.d.ts.map +1 -0
  34. package/dist/cli/console.js +35 -0
  35. package/dist/cli/constant.d.ts +11 -0
  36. package/dist/cli/constant.d.ts.map +1 -0
  37. package/dist/cli/constant.js +22 -0
  38. package/dist/cli/db.d.ts +11 -0
  39. package/dist/cli/db.d.ts.map +1 -0
  40. package/dist/cli/db.js +119 -0
  41. package/dist/cli/dml.d.ts +11 -0
  42. package/dist/cli/dml.d.ts.map +1 -0
  43. package/dist/cli/dml.js +116 -0
  44. package/dist/cli/env.d.ts +11 -0
  45. package/dist/cli/env.d.ts.map +1 -0
  46. package/dist/cli/env.js +67 -0
  47. package/dist/cli/exec.d.ts +11 -0
  48. package/dist/cli/exec.d.ts.map +1 -0
  49. package/dist/cli/exec.js +50 -0
  50. package/dist/cli/image.d.ts +11 -0
  51. package/dist/cli/image.d.ts.map +1 -0
  52. package/dist/cli/image.js +140 -0
  53. package/dist/cli/init.d.ts +11 -0
  54. package/dist/cli/init.d.ts.map +1 -0
  55. package/dist/cli/init.js +66 -0
  56. package/dist/cli/internal-curl.d.ts +11 -0
  57. package/dist/cli/internal-curl.d.ts.map +1 -0
  58. package/dist/cli/internal-curl.js +43 -0
  59. package/dist/cli/job.d.ts +11 -0
  60. package/dist/cli/job.d.ts.map +1 -0
  61. package/dist/cli/job.js +67 -0
  62. package/dist/cli/jwt.d.ts +11 -0
  63. package/dist/cli/jwt.d.ts.map +1 -0
  64. package/dist/cli/jwt.js +27 -0
  65. package/dist/cli/namespace.d.ts +11 -0
  66. package/dist/cli/namespace.d.ts.map +1 -0
  67. package/dist/cli/namespace.js +70 -0
  68. package/dist/cli/prep-build.d.ts +11 -0
  69. package/dist/cli/prep-build.d.ts.map +1 -0
  70. package/dist/cli/prep-build.js +82 -0
  71. package/dist/cli/prisma.d.ts +11 -0
  72. package/dist/cli/prisma.d.ts.map +1 -0
  73. package/dist/cli/prisma.js +25 -0
  74. package/dist/cli/redis.d.ts +11 -0
  75. package/dist/cli/redis.d.ts.map +1 -0
  76. package/dist/cli/redis.js +76 -0
  77. package/dist/cli/registry.d.ts +11 -0
  78. package/dist/cli/registry.d.ts.map +1 -0
  79. package/dist/cli/registry.js +58 -0
  80. package/dist/cli/run-many.d.ts +11 -0
  81. package/dist/cli/run-many.d.ts.map +1 -0
  82. package/dist/cli/run-many.js +50 -0
  83. package/dist/cli/run.d.ts +11 -0
  84. package/dist/cli/run.d.ts.map +1 -0
  85. package/dist/cli/run.js +37 -0
  86. package/dist/cli/template.d.ts +11 -0
  87. package/dist/cli/template.d.ts.map +1 -0
  88. package/dist/cli/template.js +123 -0
  89. package/dist/cli/test.d.ts +11 -0
  90. package/dist/cli/test.d.ts.map +1 -0
  91. package/dist/cli/test.js +28 -0
  92. package/dist/devops.d.ts +3 -0
  93. package/dist/devops.d.ts.map +1 -0
  94. package/dist/devops.js +103 -0
  95. package/dist/index.d.ts +4 -0
  96. package/dist/index.d.ts.map +1 -0
  97. package/dist/index.js +3 -0
  98. package/dist/libs/affected-entities.d.ts +15 -0
  99. package/dist/libs/affected-entities.d.ts.map +1 -0
  100. package/dist/libs/affected-entities.js +52 -0
  101. package/dist/libs/config.d.ts +6 -0
  102. package/dist/libs/config.d.ts.map +1 -0
  103. package/dist/libs/config.js +98 -0
  104. package/dist/libs/dependencies.d.ts +19 -0
  105. package/dist/libs/dependencies.d.ts.map +1 -0
  106. package/dist/libs/dependencies.js +62 -0
  107. package/dist/libs/dependencies.spec.d.ts +2 -0
  108. package/dist/libs/dependencies.spec.d.ts.map +1 -0
  109. package/dist/libs/dependencies.spec.js +21 -0
  110. package/dist/libs/digital-ocean/container-reg.d.ts +6 -0
  111. package/dist/libs/digital-ocean/container-reg.d.ts.map +1 -0
  112. package/dist/libs/digital-ocean/container-reg.js +69 -0
  113. package/dist/libs/discovery/dependencies.d.ts +19 -0
  114. package/dist/libs/discovery/dependencies.d.ts.map +1 -0
  115. package/dist/libs/discovery/dependencies.js +62 -0
  116. package/dist/libs/discovery/dependencies.spec.d.ts +2 -0
  117. package/dist/libs/discovery/dependencies.spec.d.ts.map +1 -0
  118. package/dist/libs/discovery/dependencies.spec.js +21 -0
  119. package/dist/libs/discovery/images.d.ts +5 -0
  120. package/dist/libs/discovery/images.d.ts.map +1 -0
  121. package/dist/libs/discovery/images.js +45 -0
  122. package/dist/libs/discovery/index.d.ts +5 -0
  123. package/dist/libs/discovery/index.d.ts.map +1 -0
  124. package/dist/libs/discovery/index.js +55 -0
  125. package/dist/libs/discovery/package-json-processor.d.ts +3 -0
  126. package/dist/libs/discovery/package-json-processor.d.ts.map +1 -0
  127. package/dist/libs/discovery/package-json-processor.js +34 -0
  128. package/dist/libs/discovery/process-common.d.ts +25 -0
  129. package/dist/libs/discovery/process-common.d.ts.map +1 -0
  130. package/dist/libs/discovery/process-common.js +40 -0
  131. package/dist/libs/discovery/process-package-json.d.ts +3 -0
  132. package/dist/libs/discovery/process-package-json.d.ts.map +1 -0
  133. package/dist/libs/discovery/process-package-json.js +34 -0
  134. package/dist/libs/discovery/process-pyproject-toml.d.ts +3 -0
  135. package/dist/libs/discovery/process-pyproject-toml.d.ts.map +1 -0
  136. package/dist/libs/discovery/process-pyproject-toml.js +36 -0
  137. package/dist/libs/discovery/pyproject-toml-processor.d.ts +3 -0
  138. package/dist/libs/discovery/pyproject-toml-processor.d.ts.map +1 -0
  139. package/dist/libs/discovery/pyproject-toml-processor.js +39 -0
  140. package/dist/libs/git-helpers.d.ts +8 -0
  141. package/dist/libs/git-helpers.d.ts.map +1 -0
  142. package/dist/libs/git-helpers.js +20 -0
  143. package/dist/libs/hetzner/reg-secret.d.ts +3 -0
  144. package/dist/libs/hetzner/reg-secret.d.ts.map +1 -0
  145. package/dist/libs/hetzner/reg-secret.js +39 -0
  146. package/dist/libs/k8s-constants.d.ts +12 -0
  147. package/dist/libs/k8s-constants.d.ts.map +1 -0
  148. package/dist/libs/k8s-constants.js +66 -0
  149. package/dist/libs/k8s-db.d.ts +18 -0
  150. package/dist/libs/k8s-db.d.ts.map +1 -0
  151. package/dist/libs/k8s-db.js +73 -0
  152. package/dist/libs/k8s-generate.d.ts +17 -0
  153. package/dist/libs/k8s-generate.d.ts.map +1 -0
  154. package/dist/libs/k8s-generate.js +179 -0
  155. package/dist/libs/k8s-helpers.d.ts +11 -0
  156. package/dist/libs/k8s-helpers.d.ts.map +1 -0
  157. package/dist/libs/k8s-helpers.js +42 -0
  158. package/dist/libs/k8s-image-config.d.ts +8 -0
  159. package/dist/libs/k8s-image-config.d.ts.map +1 -0
  160. package/dist/libs/k8s-image-config.js +113 -0
  161. package/dist/libs/k8s-job-waiter.d.ts +8 -0
  162. package/dist/libs/k8s-job-waiter.d.ts.map +1 -0
  163. package/dist/libs/k8s-job-waiter.js +84 -0
  164. package/dist/libs/k8s-namespace.d.ts +7 -0
  165. package/dist/libs/k8s-namespace.d.ts.map +1 -0
  166. package/dist/libs/k8s-namespace.js +27 -0
  167. package/dist/libs/k8s-redis.d.ts +6 -0
  168. package/dist/libs/k8s-redis.d.ts.map +1 -0
  169. package/dist/libs/k8s-redis.js +31 -0
  170. package/dist/libs/k8s-secrets-manager.d.ts +5 -0
  171. package/dist/libs/k8s-secrets-manager.d.ts.map +1 -0
  172. package/dist/libs/k8s-secrets-manager.js +61 -0
  173. package/dist/libs/validate-env.d.ts +56 -0
  174. package/dist/libs/validate-env.d.ts.map +1 -0
  175. package/dist/libs/validate-env.js +214 -0
  176. package/dist/libs/validate-env.spec.d.ts +2 -0
  177. package/dist/libs/validate-env.spec.d.ts.map +1 -0
  178. package/dist/libs/validate-env.spec.js +168 -0
  179. package/dist/libs/workspace-discovery.d.ts +2 -0
  180. package/dist/libs/workspace-discovery.d.ts.map +1 -0
  181. package/dist/libs/workspace-discovery.js +75 -0
  182. package/dist/test.d.ts +2 -0
  183. package/dist/test.d.ts.map +1 -0
  184. package/dist/test.js +1 -0
  185. package/dist/types/index.d.ts +925 -0
  186. package/dist/types/index.d.ts.map +1 -0
  187. package/dist/types/index.js +79 -0
  188. package/package.json +55 -0
  189. package/src/app-support/crypto/index.ts +31 -0
  190. package/src/app-support/crypto/internal-token.spec.ts +53 -0
  191. package/src/app-support/crypto/internal-token.ts +82 -0
  192. package/src/app-support/crypto/secret.spec.ts +18 -0
  193. package/src/app-support/crypto/secret.ts +13 -0
  194. package/src/app-support/discovery/dev-discovery-loader.ts +35 -0
  195. package/src/app-support/discovery/service-endpoint.ts +12 -0
  196. package/src/cli/affected.ts +116 -0
  197. package/src/cli/common.spec.ts +78 -0
  198. package/src/cli/common.ts +323 -0
  199. package/src/cli/console.ts +46 -0
  200. package/src/cli/constant.ts +25 -0
  201. package/src/cli/db.ts +133 -0
  202. package/src/cli/dml.ts +126 -0
  203. package/src/cli/env.ts +87 -0
  204. package/src/cli/exec.sh +21 -0
  205. package/src/cli/exec.ts +57 -0
  206. package/src/cli/image.ts +197 -0
  207. package/src/cli/init.ts +75 -0
  208. package/src/cli/internal-curl.ts +48 -0
  209. package/src/cli/job.ts +80 -0
  210. package/src/cli/jwt.ts +32 -0
  211. package/src/cli/namespace.ts +78 -0
  212. package/src/cli/prep-build.ts +96 -0
  213. package/src/cli/prisma.ts +33 -0
  214. package/src/cli/redis.ts +83 -0
  215. package/src/cli/registry.ts +76 -0
  216. package/src/cli/run-many.ts +61 -0
  217. package/src/cli/run.ts +46 -0
  218. package/src/cli/template.ts +169 -0
  219. package/src/cli/test.ts +30 -0
  220. package/src/devops.ts +119 -0
  221. package/src/index.ts +3 -0
  222. package/src/libs/affected-entities.ts +71 -0
  223. package/src/libs/config.ts +117 -0
  224. package/src/libs/digital-ocean/container-reg.ts +81 -0
  225. package/src/libs/discovery/dependencies.spec.ts +25 -0
  226. package/src/libs/discovery/dependencies.ts +73 -0
  227. package/src/libs/discovery/images.ts +57 -0
  228. package/src/libs/discovery/index.ts +60 -0
  229. package/src/libs/discovery/process-common.ts +55 -0
  230. package/src/libs/discovery/process-package-json.ts +47 -0
  231. package/src/libs/discovery/process-pyproject-toml.ts +43 -0
  232. package/src/libs/git-helpers.ts +32 -0
  233. package/src/libs/hetzner/reg-secret.ts +54 -0
  234. package/src/libs/k8s-constants.ts +83 -0
  235. package/src/libs/k8s-db.ts +83 -0
  236. package/src/libs/k8s-generate.ts +211 -0
  237. package/src/libs/k8s-helpers.ts +59 -0
  238. package/src/libs/k8s-image-config.ts +165 -0
  239. package/src/libs/k8s-job-waiter.ts +124 -0
  240. package/src/libs/k8s-namespace.ts +41 -0
  241. package/src/libs/k8s-redis.ts +31 -0
  242. package/src/libs/k8s-secrets-manager.ts +79 -0
  243. package/src/libs/validate-env.spec.ts +223 -0
  244. package/src/libs/validate-env.ts +266 -0
  245. package/src/target-templates/.devops/config/constants.yaml +17 -0
  246. package/src/target-templates/.devops/config/images.yaml +88 -0
  247. package/src/target-templates/.devops/docker-images/common/docker-common.sh +23 -0
  248. package/src/target-templates/.devops/docker-images/node-services/node-exec.sh +8 -0
  249. package/src/target-templates/.devops/docker-images/node-services/node-run.sh +8 -0
  250. package/src/target-templates/.devops/docker-images/node-services.Dockerfile +34 -0
  251. package/src/target-templates/.devops/docker-images/python-services/python-exec.sh +8 -0
  252. package/src/target-templates/.devops/docker-images/python-services/python-run.sh +8 -0
  253. package/src/target-templates/.devops/docker-images/python-services.Dockerfile +29 -0
  254. package/src/target-templates/.devops/env.example.yaml +23 -0
  255. package/src/target-templates/.devops/infra/hetzner/abandoned/harbor-values.yaml +30 -0
  256. package/src/target-templates/.devops/infra/hetzner/abandoned/hcloud-config.yaml +134 -0
  257. package/src/target-templates/.devops/infra/hetzner/cert-manager.yaml +25 -0
  258. package/src/target-templates/.devops/infra/hetzner/harbor-cert.yaml +13 -0
  259. package/src/target-templates/.devops/infra/hetzner/harbor-values.yaml +76 -0
  260. package/src/target-templates/.devops/infra/hetzner/hcloud-config.yaml +113 -0
  261. package/src/target-templates/.devops/infra/hetzner/ingress-nginx-annotations.yaml +49 -0
  262. package/src/target-templates/.devops/infra/hetzner/ingress-nginx-configmap.yaml +8 -0
  263. package/src/target-templates/.devops/infra/hetzner/retain-storage-class.yaml +8 -0
  264. package/src/target-templates/.devops/infra/monitoring-ingress.yaml +62 -0
  265. package/src/target-templates/.devops/infra/stackgres-ui-ingress.yaml +35 -0
  266. package/src/target-templates/.devops/infra/test.yaml +60 -0
  267. package/src/target-templates/.devops/manifests/_index.yaml +21 -0
  268. package/src/target-templates/.devops/manifests/cron-jobs.yaml.hb +55 -0
  269. package/src/target-templates/.devops/manifests/db-migrate-job.yaml.hb +42 -0
  270. package/src/target-templates/.devops/manifests/deployment-debug.yaml.hb +44 -0
  271. package/src/target-templates/.devops/manifests/deployment-process.yaml.hb +47 -0
  272. package/src/target-templates/.devops/manifests/deployment-web.yaml.hb +53 -0
  273. package/src/target-templates/.devops/manifests/ingress.yaml.hb +21 -0
  274. package/src/target-templates/.devops/manifests/prefect.yaml.hb +62 -0
  275. package/src/target-templates/.devops/manifests/service.yaml.hb +15 -0
  276. package/src/target-templates/.devops/milvus/production/milvus-values.yaml +2 -0
  277. package/src/target-templates/.devops/milvus/staging/milvus-values.yaml +2 -0
  278. package/src/target-templates/.devops/postgres/DailyOperatorRestart.yaml +54 -0
  279. package/src/target-templates/.devops/postgres/production/cluster/PodDisruptionBudget.yaml +27 -0
  280. package/src/target-templates/.devops/postgres/production/cluster/SGCluster.yaml +47 -0
  281. package/src/target-templates/.devops/postgres/production/cluster/StackGres-alerts.yaml +191 -0
  282. package/src/target-templates/.devops/postgres/production/configurations/06-SGDistributedLogs.yaml +11 -0
  283. package/src/target-templates/.devops/postgres/production/configurations/07-SGObjectStorage.yaml +18 -0
  284. package/src/target-templates/.devops/postgres/production/configurations/08-SGScript.yaml +12 -0
  285. package/src/target-templates/.devops/postgres/staging/cluster/SGCluster.yaml +42 -0
  286. package/src/target-templates/.devops/postgres/staging/configurations/07-SGObjectStorage.yaml +18 -0
  287. package/src/target-templates/.devops/postgres/staging/configurations/08-SGScript.yaml +12 -0
  288. package/src/target-templates/.devops/prefect/production/prefect-values.yaml +14 -0
  289. package/src/target-templates/.devops/prefect/staging/prefect-values.yaml +14 -0
  290. package/src/target-templates/.devops/redis/production/redis-values.yaml +20 -0
  291. package/src/target-templates/.devops/redis/staging/redis-values.yaml +8 -0
  292. package/src/target-templates/.envrc +5 -0
  293. package/src/target-templates/.github/actions/build-image@v1/action.yaml +86 -0
  294. package/src/target-templates/.github/actions/connect-to-digital-ocean@v1/action.yaml +29 -0
  295. package/src/target-templates/.github/actions/connect-to-hetzner@v1/action.yaml +31 -0
  296. package/src/target-templates/.github/actions/connect-to-infra@v1/action.yaml +46 -0
  297. package/src/target-templates/.github/actions/db-migrate@v1/action.yaml +23 -0
  298. package/src/target-templates/.github/actions/deploy-image@v1/action.yaml +33 -0
  299. package/src/target-templates/.github/actions/setup-prereq@v1/action.yaml +29 -0
  300. package/src/target-templates/.github/workflows/k8s-build.yaml +84 -0
  301. package/src/target-templates/applications/example-data-pipeline/pyproject.toml +14 -0
  302. package/src/target-templates/applications/example-data-pipeline/src/example_data_pipeline/main.py +38 -0
  303. package/src/target-templates/applications/example-node/index.ts +30 -0
  304. package/src/target-templates/applications/example-node/package.json +26 -0
  305. package/src/target-templates/applications/example-node/tsconfig.json +3 -0
  306. package/src/target-templates/applications/example-python/pyproject.toml +20 -0
  307. package/src/target-templates/applications/example-python/src/example_python/__init__.py +0 -0
  308. package/src/target-templates/applications/example-python/src/example_python/main.py +13 -0
  309. package/src/target-templates/applications/example-python/src/example_python/scripts.py +17 -0
  310. package/src/target-templates/applications/example-python/tests/__init__.py +0 -0
  311. package/src/target-templates/applications/jobs/README.md +68 -0
  312. package/src/target-templates/applications/jobs/index.ts +1 -0
  313. package/src/target-templates/applications/jobs/package.json +30 -0
  314. package/src/target-templates/applications/jobs/tsconfig.json +3 -0
  315. package/src/target-templates/config/.env.development +1 -0
  316. package/src/target-templates/config/.env.global +4 -0
  317. package/src/target-templates/config/.env.test +1 -0
  318. package/src/target-templates/db/db/__init__.py +0 -0
  319. package/src/target-templates/db/db/db_client_test.py +46 -0
  320. package/src/target-templates/db/db-client-test.ts +140 -0
  321. package/src/target-templates/db/db-client.ts +19 -0
  322. package/src/target-templates/db/env.yaml +4 -0
  323. package/src/target-templates/db/package.json +17 -0
  324. package/src/target-templates/db/prisma/schema.prisma +24 -0
  325. package/src/target-templates/db/prisma-setup-vitest.ts +27 -0
  326. package/src/target-templates/db/pyproject.toml +14 -0
  327. package/src/target-templates/db/tsconfig.json +3 -0
  328. package/src/target-templates/devops +3 -0
  329. package/src/target-templates/devopspy +3 -0
  330. package/src/target-templates/dml/package.json +7 -0
  331. package/src/target-templates/dml/tsconfig.json +3 -0
  332. package/src/target-templates/libs/example-node-lib/bun.lock +27 -0
  333. package/src/target-templates/libs/example-node-lib/index.ts +3 -0
  334. package/src/target-templates/libs/example-node-lib/package.json +12 -0
  335. package/src/target-templates/libs/example-node-lib/tsconfig.json +3 -0
  336. package/src/target-templates/libs/example-python-lib/pyproject.toml +11 -0
  337. package/src/target-templates/libs/example-python-lib/src/example_python_lib/__init__.py +2 -0
  338. package/src/target-templates/pyproject.toml +19 -0
  339. package/src/target-templates/tmp/.gitkeep +0 -0
  340. package/src/target-templates/tsconfig.json +27 -0
  341. package/src/test.ts +0 -0
  342. package/src/types/index.ts +173 -0
@@ -0,0 +1,46 @@
1
+ import pytest_asyncio
2
+ from prisma import Prisma
3
+ from contextlib import asynccontextmanager
4
+
5
+ """Usage:
6
+ Add the file tests/conftest.py with the following content:
7
+
8
+ from db.db_client_test import *
9
+ """
10
+
11
+ # To open ipython at a particular point, do this:
12
+ #
13
+ # Add imports:
14
+ # from IPython import embed
15
+ # import nest_asyncio
16
+ #
17
+ # Insert this to the right position in the code:
18
+ # nest_asyncio.apply()
19
+ # embed()
20
+
21
+ class RollbackTransaction(Exception): pass
22
+
23
+ class TransactionProxy:
24
+ def __init__(self, transaction):
25
+ self._transaction = transaction
26
+
27
+ def __getattr__(self, name):
28
+ return getattr(self._transaction, name)
29
+
30
+ @asynccontextmanager
31
+ async def tx(self):
32
+ yield self._transaction
33
+
34
+ @pytest_asyncio.fixture(scope='function')
35
+ async def db_connection():
36
+ db = Prisma()
37
+ await db.connect()
38
+ try:
39
+ async with db.tx() as transaction:
40
+ tx = TransactionProxy(transaction)
41
+ yield tx
42
+ raise RollbackTransaction('rollback')
43
+ except RollbackTransaction:
44
+ pass
45
+ finally:
46
+ await db.disconnect()
@@ -0,0 +1,140 @@
1
+ // This code is used in db/prisma-setup-vitest.ts to run test code in the context of a rollbacked transaction.
2
+ // It is an improvement of:
3
+ // https://github.com/prisma/prisma-client-extensions/tree/main/callback-free-itx
4
+ //
5
+ // The main idea is to return a single client object that knows whether a transaction is active.
6
+ // If a transaction is active, it routes all calls to that transaction client.
7
+ // If no transaction is active, it routes all calls to the original client.
8
+ // To activate a transaction, use $begin().
9
+ //
10
+ // See:
11
+ // https://github.com/prisma/prisma/issues/12458
12
+ // https://github.com/prisma/prisma-client-extensions/pull/52
13
+ // https://www.prisma.io/docs/orm/more/help-and-troubleshooting/help-articles/nextjs-prisma-client-dev-practices
14
+ //
15
+ import { Prisma, PrismaClient } from '@prisma/client';
16
+
17
+ const ROLLBACK = { [Symbol.for('prisma.client.extension.rollback')]: true };
18
+
19
+ export const prismaClientSingleton = () => {
20
+ let _txClient: FlatTransactionClient | null = null;
21
+ const prismaClientOptions = process.env['PRISMA_DEBUG']
22
+ ? { log: ['query' as const] }
23
+ : undefined;
24
+
25
+ const extendedClient = new PrismaClient(prismaClientOptions).$extends({
26
+ client: {
27
+ async $begin() {
28
+ const prisma = Prisma.getExtensionContext(this);
29
+ let setTxClient: (txClient: Prisma.TransactionClient) => void;
30
+ let commit: () => void;
31
+ let rollback: () => void;
32
+
33
+ // a promise for getting the tx inner client
34
+ const txClient = new Promise<Prisma.TransactionClient>((res) => {
35
+ setTxClient = (txClient) => res(txClient);
36
+ });
37
+
38
+ // a promise for controlling the transaction
39
+ const txPromise = new Promise((_res, _rej) => {
40
+ commit = () => _res(undefined);
41
+ rollback = () => _rej(ROLLBACK);
42
+ });
43
+
44
+ // opening a transaction to control externally
45
+ if (
46
+ '$transaction' in prisma &&
47
+ typeof prisma.$transaction === 'function'
48
+ ) {
49
+ // [AA] Note the change from the github repo to actually make rollbacks work
50
+ const tx = prisma
51
+ .$transaction((txClient: unknown) => {
52
+ setTxClient(txClient as unknown as Prisma.TransactionClient);
53
+ return txPromise;
54
+ })
55
+ .catch((e: unknown) => {
56
+ if (e === ROLLBACK) return;
57
+ throw e;
58
+ });
59
+
60
+ // return a proxy TransactionClient with `$commit` and `$rollback` methods
61
+ _txClient = new Proxy(await txClient, {
62
+ get(target, prop) {
63
+ if (prop === '$commit') {
64
+ return () => {
65
+ _txClient = null;
66
+ commit();
67
+ return tx;
68
+ };
69
+ }
70
+ if (prop === '$rollback') {
71
+ return () => {
72
+ _txClient = null;
73
+ rollback();
74
+ return tx;
75
+ };
76
+ }
77
+ if (prop === '$transaction') {
78
+ return async (fn: CallableFunction) => {
79
+ return fn(target);
80
+ };
81
+ }
82
+ return target[prop as keyof typeof target];
83
+ },
84
+ }) as FlatTransactionClient;
85
+
86
+ return _txClient;
87
+ }
88
+
89
+ throw new Error('Transactions are not supported by this client');
90
+ },
91
+ },
92
+ });
93
+
94
+ /* eslint-disable */
95
+ // @ts-ignore
96
+ const client = new Proxy(extendedClient, {
97
+ get(_target, prop) {
98
+ if (_txClient) {
99
+ return _txClient[prop as keyof typeof _txClient];
100
+ } else {
101
+ return extendedClient[prop as keyof typeof extendedClient];
102
+ }
103
+ },
104
+ });
105
+ /* eslint-enable */
106
+
107
+ return client as unknown as ExtendedTransactionClient | FlatTransactionClient;
108
+ };
109
+
110
+ declare global {
111
+ // eslint-disable-next-line no-var
112
+ var prismaTestGlobal:
113
+ | ExtendedTransactionClient
114
+ | FlatTransactionClient
115
+ | undefined;
116
+ }
117
+
118
+ export type ExtendedTransactionClient = Prisma.TransactionClient & {
119
+ $begin: () => Promise<FlatTransactionClient>;
120
+ };
121
+
122
+ export type FlatTransactionClient = Prisma.TransactionClient & {
123
+ $commit: () => Promise<void>;
124
+ $rollback: () => Promise<void>;
125
+ };
126
+
127
+ const prisma: ExtendedTransactionClient | FlatTransactionClient =
128
+ globalThis.prismaTestGlobal ?? prismaClientSingleton();
129
+
130
+ globalThis.prismaTestGlobal = prisma;
131
+
132
+ export { prisma };
133
+
134
+ export async function startTx() {
135
+ await (prisma as ExtendedTransactionClient).$begin();
136
+ }
137
+
138
+ export async function rollbackTx() {
139
+ await (prisma as FlatTransactionClient).$rollback();
140
+ }
@@ -0,0 +1,19 @@
1
+ // See https://www.prisma.io/docs/orm/more/help-and-troubleshooting/help-articles/nextjs-prisma-client-dev-practices
2
+ import { PrismaClient } from '@prisma/client';
3
+
4
+ declare global {
5
+ // eslint-disable-next-line no-var
6
+ var prismaGlobal: PrismaClient | undefined;
7
+ }
8
+
9
+ const prismaClientSingleton = () => {
10
+ return new PrismaClient();
11
+ };
12
+
13
+ const prisma = (globalThis.prismaGlobal ??
14
+ prismaClientSingleton()) as PrismaClient;
15
+
16
+ globalThis.prismaGlobal = prisma;
17
+
18
+ export { prisma };
19
+ export * from '@prisma/client';
@@ -0,0 +1,4 @@
1
+ # Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
2
+ # See the documentation for all the connection string options: https://pris.ly/d/connection-strings
3
+
4
+ - DATABASE_URL
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "db",
3
+ "main": "db-client.ts",
4
+ "type": "module",
5
+ "private": true,
6
+ "scripts": {
7
+ "generate": "prisma generate --generator js-client",
8
+ "migrate-deploy": "prisma migrate deploy"
9
+ },
10
+ "dependencies": {
11
+ "@prisma/client": "^6.5.0",
12
+ "prisma": "^6.5.0"
13
+ },
14
+ "devDependencies": {
15
+ "vitest": "^3.0.9"
16
+ }
17
+ }
@@ -0,0 +1,24 @@
1
+ // This is your Prisma schema file,
2
+ // learn more about it in the docs: https://pris.ly/d/prisma-schema
3
+
4
+ // Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
5
+ // Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
6
+
7
+ generator client {
8
+ provider = "prisma-client-js"
9
+ }
10
+
11
+ generator js-client {
12
+ provider = "prisma-client-js"
13
+ previewFeatures = ["postgresqlExtensions"]
14
+ }
15
+
16
+ generator python-client {
17
+ provider = "prisma-client-py"
18
+ previewFeatures = ["postgresqlExtensions"]
19
+ }
20
+
21
+ datasource db {
22
+ provider = "postgresql"
23
+ url = env("DATABASE_URL")
24
+ }
@@ -0,0 +1,27 @@
1
+ import { afterEach, beforeEach, vi } from 'vitest';
2
+ import { prisma, rollbackTx, startTx } from './db-client-test';
3
+
4
+ /**
5
+ * Usage:
6
+ * Create a `vitest.config.ts` in the project's folder with the following content.
7
+ * Adjust the path to the setup file based on the nesting of the project's folder.
8
+
9
+ import { defineConfig } from 'vitest/config'
10
+
11
+ export default defineConfig({
12
+ test: {
13
+ setupFiles: ['../../db/prisma-setup-vitest.ts']
14
+ },
15
+ })
16
+
17
+ */
18
+
19
+ vi.mock('db', () => ({ prisma }));
20
+
21
+ beforeEach(async () => {
22
+ await startTx();
23
+ });
24
+
25
+ afterEach(async () => {
26
+ await rollbackTx();
27
+ });
@@ -0,0 +1,14 @@
1
+ [project]
2
+ name = "db"
3
+ version = "0.1.0"
4
+ description = ""
5
+ authors = []
6
+ requires-python = ">=3.12"
7
+ dependencies = ["prisma (>=0.15.0,<0.16.0)"]
8
+
9
+ [tool.devops.scripts]
10
+ generate = "prisma generate --generator python-client"
11
+
12
+ [build-system]
13
+ requires = ["hatchling"]
14
+ build-backend = "hatchling.build"
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "../tsconfig.json"
3
+ }
@@ -0,0 +1,3 @@
1
+ #! /usr/bin/env bash
2
+
3
+ bunx devops "$@"
@@ -0,0 +1,3 @@
1
+ #! /usr/bin/env bash
2
+
3
+ uv run devopspy "$@"
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "dml",
3
+ "type": "module",
4
+ "dependencies": {
5
+ "db": "workspace:*"
6
+ }
7
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "../tsconfig.json"
3
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "lockfileVersion": 1,
3
+ "workspaces": {
4
+ "": {
5
+ "name": "example-node-lib",
6
+ "devDependencies": {
7
+ "@types/bun": "latest",
8
+ },
9
+ "peerDependencies": {
10
+ "typescript": "^5",
11
+ },
12
+ },
13
+ },
14
+ "packages": {
15
+ "@types/bun": ["@types/bun@1.2.5", "", { "dependencies": { "bun-types": "1.2.5" } }, "sha512-w2OZTzrZTVtbnJew1pdFmgV99H0/L+Pvw+z1P67HaR18MHOzYnTYOi6qzErhK8HyT+DB782ADVPPE92Xu2/Opg=="],
16
+
17
+ "@types/node": ["@types/node@22.13.11", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-iEUCUJoU0i3VnrCmgoWCXttklWcvoCIx4jzcP22fioIVSdTmjgoEvmAO/QPw6TcS9k5FrNgn4w7q5lGOd1CT5g=="],
18
+
19
+ "@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="],
20
+
21
+ "bun-types": ["bun-types@1.2.5", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-3oO6LVGGRRKI4kHINx5PIdIgnLRb7l/SprhzqXapmoYkFl5m4j6EvALvbDVuuBFaamB46Ap6HCUxIXNLCGy+tg=="],
22
+
23
+ "typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="],
24
+
25
+ "undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="],
26
+ }
27
+ }
@@ -0,0 +1,3 @@
1
+ export function test() {
2
+ return "test";
3
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "example-node-lib",
3
+ "module": "index.ts",
4
+ "type": "module",
5
+ "private": true,
6
+ "devDependencies": {
7
+ "@types/bun": "latest"
8
+ },
9
+ "peerDependencies": {
10
+ "typescript": "^5"
11
+ }
12
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "../../tsconfig.json"
3
+ }
@@ -0,0 +1,11 @@
1
+ [project]
2
+ name = "example-python-lib"
3
+ version = "0.1.0"
4
+ description = ""
5
+ authors = []
6
+ requires-python = ">=3.12"
7
+ dependencies = []
8
+
9
+ [build-system]
10
+ requires = ["hatchling"]
11
+ build-backend = "hatchling.build"
@@ -0,0 +1,19 @@
1
+ [project]
2
+ name = "devops-test"
3
+ version = "0.1.0"
4
+ description = ""
5
+ authors = []
6
+ readme = "README.md"
7
+ requires-python = ">=3.12"
8
+ dependencies = ["devops-python"]
9
+
10
+ [tool.uv.workspace]
11
+ members = [
12
+ "db",
13
+ "applications/example-data-pipeline",
14
+ "applications/example-python",
15
+ "libs/example-python-lib",
16
+ ]
17
+
18
+ [tool.uv.sources]
19
+ devops-python = { git = "https://github.com/vaharoni/devops-python.git" }
File without changes
@@ -0,0 +1,27 @@
1
+ {
2
+ "compilerOptions": {
3
+ // Enable latest features
4
+ "lib": ["ESNext", "DOM"],
5
+ "target": "ESNext",
6
+ "module": "ESNext",
7
+ "moduleDetection": "force",
8
+ "jsx": "react-jsx",
9
+ "allowJs": true,
10
+
11
+ // Bundler mode
12
+ "moduleResolution": "bundler",
13
+ "allowImportingTsExtensions": true,
14
+ "verbatimModuleSyntax": true,
15
+ "noEmit": true,
16
+
17
+ // Best practices
18
+ "strict": true,
19
+ "skipLibCheck": true,
20
+ "noFallthroughCasesInSwitch": true,
21
+
22
+ // Some stricter flags (disabled by default)
23
+ "noUnusedLocals": false,
24
+ "noUnusedParameters": false,
25
+ "noPropertyAccessFromIndexSignature": false
26
+ }
27
+ }
package/src/test.ts ADDED
File without changes
@@ -0,0 +1,173 @@
1
+ import { z } from "zod";
2
+
3
+ export const SUPPORTED_LANGUAGES = ["python", "node"] as const;
4
+ export type SupportedLanguages = typeof SUPPORTED_LANGUAGES[number];
5
+
6
+ // Config files
7
+
8
+ export const constFileSchema = z.object({
9
+ "project-name": z.string(),
10
+ "infra": z.enum(["hetzner", "digitalocean"]),
11
+ "image-versions-to-keep": z.number(),
12
+ "registry-base-url": z.string(),
13
+ "registry-name": z.string(),
14
+ "extra-remote-environments": z.array(z.string()),
15
+ "extra-local-environments": z.array(z.string()),
16
+ })
17
+ export type ConstFileSchema = z.infer<typeof constFileSchema>;
18
+
19
+ const singleTemplateSchema = z.object({
20
+ "copy-common": z.boolean().optional(),
21
+ "extra-content": z.array(z.string()).optional(),
22
+ })
23
+ export type SingleTemplateSchema = z.infer<typeof singleTemplateSchema>;
24
+
25
+ const singleImageSchema = z.object({
26
+ "image-template": z.string(),
27
+ "language": z.enum(SUPPORTED_LANGUAGES),
28
+ "domains": z.record(z.string()).optional(),
29
+ "debug-template": z.string(),
30
+ "can-db-migrate": z.boolean().optional(),
31
+ applications: z.array(z.string()),
32
+ });
33
+ export type SingleImageSchema = z.infer<typeof singleImageSchema>;
34
+
35
+ export const imageFileSchema = z.object({
36
+ templates: z.record(singleTemplateSchema),
37
+ images: z.record(singleImageSchema),
38
+ })
39
+ export type ImageFileSchema = z.infer<typeof imageFileSchema>;
40
+
41
+ // # Workspace Discovery
42
+
43
+ // We need a term to describe the files that contain the project data (e.g. package.json, pyproject.toml).
44
+ // While they are typically called "manifests" in the context of package managers, we cannot use that term here due to
45
+ // ambiguity with kubernetes manifests. We therefore refer to them as "package files".
46
+ //
47
+ // Terminology:
48
+ // - Workspace - a project that is part of the monorepo. Can be either a library or an application. We borrow this term from npm workspaces.
49
+ // - Package File - language-specific file that resides inside the workspace's root folder and contains project data (e.g. package.json, pyproject.toml)
50
+ // - Package Data - a language-agnostic abstraction of the relevant data in a package file. Package Files are converted into Package Data.
51
+ // - Workspace Index Entry - a record that maps workspace names to where they reside and their package data. A workspace may contain multiple
52
+ // package files. In such case, their content must use the same "name" key so that we can always translate paths to names and vice versa.
53
+ //
54
+
55
+ // ## Workspace Discovery: Language-agnostic constructs
56
+
57
+ // The keys are the workspace names
58
+ export type WorkspaceIndex = Record<string, WorkspaceIndexEntry>;
59
+
60
+ export type WorkspaceIndexEntry = {
61
+ rootPath: string;
62
+ packageDataEntries: PackageData[];
63
+ };
64
+
65
+ export type PackageData = Omit<PackageFileNode, 'dependencies'> & {
66
+ // Duplication with WorkspaceIndexEntry intentional to simplify types
67
+ rootPath: string;
68
+ language: SupportedLanguages;
69
+ /** The list of monorepo-internal packages this project depends on */
70
+ dependencyNames: string[];
71
+ }
72
+
73
+ const deploymentSchema = z.object({
74
+ /** The name of the composite template to build in order to support this deployment */
75
+ template: z.string(),
76
+ /** The name used by kubernetes objects. If ommitted, the name field from the enclosing context (e.g. package.json) is used. */
77
+ app_name: z.string().optional(),
78
+ /** This will be the name of the internal service used for intra-cluster communication */
79
+ service_name: z.string().optional(),
80
+ /** For services, the port to expose */
81
+ port: z.number().optional(),
82
+ /** This will be the subdomain of the exposed ingress. If not provided, taken from service_name */
83
+ subdomain: z.string().optional(),
84
+ /** For cron jobs */
85
+ cronJobs: z.array(
86
+ z.object({
87
+ /** The name of the cron job. Used to identify in k8s. Should be unique among all cron jobs. */
88
+ name: z.string().optional(),
89
+ /** The cron schedule */
90
+ cron: z.string().optional(),
91
+ /** The curl command to invoke. Must be an array. */
92
+ curl: z.array(z.string()).optional(),
93
+ })
94
+ ).optional(),
95
+ prefectFlows: z.array(
96
+ z.object({
97
+ /** The name of the container inside the prefect pod */
98
+ flow_name: z.string(),
99
+ /** The path to the file that runs the flow, relative to the project folder. E.g. src/data_pipeline/main.py */
100
+ script_path: z.string(),
101
+ })
102
+ ).optional()
103
+ /** The catchall below allows any other fields that might be in the package.json file */
104
+ }).catchall(z.any());
105
+ export type Deployment = z.infer<typeof deploymentSchema>;
106
+
107
+ // ## Workspace Discovery: Languae-specific constructs
108
+
109
+ export const packageFileNodeSchema = z.object({
110
+ /** This is considered the project name */
111
+ name: z.string(),
112
+ /** Scripts exposed by this project. */
113
+ scripts: z.record(z.string()).optional(),
114
+ /** The dependencies of the project */
115
+ dependencies: z.record(z.string()).optional(),
116
+ /** When a deployment data is available, a k8s deployment is created */
117
+ deployment: deploymentSchema.optional(),
118
+ });
119
+ export type PackageFileNode = z.infer<typeof packageFileNodeSchema>;
120
+
121
+ export const packageFilePythonSchema = z.object({
122
+ project: z.object({
123
+ name: z.string(),
124
+ dependencies: z.string().array().optional(),
125
+ }),
126
+ tool: z.object({
127
+ devops: z.object({
128
+ deployment: deploymentSchema.optional(),
129
+ scripts: z.record(z.string()).optional(),
130
+ }).optional(),
131
+ }).optional(),
132
+ })
133
+ export type PackageFilePython = z.infer<typeof packageFilePythonSchema>;
134
+
135
+ // # k8s template generation
136
+
137
+ // When we generate k8s templates, we need to provide a context object that contains all the necessary information to render the template.
138
+ // There are 3 contexts in which we generate templates, and thus 3 types of context objects:
139
+ // - Deployment - used to render the deployable k8s entities a workspace declared in its package file (as part of image deployment)
140
+ // - Debug - used to render a "debug instance" for an image the user can console into (as part of an image deployment)
141
+ // - DbMigrateJob - used to render a job that runs database migrations using one of the images that support it (as part of the orchestrating git-push process)
142
+
143
+ export type TemplateSharedContext = {
144
+ /** The monorepo environment */
145
+ monorepo_env: string;
146
+ /** The k8s namespace that the monorepo environment is associated with */
147
+ namespace: string;
148
+ /** The domain name associated with the monorepo environment (from constnts.yaml) */
149
+ domain_name: string;
150
+ /** The path to the image in the container registry */
151
+ image_path: string;
152
+ /** The secret name of the monorepo environment */
153
+ env_secret_name: string;
154
+ /** The name of the key inside the environment's secret that contains the base secret (constant) */
155
+ env_base_secret_key: string;
156
+ }
157
+
158
+ export type TemplateDeploymentObject = TemplateSharedContext & Deployment & {
159
+ /** Same as pkgData.name */
160
+ project_name: string;
161
+ /** The number of replicas as defined by running devops scale */
162
+ replicas: number;
163
+ }
164
+
165
+ export type TemplateDbMigrateObject = TemplateSharedContext & {
166
+ /** The name of the migration job to create */
167
+ db_migrate_job_name: string;
168
+ }
169
+
170
+ export type TemplateDebugObject = TemplateSharedContext & {
171
+ /** The name of the debug pod */
172
+ debug_pod_name: string;
173
+ }